summaryrefslogtreecommitdiff
path: root/silx/math/medianfilter/include/median_filter.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'silx/math/medianfilter/include/median_filter.hpp')
-rw-r--r--silx/math/medianfilter/include/median_filter.hpp139
1 files changed, 139 insertions, 0 deletions
diff --git a/silx/math/medianfilter/include/median_filter.hpp b/silx/math/medianfilter/include/median_filter.hpp
new file mode 100644
index 0000000..da1f9fe
--- /dev/null
+++ b/silx/math/medianfilter/include/median_filter.hpp
@@ -0,0 +1,139 @@
+/*##########################################################################
+#
+# Copyright (c) 2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+// __authors__ = ["H. Payno"]
+// __license__ = "MIT"
+// __date__ = "10/02/2017"
+
+#ifndef MEDIAN_FILTER
+#define MEDIAN_FILTER
+
+#include <vector>
+#include <assert.h>
+#include <algorithm>
+#include <signal.h>
+
+// Simple function browsing a deque and registring the min and max values
+// and if those values are unique or not
+template<typename T>
+void getMinMax(std::vector<const T*>& v, T& min, T&max){
+ // init min and max values
+ typename std::vector<const T*>::const_iterator it = v.begin();
+ if (v.size() == 0){
+ raise(SIGINT);
+ }else{
+ min = max = *(*it);
+ }
+ it++;
+
+ // Browse all the deque
+ while(it!=v.end()){
+ // check if repeated (should always be before min/max setting)
+ if(*(*it) > max) max = *(*it);
+ if(*(*it) < min) min = *(*it);
+
+ it++;
+ }
+}
+
+template<typename T>
+bool cmp(const T* a, const T* b){
+ return *a < *b;
+}
+
+template<typename T>
+const T* median(std::vector<const T*>& v) {
+ std::nth_element(v.begin(), v.begin() + v.size()/2, v.end(), cmp<T>);
+ return v[v.size()/2];
+}
+
+// Browse the column of pixel_x
+template<typename T>
+void median_filter(
+ const T* input,
+ T* output,
+ int* kernel_dim, // two values : 0:width, 1:height
+ int* image_dim, // two values : 0:width, 1:height
+ int x_pixel, // the x pixel to process
+ int y_pixel_range_min,
+ int y_pixel_range_max,
+ bool conditional){
+
+ assert(kernel_dim[0] > 0);
+ assert(kernel_dim[1] > 0);
+ assert(x_pixel >= 0);
+ assert(image_dim[0] > 0);
+ assert(image_dim[1] > 0);
+ assert(x_pixel >= 0);
+ assert(x_pixel < image_dim[0]);
+ assert(y_pixel_range_max < image_dim[1]);
+ assert(y_pixel_range_min <= y_pixel_range_max);
+ // # kernel odd
+ assert((kernel_dim[0] - 1)%2 == 0);
+ assert((kernel_dim[1] - 1)%2 == 0);
+
+ // # this should be move up to avoid calculation each time
+ int halfKernel_x = (kernel_dim[1] - 1) / 2;
+ int halfKernel_y = (kernel_dim[0] - 1) / 2;
+
+ // init buffer
+ // fill the buffer for the first iteration
+ // we are treating
+ std::vector<const T*> window_values(kernel_dim[0]*kernel_dim[1]);
+
+ for(int pixel_y=y_pixel_range_min; pixel_y <= y_pixel_range_max; pixel_y ++ ){
+ typename std::vector<const T*>::iterator it = window_values.begin();
+ // fill the vector
+ for(int win_y=pixel_y-halfKernel_y; win_y<= pixel_y+halfKernel_y; win_y++)
+ {
+ for(int win_x = x_pixel-halfKernel_x; win_x <= x_pixel+halfKernel_x; win_x++)
+ {
+ int index_x = std::min(std::max(win_x, 0), image_dim[0] - 1);
+ int index_y = std::min(std::max(win_y, 0), image_dim[1] - 1);
+ *it = (&input[index_y*image_dim[0] + index_x]);
+ ++it;
+ }
+ }
+
+ const T* currentPixelValue = &input[image_dim[0]*pixel_y + x_pixel];
+ // change value for the median, only if we don't intend to use the
+ // conditional or if the value of the pixel is one of the extrema
+ // of the pixel value
+ if (conditional == true){
+ T min = 0;
+ T max = 0;
+ getMinMax(window_values, min, max);
+ // In conditional point we are only setting the value to the pixel
+ // if the value is the min or max and unique
+ if ((*currentPixelValue == max) || (*currentPixelValue == min)){
+ output[image_dim[0]*pixel_y + x_pixel] = *(median<T>(window_values));
+ }else{
+ output[image_dim[0]*pixel_y + x_pixel] = *currentPixelValue;
+ }
+ }else{
+ output[image_dim[0]*pixel_y + x_pixel] = *(median<T>(window_values));
+ }
+ }
+}
+
+#endif // MEDIAN_FILTER