自适应中值滤波器

今天闲着无聊,实现了下《数字图像处理(第三版)》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);
}

引用请注明出处

原文地址:https://www.cnblogs.com/cyssmile/p/12527109.html

时间: 2024-11-03 10:44:12

自适应中值滤波器的相关文章

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

本文主要介绍了自适应的中值滤波器,并基于OpenCV实现了该滤波器,并且将自适应的中值滤波器和常规的中值滤波器对不同概率的椒盐噪声的过滤效果进行了对比.最后,对中值滤波器的优缺点了进行了总结. 空间滤波器 一个空间滤波器包括两个部分: 一个邻域,滤波器进行操作的像素集合,通常是一个矩形区域 对邻域中像素进行的操作 一个滤波器就是在选定的邻域像素上执行预先定义好的操作产生新的像素,并用新的像素替换掉原来像素形成新的图像. 通常,也可以将滤波器称之为核(kernel),模板(template)或者窗

[数字图像处理]图像去噪初步(2)--非线性滤波器

1.非线性处理与线性处理的区别 上一篇博文的内容,是关于均值滤波器的.比如说像算术均值滤波器,几何均值滤波器.这以类型的滤波器的常常被用于剔除某些不需要的频率成分,或者选择需要的频率成分,从而达到去噪的目的.这样的滤波器,被称为线性滤波器. 然而,还有一些特殊滤波器,他们被称为非线性滤波器.其代表为中央值滤波器.所谓中央值滤波器,就是将一定范围内的数据(对于图像而言,是像素的灰度值)进行排序,选择中央值作为滤波器的输出. 中央值滤波器的目的并不是频率成分的选择,而是求root信号.关于root信

各种变换滤波和噪声的类型和用途总结

摘自http://imgtec.eetrend.com/blog/4564 一.基本的灰度变换函数 1.1图像反转 适用场景:增强嵌入在一幅图像的暗区域中的白色或灰色细节,特别是当黑色的面积在尺寸上占主导地位的时候. 1.2对数变换(反对数变换与其相反) 过程:将输入中范围较窄的低灰度值映射为输出中较宽范围的灰度值. 用处:用来扩展图像中暗像素的值,同时压缩更高灰度级的值. 特征:压缩像素值变化较大的图像的动态范围. 举例:处理傅里叶频谱,频谱中的低值往往观察不到,对数变换之后细节更加丰富. 1

[DIP] 数字图像处理 (MATLAB) CH05

---慢慢地go through冈萨雷斯的DIP和配套的matlab,记下一些零碎的知识点给自己以后复习. DIP CH05 图像复原与重建 首先是一些空间域和频域添加噪声的方法,书中编写了imnoise2与imnoise3,分别在空间域和频域添加噪声(频域噪声对应空间周期噪声).其中imnoise2主要是利用函数rand()与randn(),分别生成均匀分布(U(0,1))与高斯分布(N(0,1))的随机数,配合find()函数进行噪声生成:imnoise3则利用第四章的知识,用fftshif

几种常见空间滤波器MATLAB实现

本文链接:https://blog.csdn.net/LYduring/article/details/80443573 一.目的实现算术均值滤波器.几何均值滤波器.中值滤波器.修正的阿尔法均值滤波器.自适应中值滤波器,并比较不同滤波器的降噪结果. 二.代码代码的思路如下: (1)先对原始的电路图先后进行加高斯噪声和椒盐噪声:之后设置滤波器的模板大小为5*5,分别对被噪声污染的图像进行算术均值.几何均值.中值.修正的阿尔法滤波,并输出图像,方便结果比较. (2)为了比较中值滤波器和自适应中值滤波

移动页面HTML5自适应手机屏幕宽度

网上关于这方面的文章有很多,重复的东西本文不再赘述,仅提供思路,并解释一些其他文章讲述模糊的地方. 1.使用meta标签,这也是普遍使用的方法,理论上讲使用这个标签是可以适应所有尺寸的屏幕的,但是各设备对该标签的解释方式及支持程度不同造成了不能兼容所有浏览器或系统. 首先解释该标签的含义: <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, max

前端 css 垂直居中及自适应问题

此css作用为将下面div结构中的Container-fluid背景自适应屏幕,content自适应居中 1.Div结构 all Head Container-fluid Content Under <div id="all">   <div  class="head" style="height: 81px;width: 100%;min-width: 1000px;position: relative;">      

WordPress解决优酷、土豆视频移动端观看问题并自适应

转:https://www.xhsay.com/wp-iframe-handler-youku-tudou.html 虽然WordPress能直接插入优酷.土豆的视频但是无法在移动端观看,于是乎笨笨就开始各种折腾终于找到了合适的解决办法另外在说一句支持移动端自适应哦. 函数代码 在主题函数文件function.php里面添加以下代码即可,保证在最后一个?>之前就好了 //Youku function wp_iframe_handler_youku($matches, $attr, $url, $

firemonkey 手机屏幕自适应程序问题

我是新手.在我才学了2个星期的时候,那个白痴老板说什么手机屏幕自适应程序,我当时不能理解呀,觉得用Delphi的布局设计不就行了吗.结果他说:我就是想让控件内容什么的放在小屏幕手机上也不出来.我就说,那用布局layout.结果那个傻x又是画控件关于屏幕的位置,又是记录控件的位置,整了一大套.整个把我给整晕了,新手伤不起啊,我不知道Delphi xe5有一个控件布局叫ScaledLayout,结果捣鼓了很长时间.我在Delphi交流群里说这个功能时,大家都说我想多了.唉 ,没办法自己又把控件布局什