自适应中值滤波器

Posted cyssmile

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自适应中值滤波器相关的知识,希望对你有一定的参考价值。

今天闲着无聊,实现了下《数字图像处理(第三版)》P209页的,自适应中值滤波器。

原理书上都有,我自己实现的代码可能有点复杂。对图片的边缘处理有些粗糙。有兴趣可以自己改进下。
看下实验效果吧!
技术图片
左边第一幅图片是原始图片
中间的是对全图 加上了0.25 比例的椒盐噪声,可以看出来,几乎已经看不出来原始模样了。
右边的是经过自适应中值滤波处理后的图片。
逐像素的处理的额,速度有点慢。边缘简单的处理了,可以改进。
这段代码地址:https://github.com/cyssmile/openCV_learning_notes/blob/master/opencv_test/opencv_023/opencv_023.cpp

#include<opencv2/opencv.hpp>
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
using namespace cv;

void addSoaltAndPepperNoise(Mat &images, int numberOfNoise);
void adaptiveMedianBlur(Mat &images);
int getBordValue(int Length, int step, int kernelSize);
void autoCopyMakeBorder(Mat &images, int borderType, int step, int kernelSize);
void getMinMaxSplitChannel(Mat &images, double &min_val, double &max_val);
void getMedianSplitChannel(Mat &images, double &median_val);
double process_B(double Z_xy, double min_val, double max_val, double median_val);
double dealSplitSubImages(Mat &split_images,int &S_now);
void dealMainSplitImages(Mat &split_images, Mat &split_images_clone);
void dealDstEdges(Mat &src, int edges);

int main(int argc, char** argv)
{
    Mat src = imread("D:/images/test.jpg", -1);
    if (src.empty())
    {
        cout << " can`t open this ph" << endl;
    }
    imshow("src_win", src);
    Mat images_src = src.clone();
    /*
    * 添加全图0.25比例的椒盐噪声
    */
    int row = images_src.rows;
    int col = images_src.cols;
    addSoaltAndPepperNoise(images_src, row*col*0.25);
    adaptiveMedianBlur(images_src);
    waitKey(0);
    destroyAllWindows();
    return 0;
}

/*
* add salt and pepper noise into source images
* cyssmile
* 2020/3/15
*/
void addSoaltAndPepperNoise(Mat &images, int numberOfNoise)
{
    RNG rng(12345);
    int row = images.rows;
    int col = images.cols;
    for (int i = 0; i < numberOfNoise; i++)
    {
        int x = rng.uniform(0, row);
        int y = rng.uniform(0, col);
        if (i % 2 == 0)
        {
            images.at<Vec3b>(x, y) = Vec3b(255, 255, 255);
        }
        else
        {
            images.at<Vec3b>(x, y) = Vec3b(0, 0, 0);
        }
    }
    imshow("salt and pepper noise", images);
}

/*
* get the value of copyMakeBorder
* cyssmile
* 2020/3/19
*/
int getBordValue(int Length, int step, int kernelSize) 
{
    return (Length*(step - 1) - step + kernelSize) / 2;
}

/*
* auto fill picture
* cyssmile
* 2020/3/19
*/
void autoCopyMakeBorder(Mat &images, int borderType, int step, int kernelSize)
{
    int row = images.rows;
    int col = images.cols;
    int hightValue = getBordValue(row, step, kernelSize);
    int widthValue = getBordValue(col, step, kernelSize);
    copyMakeBorder(images, images, hightValue, hightValue, widthValue, widthValue, borderType);
}
/*
* adaptive median filtering
* Anchor Point at top left corner
* S_Min =3,S_Max=5
* cyssmile
* 2020/3/19
*/
void adaptiveMedianBlur(Mat &images) 
{
    int S_Max = 5;
    int S_Min = 3;
    int row = images.rows;
    int col = images.cols;
    Mat images_clone = images.clone();
    autoCopyMakeBorder(images, BORDER_DEFAULT, 1, S_Min);
    
    vector<Mat> sub_images;
    split(images,sub_images);

    vector<Mat> sub_images_clone;
    split(images_clone, sub_images_clone);

    for (int i=0;i<images.channels();i++) 
    {
        dealMainSplitImages(sub_images[i], sub_images_clone[i]);
    }
    Mat dst;
    merge(sub_images_clone,dst);
    dealDstEdges(dst, S_Max);
    imshow("dst_output", dst);
}
/*
* get the min and max value in images
* cyssmile
* 2020/03/19
*/
void getMinMaxSplitChannel(Mat &images,double &min_val,double &max_val)
{
    Point minloc, maxloc;
    minMaxLoc(images, &min_val, &max_val, &minloc, &maxloc);
}

