图像处理一百题 Q.10 メディアンフィルタ(中值滤波)顺便提一下 Q.11 均值滤波(平滑滤波)

分析

把高斯权重改成均值权重,我们就得到了均值滤波器。而均值滤波器改成用周边窗口(也称领域)的均值作为自己值,就得到了中值滤波。

关于什么是领域:想想一个数独,中心的 3x3 就是当前窗口。周围的八个 3x3 窗口构成领域。

2019-10-23T15:40:32.png

均值滤波

#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <math.h>

cv::Mat Gaussian(cv::Mat in)
{
  cv::Mat out = cv::Mat::zeros(in.rows, in.cols, CV_8UC3);
  float tmpl[9] = {0.1111, 0.1111, 0.1111,
                   0.1111, 0.1111, 0.1111,
                   0.1111, 0.1111, 0.1111};
  cv::Mat matTmpl = cv::Mat(3, 3, CV_32FC1, tmpl);
  for (int x = 0; x < in.cols; x += 1)
    for (int y = 0; y < in.rows; y += 1)
    {
      for (int c = 0; c < in.channels(); c++)
      {
        float data[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
        cv::Mat mat = cv::Mat(3, 3, CV_32FC1, data);
        for (int i = -1; i <= 1; i++)
        {
          for (int j = -1; j <= 1; j++)
          {
            int p_x = x + i;
            int p_y = y + j;
            if (p_x < 0 || p_y < 0 || p_x >= in.cols || p_y >= in.rows)
            {
              mat.at<float>(i + 1, j + 1) = 0.0f;
            }
            else
            {
              mat.at<float>(i + 1, j + 1) = (float)in.at<cv::Vec3b>(p_x, p_y)[c];
            }
          }
        }
        out.at<cv::Vec3b>(x,y)[c] = (uchar)mat.dot(matTmpl);
      }
    }

  return out;
}

int main(int argc, const char *argv[])
{
  cv::Mat img = cv::imread("imori.jpg", cv::IMREAD_COLOR);
  cv::Mat out = Gaussian(img);
  cv::imwrite("out.jpg", out);
  cv::imshow("sample", out);
  cv::waitKey(0);
  cv::destroyAllWindows();
  return 0;
}

中值滤波

#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <math.h>


// median filter
cv::Mat median_filter(cv::Mat img, int kernel_size){
  int height = img.rows;
  int width = img.cols;
  int channel = img.channels();

  // prepare output
  cv::Mat out = cv::Mat::zeros(height, width, CV_8UC3);

  // prepare kernel
  int pad = floor(kernel_size / 2);
  
  // filtering
  double v = 0;
  int vs[kernel_size * kernel_size];
  int count = 0;
  
  for (int y = 0; y < height; y++){
    for (int x = 0; x < width; x++){
      for (int c = 0; c < channel; c++){
      v = 0;
      count = 0;
      
      for (int i = 0; i < kernel_size * kernel_size; i++){
        vs[i] = 999;
      }
      
      // get neighbor pixels
      for (int dy = -pad; dy < pad + 1; dy++){
        for (int dx = -pad; dx < pad + 1; dx++){
          if (((y + dy) >= 0) && ((x + dx) >= 0)){
            vs[count++] = (int)img.at<cv::Vec3b>(y + dy, x + dx)[c];
          }
        }
      }

      // get and assign median
      std::sort(vs, vs + (kernel_size * kernel_size));
      out.at<cv::Vec3b>(y, x)[c] = (uchar)vs[int(floor(count / 2)) + 1];
      }
    }
  }
  return out;
}

int main(int argc, const char* argv[]){
  // read image
  cv::Mat img = cv::imread("imori_noise.jpg", cv::IMREAD_COLOR);

  // median filter
  cv::Mat out = median_filter(img, 3);
  
  //cv::imwrite("out.jpg", out);
  cv::imshow("answer", out);
  cv::waitKey(0);
  cv::destroyAllWindows();

  return 0;
}

发表留言

本站启用了垃圾评论检测插件,如果误删请联系我~