http://ronny.blog.51cto.com/8801997/1394138

OpenCV成长之路:图像滤波

2014-04-11 14:28:44

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://ronny.blog.51cto.com/8801997/1394138

滤波实际上是信号处理里的一个概念,而图像本身也可以看成是一个二维的信号。其中像素点灰度值的高低代表信号的强弱。

高频:图像中灰度变化剧烈的点。

低频:图像中平坦的,灰度变化不大的点。

根据图像的高频与低频的特征,我们可以设计相应的高通与低通滤波器,高通滤波可以检测图像中尖锐、变化明显的地方;低通滤波可以让图像变得光滑,滤除图像中的噪声。

下面我们来看一下OpenCV中的一些滤波函数:

一、低通滤波

1,blur函数

这个函数是一个平滑图像的函数,它用一个点邻域内像素的平均灰度值来代替该点的灰度。

cv::blur(image,result,cv::Size(5,5));

2,高斯模糊

上面的blur的平滑原理是用邻域内的平均值来代替当前的灰度值,但是我们往往希望越靠近该像素的点提供越高的权重,这样就产生了高斯模糊滤波。它的滤波器或者叫遮罩是一个高斯分布的二维矩阵。

cv::GaussianBlur(image,result,cv::Size(5,5),1.5);

参数image为输入图像,result为输出图像,Size(5,5)定义了核的大小,最后一个参数说明了高斯核的方差。

3,中值滤波

上面讲到的2个滤波器,都是邻域内的像素按照一个权重相加最后设置为当前点的灰度值,这种操作又称为卷积,这样的滤波器叫线性滤波器,另外还有一种非线性的滤波器,比如中值滤波器,它是取邻域内所有像素的中值作为当前点的灰度值。

中值即排序后中间的那个值:median({1,2,3,3,7,5,1,8})=3。

cv::medianBlur(image,result,5);

其中最后一个参数指定了邻域的大小为5*5。中值滤波也是在实际中应用最多的平滑滤波,它可以有效的去除比如椒盐噪声一类的干扰。

下面我们对比一下上面三种滤波器的效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
int main()
{
    using namespace cv;
    Mat image=imread("../cat.png");
    cvtColor(image,image,CV_BGR2GRAY);
    Mat blurResult;
    Mat gaussianResult;
    Mat medianResult;
    blur(image,blurResult,Size(5,5));
    GaussianBlur(image,gaussianResult,Size(5,5),1.5);
    medianBlur(image,medianResult,5);
    namedWindow("blur");imshow("blur",blurResult);
    namedWindow("Gaussianblur");imshow("Gaussianblur",gaussianResult);
    namedWindow("medianBlur");imshow("medianBlur",medianResult);
    waitKey();
    return 0;
}

二、高通滤波:边缘检测

高通滤波器最好的一个应用就是边缘检测,由文章开头分析可知高频是图像中变化剧烈的地方,所以图像的边缘区域恰好符合这一特性,我们可以利用高通滤波让图像的边缘显露出来,进一步计算图像的一些特征。

边缘检测本来打算作为一个单独的主题来写一篇文章,但是由于Canny边缘检测算法比较复杂,篇幅也较大,所以先把Sobel边缘检测在高通滤波这里作为一个实例,以后Canny边缘检测作为单独的一篇文章来写。

实际上OpenCV有提供了Sobel边缘检测的函数,但是一方面阈值好像取的不太好,另一方面没有对最后边缘作细化处理,所以效果并不太让人满意,本文是模仿Matlab中算法来写的,相关的理论可以参考我原来写过的一篇文章《视觉算法:Sobel边缘检测》。

下面是Sobel实现的C++代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
bool Sobel(const Mat& image,Mat& result,int TYPE)
{
    if(image.channels()!=1)
        return false;
    // 系数设置
    int kx(0);
    int ky(0);
    if( TYPE==SOBEL_HORZ ){
        kx=0;ky=1;
    }
    else if( TYPE==SOBEL_VERT ){
        kx=1;ky=0;
    }
    else if( TYPE==SOBEL_BOTH ){
        kx=1;ky=1;
    }
    else
        return false;
    // 设置mask
    float mask[3][3]={{1,2,1},{0,0,0},{-1,-2,-1}};
    Mat y_mask=Mat(3,3,CV_32F,mask)/8;
    Mat x_mask=y_mask.t(); // 转置
    // 计算x方向和y方向上的滤波
    Mat sobelX,sobelY;
    filter2D(image,sobelX,CV_32F,x_mask);
    filter2D(image,sobelY,CV_32F,y_mask);
    sobelX=abs(sobelX);
    sobelY=abs(sobelY);
    // 梯度图
    Mat gradient=kx*sobelX.mul(sobelX)+ky*sobelY.mul(sobelY);
    // 计算阈值
    int scale=4;
    double cutoff=scale*mean(gradient)[0];
    result.create(image.size(),image.type());
    result.setTo(0);
    for(int i=1;i<image.rows-1;i++)
    {
        float* sbxPtr=sobelX.ptr<float>(i);
        float* sbyPtr=sobelY.ptr<float>(i);
        float* prePtr=gradient.ptr<float>(i-1);
        float* curPtr=gradient.ptr<float>(i);
        float* lstPtr=gradient.ptr<float>(i+1);
        uchar* rstPtr=result.ptr<uchar>(i);
        // 阈值化和极大值抑制
        for(int j=1;j<image.cols-1;j++)
        {
            if( curPtr[j]>cutoff && (
                (sbxPtr[j]>kx*sbyPtr[j] && curPtr[j]>curPtr[j-1] && curPtr[j]>curPtr[j+1]) ||
                (sbyPtr[j]>ky*sbxPtr[j] && curPtr[j]>prePtr[j] && curPtr[j]>lstPtr[j]) ))
                rstPtr[j]=255;
        }
    }
    return true;
}

本文出自 “Ronny的成长之路” 博客,请务必保留此出处http://ronny.blog.51cto.com/8801997/1394138

最新文章

  1. instanceof运算符
  2. 「LeetCode」全部题解
  3. Android Monkey 压力测试 介绍
  4. Qt:Drag-Drop操作在QGraphicsView及Model/View框架下的实现
  5. 第 26 章 CSS3 动画效果
  6. Android源码学习之模板方法模式应用
  7. nginx 缓存机制
  8. HDU 4349 Xiao Ming&#39;s Hope
  9. 【算法】 输入n 输出一个n*n的zigzag矩阵 利用c++实现
  10. Log4net - 规则简介(续)
  11. 一个优秀的http实现框架
  12. Going Home - poj 2195(最小费用流 | 二分匹配)
  13. Map的遍历方法及String和其它类型的相互转化
  14. linux上大量tcp端口处于TIME_WAIT的问题
  15. 利用python 实现微信公众号群发图片与文本消息功能
  16. 实施一个SAP项目大概分为下面几个过程
  17. C# Json字符串保存信息
  18. GIT 生成公钥
  19. JSP(6)—JavaBean及案例
  20. J2EE十三个技术规范

热门文章

  1. xampp版本和具体的php,mysql版本的对应
  2. jx problem
  3. WEB 技术分类 Javascript DOM(Element Node) BOM
  4. chrom扩展学习
  5. 黑帽么metasploit
  6. Major and minor numbers
  7. 【转】python - PyDev统一编码
  8. git 和 svn
  9. POJ 2348 Euclid's Game(简单博弈)
  10. POJ 1065 Wooden Sticks#贪心+qsort用法