/*
* get the median  value in images(roi)
* cyssmile
* 2020/03/19
*/
void getMedianSplitChannel(Mat &images,double &median_val) 
{
    vector<double> images_data;
    for (int i =0;i<images.rows;i++) 
    {
        for (int j = 0; j < images.cols; j++) 
        {
            images_data.push_back(images.at<uchar>(i, j));
        }
    }
    sort(images_data.begin(),images_data.end());
    median_val = images_data[images.rows*images.cols/2];
}
/*
* process_B
* cyssmile
* 2020/03/19
*/
double process_B(double Z_xy,double min_val,double max_val,double median_val) 
{
    if (Z_xy-min_val>0 && Z_xy-max_val<0) 
    {
        return Z_xy;
    }
    else
    {
        return median_val;
    }
}
/*
* give a roi images and then return in (x,y) its (maybe) value
* cyssmile
* 20/03/19
*/
double dealSplitSubImages(Mat &split_images,int &S_now) 
{
    double min = split_images.at<uchar>(0, 0);
    double &min_val = min;
    double max = split_images.at<uchar>(0, 0);
    double &max_val = max;
    getMinMaxSplitChannel(split_images, min_val, max_val);

    double median = split_images.at<uchar>(0, 0);
    double &median_val = median;
    getMedianSplitChannel(split_images, median_val);

    double result_piexl= split_images.at<uchar>(0, 0);
    if (median - min_val > 0 && median - max_val < 0)
    { // turn process B
        result_piexl = process_B(split_images.at<uchar>(0, 0), min_val, max_val, median_val);

    }else {
        S_now = S_now + 2;
    }
    return result_piexl;
}
/*
* deal a splited channel images
* cyssmile
* 20/03/19
*/
void dealMainSplitImages(Mat &split_images,Mat &split_images_clone) 
{
    int S_Min = 3, S_Max = 7;
    for (int i = 0; i < split_images_clone.rows; i++)
    {
        for (int j = 0; j < split_images_clone.cols; j++)
        {
            int S_now = S_Min;
            double median;
            double result_piexl = split_images_clone.at<uchar>(i, j);
            if ((i + S_Max < split_images.rows )&& (j + S_Max < split_images.cols))
            {
                while (S_now <= S_Max)
                { //重复A处理过程
                    Rect rec;
                    rec.x = j;
                    rec.y = i;
                    rec.width = S_now;
                    rec.height = S_now;
                    if ((rec.x + S_now >= split_images.rows) && (rec.y + S_now >= split_images.cols))
                    {
                        break;
                    }
                    Mat sub = split_images(rec);
                    int S_old = S_now;
                    result_piexl = dealSplitSubImages(sub, S_now);
                    if (S_old == S_now) 
                    {
                        break;
                    }
                    else 
                    {
                        getMedianSplitChannel(sub, median);
                        result_piexl = median;
                    }
                }
            }
            split_images_clone.at<uchar>(i, j) = result_piexl;
        }
    }
}

/*
* deal edges int dst images
* cyssmile
* 20/03/19
*/
void dealDstEdges(Mat &src,int edges) 
{
    Rect rec;
    rec.x = src.cols - edges;
    rec.y = 0 ;
    rec.width = edges;
    rec.height = src.rows;
    Mat NeedDealMat = src(rec);
    medianBlur(NeedDealMat, NeedDealMat, 3);
    
    Rect rec_bottom;
    rec_bottom.x = 0;
    rec_bottom.y = src.rows - edges;
    rec_bottom.width = src.cols;
    rec_bottom.height = edges;
    Mat NeedDealMat_bottom = src(rec_bottom);
    medianBlur(NeedDealMat_bottom, NeedDealMat_bottom, 3);
}

引用请注明出处

以上是关于自适应中值滤波器的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV 例程200篇101. 自适应中值滤波器

OpenCV 例程200篇101. 自适应中值滤波器

每日一练之自适应中值滤波器(基于OpenCV实现)

图像去噪基于matlab自适应中值滤波图像去噪含Matlab 1156期

图像去噪基于matlab自适应中值滤波图像去噪含Matlab 1844期

基于Opencv的自适应中值滤波函数selfAdaptiveMedianBlur()