File indexing completed on 2024-05-12 15:57:02
0001 /* 0002 * SPDX-FileCopyrightText: 2022 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "KisFilteredRollingMean.h" 0008 0009 #include <algorithm> 0010 #include <numeric> 0011 #include <QtMath> 0012 #include "kis_assert.h" 0013 #include "kis_debug.h" 0014 0015 0016 KisFilteredRollingMean::KisFilteredRollingMean(int windowSize, qreal effectivePortion) 0017 : m_values(windowSize), 0018 m_rollingSum(0.0), 0019 m_effectivePortion(effectivePortion), 0020 m_cutOffBuffer(qCeil(0.5 * (qCeil(windowSize * (1.0 - effectivePortion))))) 0021 { 0022 } 0023 0024 void KisFilteredRollingMean::addValue(qreal value) 0025 { 0026 if (m_values.full()) { 0027 m_rollingSum -= m_values.front(); 0028 } 0029 0030 m_values.push_back(value); 0031 m_rollingSum += value; 0032 } 0033 0034 qreal KisFilteredRollingMean::filteredMean() const 0035 { 0036 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!m_values.empty(), 0.0); 0037 0038 const int usefulElements = qMax(1, qRound(m_effectivePortion * m_values.size())); 0039 0040 qreal sum = 0.0; 0041 int num = 0; 0042 0043 const int cutOffTotal = m_values.size() - usefulElements; 0044 0045 if (cutOffTotal > 0) { 0046 const int cutMin = qRound(0.5 * cutOffTotal); 0047 const int cutMax = cutOffTotal - cutMin; 0048 0049 KIS_SAFE_ASSERT_RECOVER(cutMin <= m_cutOffBuffer.size()) { 0050 m_cutOffBuffer.resize(cutMin); 0051 } 0052 KIS_SAFE_ASSERT_RECOVER(cutMax <= m_cutOffBuffer.size()) { 0053 m_cutOffBuffer.resize(cutMax); 0054 } 0055 0056 sum = m_rollingSum; 0057 num = usefulElements; 0058 0059 std::partial_sort_copy(m_values.begin(), 0060 m_values.end(), 0061 m_cutOffBuffer.begin(), 0062 m_cutOffBuffer.begin() + cutMin); 0063 0064 sum -= std::accumulate(m_cutOffBuffer.begin(), 0065 m_cutOffBuffer.begin() + cutMin, 0066 0.0); 0067 0068 std::partial_sort_copy(m_values.begin(), 0069 m_values.end(), 0070 m_cutOffBuffer.begin(), 0071 m_cutOffBuffer.begin() + cutMax, 0072 std::greater<qreal>()); 0073 0074 sum -= std::accumulate(m_cutOffBuffer.begin(), 0075 m_cutOffBuffer.begin() + cutMax, 0076 0.0); 0077 } else { 0078 sum = m_rollingSum; 0079 num = m_values.size(); 0080 } 0081 0082 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(num > 0, 0.0); 0083 0084 return sum / num; 0085 } 0086 0087 bool KisFilteredRollingMean::isEmpty() const 0088 { 0089 return m_values.empty(); 0090 }