OpenCV adaptive median filter and its implementation

Median Filter

  The idea of ​​median filtering is to compare the size of pixel values ​​in a certain area, and take out the median value as the new value of the center pixel in this area. Assuming that all pixels in a certain area are sorted from small to large, if there are isolated noise points, such as salt and pepper noise (pepper noise—smaller gray value, the effect is small black dots; salt noise—larger gray value, the effect is small white dots), then in the array sorted from small to large, those isolated noises must be distributed on both sides (either small or large), so that the median point taken out in this way can preserve pixel information well and filter out the influence of noise points.

  The median filter is greatly affected by the size of the filtering window and is used to eliminate noise and protect image details, and there will be conflicts between the two. If the window size is small, it can better protect some details in the image, but the noise filtering effect will be compromised; on the contrary, if the window size is larger, it will have a better noise filtering effect, but it will also cause a certain blur effect on the image, thus losing part of the detail information. In addition, if the number of noise points in the filtering window is greater than the number of pixels in the entire window, the median filter cannot filter out the noise well.

 The benefits of this article, the fee to receive Qt development learning materials package, technical video, content includes (Qt actual combat project, C++ language foundation, C++ design pattern, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project combat, QSS, OpenCV, Quick module, interview questions, etc. )

Adaptive Median Filter

  In the case where the noise density is not very large (according to experience, the probability of noise occurrence is less than 0.2), the effect of using median filtering is good. But when the probability of noise is relatively high, the original median filtering algorithm is not very effective. Only increase the filter window size, although it will blur the image.

  The purpose of using the adaptive median filter is to dynamically change the window size of the median filter according to preset conditions, so as to simultaneously take into account the effects of denoising and protecting details.

  The following is a detailed description of the adaptive median filter algorithm:

The following symbols are predefined:

 

intuitive explanation

  In the adaptive median filtering algorithm, step A will first judge whether Zmin<Zmed<ZmaxZmin<Zmed<Zmax is satisfied. The essence of this step is to judge whether the median point in the current area is a noise point. Generally speaking, it satisfies the condition of Zmin<Zmed<ZmaxZmin<Zmed<Zmax. At this time, the median point is not a noise point and jumps to B; considering some special cases, if Zmed=ZminZmed=Zmin or Zmed=ZmaxZmed=Zmax, it is considered to be a noise point, and the window size should be enlarged to find a suitable non-noise point in a larger range, and then jump to B, otherwise the median value of the output points are noise points;

  Next, consider the situation after jumping to B: judge whether the pixel value of the center point is a noise point, the judgment condition is Zmin<Zxy<ZmaxZmin<Zxy<Zmax, the principle is the same as above, because if Zxy=ZminZxy=Zmin or Zxy=ZmaxZxy=Zmax, it is considered a noise point. If it is not a noise point, we can keep the gray value of the current pixel; if it is a noise point, use the median value instead of the original gray value to filter out the noise.

program implementation

  The program defines functions for generating pepper noise and salt noise, as well as functions for median filtering and adaptive median filtering.

The program is very basic, so I won't repeat it.

#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

//盐噪声
void saltNoise(cv::Mat img, int n)
{
    int x, y;
    for (int i = 0;i < n / 2;i++)
    {
        x = std::rand() % img.cols;
        y = std::rand() % img.rows;
        if (img.type() == CV_8UC1)
        {
            img.at<uchar>(y, x) = 255;
        }
        else if (img.type() == CV_8UC3)
        {
            img.at<cv::Vec3b>(y, x)[0] = 255;
            img.at<cv::Vec3b>(y, x)[1] = 255;
            img.at<cv::Vec3b>(y, x)[2] = 255;
        }
    }
}

//椒噪声
void pepperNoise(cv::Mat img, int n)
{
    int x, y;
    for (int i = 0;i < n / 2;i++)
    {
        x = std::rand() % img.cols;
        y = std::rand() % img.rows;
        if (img.type() == CV_8UC1)
        {
            img.at<uchar>(y, x) = 0;
        }
        else if (img.type() == CV_8UC3)
        {
            img.at<cv::Vec3b>(y, x)[0] = 0;
            img.at<cv::Vec3b>(y, x)[1] = 0;
            img.at<cv::Vec3b>(y, x)[2] = 0;
        }
    }
}

