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 #ifndef KISFILTEREDROLLINGMEAN_H 0008 #define KISFILTEREDROLLINGMEAN_H 0009 0010 #include "kritaglobal_export.h" 0011 0012 #include <vector> 0013 #include <boost/circular_buffer.hpp> 0014 #include <QtGlobal> 0015 0016 /** 0017 * A special class that calculates a rolling mean of the 0018 * values stream, but filtering out random extreme deviations. 0019 * 0020 * On each step the algorithm sorts the entire sampling window 0021 * and drops a small portion of the lowest and the highest 0022 * values. The rest of the values are used to calculate the 0023 * mean of the window. 0024 * 0025 * Basically, it takes the median and a few surrounding values 0026 * to calculate the mean. 0027 * 0028 * PS: 0029 * The actualy implementation does a few optimizations. For 0030 * example, it doesn't sort the entire range. But the idea is 0031 * the same. 0032 */ 0033 class KRITAGLOBAL_EXPORT KisFilteredRollingMean 0034 { 0035 public: 0036 /** 0037 * Creates a mean accumulator 0038 * 0039 * \p windowSize is the size of the samples window 0040 * \p effectivePortion the portion of the samples window 0041 * that is used for actual mean calclulation. On each 0042 * side of the sorted range (0.5 * (1.0 - effectivePortion) * 0043 * windowSize) values are dropped and are not counted for 0044 * the mean calculation. 0045 */ 0046 KisFilteredRollingMean(int windowSize, qreal effectivePortion); 0047 0048 /** 0049 * Adds a value for the rolling mean calculation. The 0050 * complexity of the call is O(1). 0051 */ 0052 void addValue(qreal value); 0053 0054 /** 0055 * Calculates the filtered mean value of the current range. 0056 * The function is slow, its complexity is O(N) + O(N*log(M)), 0057 * where N is the size of the rolling window, M is the number 0058 * of elements dropped from the window 0059 * (1.0 - effectivePortion) * windowSize). 0060 */ 0061 qreal filteredMean() const; 0062 0063 /** 0064 * Returns true if the accumulator has at least some value 0065 */ 0066 bool isEmpty() const; 0067 0068 private: 0069 boost::circular_buffer<qreal> m_values; 0070 qreal m_rollingSum; 0071 qreal m_effectivePortion; 0072 mutable std::vector<qreal> m_cutOffBuffer; 0073 }; 0074 0075 #endif // KISFILTEREDROLLINGMEAN_H