OpenCV-中值滤波算法的学习
in 代码 with 0 commentand 371 read

OpenCV-中值滤波算法的学习

in 代码 with 0 commentand 372 read

图像滤波

首先我们看一下图像滤波的概念。图像滤波,即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接影响到后续图像处理和分析的有效性和可靠性。

消除图像中的噪声成分叫作图像的平滑化或滤波操作。信号或图像的能量大部分集中在幅度谱的低频和中频段是很常见的,而在较高频段,感兴趣的信息经常被噪声淹没。因此一个能降低高频成分幅度的滤波器就能够减弱噪声的影响。
图像滤波的目的有两个:一是抽出对象的特征作为图像识别的特征模式;另一个是为适应图像处理的要求,消除图像数字化时所混入的噪声。
而对滤波处理的要求也有两条:一是不能损坏图像的轮廓及边缘等重要信息;二是使图像清晰视觉效果好。

平滑滤波是低频增强的空间域滤波技术。它的目的有两类:一类是模糊;另一类是消除噪音。
空间域的平滑滤波一般采用简单平均法进行,就是求邻近像元点的平均亮度值。邻域的大小与平滑的效果直接相关,邻域越大平滑的效果越好,但邻域过大,平滑会使边缘信息损失的越大,从而使输出的图像变得模糊,因此需合理选择邻域的大小。

关于滤波器,一种形象的比喻法是:我们可以把滤波器想象成一个包含加权系数的窗口,当使用这个滤波器平滑处理图像时,就把这个窗口放到图像之上,透过这个窗口来看我们得到的图像。

非线性滤波器

一般说来,当信号频谱与噪声频谱混叠时或者当信号中含有非叠加性噪声时如由系统非线性引起的噪声或存在非高斯噪声等),传统的线性滤波技术,如傅里叶变换,在滤除噪声的同时,总会以某种方式模糊图像细节(如边缘等)进而导致像线性特征的定位精度及特征的可抽取性降低。而非线性滤波器是基于对输入信号的一种非线性映射关系,常可以把某一特定的噪声近似地映射为零而保留信号的要特征,因而其在一定程度上能克服线性滤波器的不足之处。

OpenCV

在实现中值滤波算法之前,编译器要安装好OpenCV,

//OpenCV三大头文件
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"

由于最近一直在学习OpenCV的相关算法,所以九七年自己写了一套图片读取和输出的框架(frame)

int main(int argc, char** argv)
{
    //声明IplImage指针
    IplImage* pImg = NULL;
    IplImage* pDealImg = NULL;
    IplImage* pSubImg = NULL;
    Mat mDealImg ;

    pImg = cvLoadImage("F:\\C++code\\OpenCV\\Median_filter(Demo)\\1.jpg", -1);
    int n = pImg->nChannels;
    pDealImg = cvCreateImage(
        cvGetSize(pImg),   //获得输入图片的大小,并进行创建,也可以使用cvSize()  
        pImg->depth,
        pImg->nChannels
    );
    pSubImg = cvCreateImage(
        cvGetSize(pImg),
        pImg->depth,
        pImg->nChannels
        );

    //图像处理
    //处理代码添加在此
    
    
    //图像做差
    cvSub(pImg,pDealImg,pSubImg);

    //创建窗口
    cvNamedWindow("src", CV_WINDOW_AUTOSIZE);
    cvNamedWindow("deal", CV_WINDOW_AUTOSIZE);
    cvNamedWindow("Sub", CV_WINDOW_AUTOSIZE);


    //显示图像
    cvShowImage("src", pImg);
    cvShowImage("deal", pDealImg);
    cvShowImage("Sub", pSubImg);

    cvWaitKey(0); //等待按键

    //销毁窗口
    cvDestroyWindow("src");
    cvDestroyWindow("deal");
    cvDestroyWindow("Sub");

    //释放图像
    cvReleaseImage(&pImg);
    cvReleaseImage(&pDealImg);
    cvReleaseImage(&pSubImg);


    return 0;
}

在实现中值滤波器算法之前,当然是需要知道中值滤波器的实现原理,在学习OpenCV的时候,我们知道了数字图像的是以像素为单位的一种矩阵格式文件,相应的编解码器解码读取,由人眼的补偿功能,所以才得以看到栩栩如生的图像,在OpenCV里图像的处理也就是转化为矩阵(Mat)来处理
OpenCV.png

中值滤波算法

在图像处理中,在进行如边缘检测这样的进一步处理之前,通常需要首先进行一定程度的降噪。中值滤波是图像处理中的一个常用步骤,它对于斑点噪声(specklenoise)和椒盐噪声(alt-and-peppernoise)来说尤其有用。保存边缘的特性使它在不希望出现边缘模糊的场合也很有用。
中值滤波的本质上是一种统计的排序滤波器。对于原图像中某点(i,j),中值滤波以该点为中心的领域内的所有像素的统计排序的中值作为(I,j)的响应,中值不同于均值,是指排序队列中位于中间位置的元素的值。
例如:采用3*3中值滤波器,某点的8个领域的一系列像素的值为:12,18,18,11,23,22,13,25,118,统计的排序结果为:11,12,13,18,18,22,23,25,118,排在中间位置的第5位18作为中间滤波器的响应。而opencv里讲中心像素的正方形领域内的每个像素值用中间像素值替换。

void cvMedianFilter(const Mat &src, Mat &dst,int n)
{
    if (!src.data)return;
    Mat _dst(src.size(), src.type());
    for (int i = 0; i < src.rows; i++)
    {
        for (int j = 0; j < src.cols; j++)
        {
            if ((i - 1) > 0 && (i + 1) < src.rows && (j - 1) > 0 && (j + 1) < src.cols) {
                for (int k = 0; k < n; k++)//各通道滤波
                {
                    _dst.at<Vec3b>(i, j)[k] = Median(src.at<Vec3b>(i, j)[k], src.at<Vec3b>(i + 1, j + 1)[k],
                        src.at<Vec3b>(i + 1, j)[k], src.at<Vec3b>(i, j + 1)[k], src.at<Vec3b>(i + 1, j - 1)[k],
                        src.at<Vec3b>(i - 1, j + 1)[k], src.at<Vec3b>(i - 1, j)[k], src.at<Vec3b>(i, j - 1)[k],
                        src.at<Vec3b>(i - 1, j - 1)[k]);
                }
            }
            else
                _dst.at<Vec3b>(i, j) = src.at<Vec3b>(i, j);
        }
        _dst.copyTo(dst);
    }
}
//3*3方阵取样
unsigned char  Median(unsigned char n1, unsigned char n2, unsigned char n3,
        unsigned char n4, unsigned char n5, unsigned char n6,
        unsigned char n7, unsigned char n8, unsigned char n9) 
    {
    unsigned char arr[9] = {0};
    arr[0] = n1;
    arr[1] = n2;
    arr[2] = n3;
    arr[3] = n4;
    arr[4] = n5;
    arr[5] = n6;
    arr[6] = n7;
    arr[7] = n8;
    arr[8] = n9;
    for (int i = 0; i < 8; i++)
        for (int j = 0; j < 8 - i; j++)
            if (arr[j] > arr[j + 1])
            {
                unsigned char temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
    return arr[4];
    
}

运行效果

效果图.png

评论