// 中值滤波器
uchar medianFilter(cv::Mat img, int row, int col, int kernelSize)
{
    std::vector<uchar> pixels;
    for (int y = -kernelSize / 2;y <= kernelSize / 2;y++)
    {
        for (int x = -kernelSize / 2;x <= kernelSize / 2;x++)
        {
            pixels.push_back(img.at<uchar>(row + y, col + x));
        }
    }
    sort(pixels.begin(), pixels.end());
    auto med = pixels[kernelSize*kernelSize / 2];
    return med;
}

// 自适应中值滤波器
uchar adaptiveMedianFilter(cv::Mat &img, int row, int col, int kernelSize, int maxSize)
{
    std::vector<uchar> pixels;
    for (int y = -kernelSize / 2;y <= kernelSize / 2;y++)
    {
        for (int x = -kernelSize / 2;x <= kernelSize / 2;x++)
        {
            pixels.push_back(img.at<uchar>(row + y, col + x));
        }
    }

    sort(pixels.begin(), pixels.end());

    auto min = pixels[0];
    auto max = pixels[kernelSize*kernelSize - 1];
    auto med = pixels[kernelSize*kernelSize / 2];
    auto zxy = img.at<uchar>(row, col);
    if (med > min && med < max)
    {
        // to B
        if (zxy > min && zxy < max)
            return zxy;
        else
            return med;
    }
    else
    {
        kernelSize += 2;
        if (kernelSize <= maxSize)
            return adaptiveMedianFilter(img, row, col, kernelSize, maxSize);// 增大窗口尺寸,继续A过程。
        else
            return med;
    }
}


int main()
{
    int minSize = 3;
    int maxSize = 7;
    cv::Mat img;
    img = cv::imread("lena.bmp");
    cv::cvtColor(img, img, cv::COLOR_BGR2GRAY);
    cv::imshow("src", img);
    saltNoise(img, 40000);
    pepperNoise(img, 40000);
    cv::imshow("noise", img);
    cv::Mat temp = img.clone();

    // 自适应中值滤波
    cv::Mat img1;
    // 扩展图像的边界
    cv::copyMakeBorder(img, img1, maxSize / 2, maxSize / 2, maxSize / 2, maxSize / 2, cv::BorderTypes::BORDER_REFLECT);
    // 图像循环
    for (int j = maxSize / 2;j < img1.rows - maxSize / 2;j++)
    {
        for (int i = maxSize / 2;i < img1.cols - maxSize / 2;i++)
        {
            img1.at<uchar>(j, i) = adaptiveMedianFilter(img1, j, i, minSize, maxSize);
        }
    }
    cv::imshow("adaptiveMedianFilter", img1);

    // 中值滤波
    cv::Mat img2;
    int kernelSize = 3;
    cv::copyMakeBorder(temp, img2, kernelSize / 2, kernelSize / 2, kernelSize / 2, kernelSize / 2, cv::BorderTypes::BORDER_REFLECT);
    for (int j = kernelSize / 2;j < img2.rows - kernelSize / 2;j++)
    {
        for (int i = kernelSize / 2;i < img2.cols - kernelSize / 2;i++)
        {
            img2.at<uchar>(j, i) = medianFilter(img2, j, i, kernelSize);
        }
    }
    cv::imshow("medianFilter", img2);

    cv::waitKey();
    cv::destroyAllWindows();

    return 0;
}

Results screenshot

The original image and the image after adding salt and pepper noise.

 

  In fact, there is no obvious difference in the screenshot. After running it on your computer, the result will be clearer. It can be seen that the result of using ordinary median filtering will be blurred compared to the other, and there will still be a small noise point locally. The extra area on the edge of the image is not easy to do median filtering to preserve the original image, so there is still noise around the edge.

Original address: https://www.cnblogs.com/ybqjymy/p/17514444.html 

 The benefits of this article, the fee to receive Qt development learning materials package, technical video, content includes (Qt actual combat project, C++ language foundation, C++ design pattern, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project combat, QSS, OpenCV, Quick module, interview questions, etc. )

Guess you like

Origin blog.csdn.net/m0_73443478/article/details/131917914