总结学习下图像处理方面基础知识。算法
这是第一篇,简单的介绍下使用OpenCV的三个基本功能:数据结构
而后概述下图像噪声的类型,并为图像添加两种常见的噪声:高斯噪声和椒盐噪声。
最后,使用中值滤波和均值滤波来处理带有噪声的图像。dom
在OpenCV中,完成图像的输入输出以及显示,只须要如下几个函数:函数
namedWindow
建立一个能够经过其名字引用的窗口。第一个参数,设置窗口的name,能够经过name引用该窗口;第二个参数,设置窗口的大小。有如下几个选择:学习
imshow
显示图像spa
imread
读取图像数据到Mat
中,第一个参数是图像的文件名;第二个参数是标志,标识怎么处理图像的色彩。经常使用的几个选项:设计
Mat
是OpenCV中最重要的数据结构,在作图像处理时基本都是对该结构体的操做。Mat
由两部分构成:矩阵头和矩阵数据,矩阵头较小,建立的每一个Mat
实例都拥有一个矩阵头,而矩阵数据一般占有较大的空间,OpenCV中经过引用计数来管理这部份内存空间,当调用赋值运算符和拷贝构造函数时,并不会只复制矩阵头,并不会复制矩阵数据,只是将其的引用计数加1.例如:指针
Mat m = imread("img.jpg"); Mat a = m; // 赋值运算符 Mat b(m); // 拷贝构造函数
上面代码中的a
,b
和m
各自拥有本身的矩阵头,其引用的数据却指向同一份。也就是说,修改了其中任意一个,都会影响到其他的两个。code
要想复制矩阵数据,能够调用clone
和copyTo
这两个函数orm
Mat m = imread("img.jpg"); Mat f = m.clone(); Mat g ; m.copyTo(g);
将图像读入到Mat
后,有三种方式访问Mat
中的数据:
图像噪声是图像在获取或传输的过程当中受到随机信号的干扰,在图像上出现的一些随机的、离散的、孤立的像素点,这些点会干扰人眼对图像信息的分析。图像的噪声一般是比较复杂的,不少时候将其当作是多维随机过程,于是能够借助于随即过程描述噪声,即便用几率分布函数和几率密度函数。
图像的噪声不少,性质也千差万别, 能够经过不一样的方法给噪声分类。
按照产生的缘由:
噪声和图像信号的关系,能够分为:
最重要的来了,按照几率密度函数(PDF)分类:
按照指定的噪声类型,生成一个随机数,而后将这个随机数加到源像素值上,并将获得的值所放到[0,255]区间便可。
新的随机数生成器被抽象成了两个部分:随机数生成引擎和要生成的随机数符合的分布。
随机数引擎有三种:
第一种最经常使用,并且速度比较快;第二种号称最好的伪随机数生成器
#include <random> std::random_device rd; // 随机数种子 std::mt19937 mt(rd()); // 随机数引擎 std::normal_distribution<> d(5,20); // 高斯分布 std::map<int,int> hist; for(int n = 0; n < 10000; n ++) ++hist[std::round(d(mt))]; // 生成符合高斯分布的随机数
使用C++的随机数发生器为图像添加两种噪声:椒盐噪声和高斯噪声。
椒盐噪声是图像中离散分布的白点或者黑点,其代码以下:
// 添加椒盐噪声 void addSaltNoise(Mat &m, int num) { // 随机数产生器 std::random_device rd; //种子 std::mt19937 gen(rd()); // 随机数引擎 auto cols = m.cols * m.channels(); for (int i = 0; i < num; i++) { auto row = static_cast<int>(gen() % m.rows); auto col = static_cast<int>(gen() % cols); auto p = m.ptr<uchar>(row); p[col++] = 255; p[col++] = 255; p[col] = 255; } }
上述代码中使用ptr<uchar>()
获取图像某一行的行首指针,获得行首指针后就能够任意的访问改行的像素值。
高斯噪声是一种加性噪声,为图像添加高斯噪声的代码以下:
// 添加Gussia噪声 // 使用指针访问 void addGaussianNoise(Mat &m, int mu, int sigma) { // 产生高斯分布随机数发生器 std::random_device rd; std::mt19937 gen(rd()); std::normal_distribution<> d(mu, sigma); auto rows = m.rows; // 行数 auto cols = m.cols * m.channels(); // 列数 for (int i = 0; i < rows; i++) { auto p = m.ptr<uchar>(i); // 取得行首指针 for (int j = 0; j < cols; j++) { auto tmp = p[j] + d(gen); tmp = tmp > 255 ? 255 : tmp; tmp = tmp < 0 ? 0 : tmp; p[j] = tmp; } } }
随机产生符合高斯分布的随机数,而后将该值和图像原有的像素值相加,并将获得的和压缩到[0,255]区间内。
左边是原图,中间的是添加高斯噪声后的图像,最右边的是添加椒盐噪声后的图像。
根据噪声类型的不一样,选择不一样的滤波器过滤掉噪声。一般,对于椒盐噪声,选择中值滤波器(Median Filter),在去掉噪声的同时,不会模糊图像;对于高斯噪声,选择均值滤波器(Mean Filter),可以去掉噪声,但会对图像形成必定的模糊。
在OpenCV中,对应于均值滤波器的函数是blur
,该函数须要5个参数,一般只设置前3个后两个使用默认值便可。
blur(m, m2, Size(5, 5));
第一个参数是输入的图像,第二个参数是输出的图像,第三个参数是滤波器的大小,这里使用的是\(5 \times 5\)的矩形。
对应于中值滤波器的函数是medianBlur(m1, m3, 5);
前两个参数是输入输出的图像,第三个参数是滤波器的大小,因为是选取的是中值,滤波器的大小一般是一个奇数。
下图是对有噪声图像使用滤波器后的结果,中间的是原始图像,左边的是使用均值滤波器过滤高斯噪声后的结果;右边的是使用中值滤波器过滤椒盐噪声后的结果。能够明显的看出,这两种滤波器都可以很好的去掉图像的噪声,但会对图像形成必定的模糊,尤为是均值滤波器形成的模糊比较明显。
本文算是第一篇文章,简单的介绍下OpenCV的基本使用;接着访问图像中的像素,并借助于C++11的随机数库,为图像添加高斯噪声和椒盐噪声;最后使用中值滤波器和均值滤波器除去图像,并对结果进行了对比。
之后坚持每日对图像处理的一些知识进行整理。