问题8:图像的平滑处理,这其实有些地方可以用filt2D来实现,但opencv也写了一些函数
blur()一共5个参数,输入矩阵,输出矩阵,Size(2,3)大小 Point(0,0)指定锚点,若为负数,则表示中心,若模板无中心则自己规定清楚一点,最后一个参数为边界类型;
记住,边界是人为的加入,大的边界冗余在图像处理上是非常不好的。此函数对多维有效。
GaussianBlur()一共6个参数,输入矩阵,输出矩阵,Size大小(3,5)这里都行和列都是奇数,锚点就是中心,函数内部已经使得各个滤波参数和为一,第4和第5个调整高斯 的参数值,第6个是边界的类型,对多维有效。推荐看一下2维高斯的数学推导。
medianBlur(),3个参数,输入,输出,核的大小,要为奇数,默认就是方的,对边界有效,多维有效,边界该是反射101类
bilateralFilter(),双边滤波,对边缘的保留比高斯要好,本质都是空间,滤波,只是参数有异。参数有函数计算得出,可以输入控制。 总的来说,这种处理都与filter2D类似,只是有些函数把参数函数集成好了,自己去计算可能会比较麻烦! 问题9:膨胀与腐蚀: 这个十分的简单,膨胀是白元素的膨胀,腐蚀是对白元素(值大)的腐蚀,首先kernel=getStructuringElement(MORPH_RECT,Size(3,3));确定内核,这里还可以调整锚点,核大小 类型等,然后膨胀dilate(f,f,kernel);这里还可以调整边界的类型等,多维有效,边界有效。erode( src, erosion_dst, element );腐蚀有这个 ,很类似;#include <string> #include <cstdio> #include <cmath> #include <opencv2\opencv.hpp> #include <vector> using namespace cv; using namespace std; void main() { Mat_<Vec3f> f; Mat_<Vec3f> f1; Mat_<Vec3f> f2; Mat_<Vec3f> f3; Mat_<float> kernel; string image_name="../21.png"; f=imread(image_name,CV_LOAD_IMAGE_COLOR); if (f.empty()) { cout<<"failed"<<endl; return; } kernel=getStructuringElement(MORPH_RECT,Size(5,5)); normalize(f,f,0,1,CV_MINMAX); dilate(f,f1,kernel); erode(f,f2,kernel); f3=f1-f2; namedWindow("1",1); imshow("1",f); namedWindow("2",1); imshow("2",f1); namedWindow("3",1); imshow("3",f2); namedWindow("4",1); imshow("4",f3); waitKey(0); } 测试代码如上,图片还是用小人图吧;效果比较明显。 问题10:图像金字塔 这个问题非常的是用,也非常的简单。在点Sift特征时是基本的步骤; 下采样(图片变小)用pyrDown()函数,输入,输出,Size(输入函数/2,输入列数/2)这里要求函数与列数是偶数,还有参数是调整边界的,因为由于滤波器过程 上扩展(图像变大)用 pyrUp(f,f,Size((f.rows*2),(f.cols*2)));同样要求输入f的函数与列数都是偶数,奇数连向上扩展都不行。为了使用函数,有时候我们必须 扩展图像的边界。一个像素就够了,遇到函数时,在判断,在添加!下采样和上扩充过程都使用了滤波器,比较常见的有高斯与拉普拉斯。 问题11:阀值操作 这个非常简单,多维有效,由于针对单个元素,所以没有边界的问题。threshold(f,f,205,188,0);,输入,输出,阀值,大鱼阀值后的值取值,最后一个为类型,0表示 2值化,不超过的变为0.超过变成188;1表示超过变成0,不超过(含等于)变成188;2表示不能超过第3个参数(这里是205),超过就变成了205,这时候第4个参数是无效的;3表示不 超过的变成0,超过是原样;4表示超过变成0,不超过原样。挺有意思的。 问题12:给图形添加边界 图像的边界在前面我们已经用到很多了。因为有时候为了规范化,我们必须向图像添加一个边界。 copyMakeBorder()函数,这个在前面可能没讲清楚。一共8个参数,第一个输入的矩阵,第二个输出,然后是原始矩阵的上下左右需要添加的边界的宽度,然后的类型,若为 BORDER_CONSTANT,还可以设置最后一个参数。支持多维copyMakeBorder(f,f,2,0,2,0,BORDER_CONSTANT,Scalar(3,3,3));上和左增加2维,为(3,0,0),常用的是BORDER_REFLECT_101 具体见http://www.linuxidc.com/Linux/2012-12/75965.htm;应该比较详细 问题13:Sobel导数 其实就是2次空间卷积(计算x方向与y方向的2个模板),近似的得出在像素变化点较大的值。 #include <string> #include <cstdio> #include <cmath> #include <opencv2\opencv.hpp> #include <vector> using namespace cv; using namespace std; void main() { int i,j; Mat_<Vec3f> f; Mat_<Vec3f> f1; Mat_<Vec3f> f2; string image_name="../Lena.jpg"; f=imread(image_name,CV_LOAD_IMAGE_COLOR); if (f.empty()) { cout<<"failed"<<endl; return; } GaussianBlur(f,f,Size(5,5),0,0); Sobel(f,f1,f1.depth(),1,0); Sobel(f,f2,f2.depth(),0,1); for(i=0;i<f.rows;i++) for (j=0;j<f.cols;j++) { f(i,j)[0]=sqrt(f1(i,j)[0]*f2(i,j)[0]); f(i,j)[1]=sqrt(f1(i,j)[1]*f2(i,j)[1]); f(i,j)[2]=sqrt(f1(i,j)[2]*f2(i,j)[2]); } normalize(f,f,0,1,CV_MINMAX); imshow("1",f); waitKey(0); } 彩图也可以算,支持多维的。Scharr函数与sobel类似,只是内核不一样,参数都一样,效果也差不多。大概还是能找出图像的边界轮廓的。 问题14:拉普拉斯算子,这是基于2阶导的,因为最大值的点与一阶导有区别。也能找出边界轮廓,貌似效果比一阶的要好一些,支持多维。 #include <string> #include <cstdio> #include <cmath> #include <opencv2\opencv.hpp> #include <vector> using namespace cv; using namespace std; void main() { int i,j; Mat_<Vec3f> f; string image_name="../Lena.jpg"; f=imread(image_name,CV_LOAD_IMAGE_COLOR); if (f.empty()) { cout<<"failed"<<endl; return; } GaussianBlur(f,f,Size(5,5),0,0); Laplacian(f,f,f.depth(),3); for(i=0;i<f.rows;i++) for (j=0;j<f.cols;j++) { f(i,j)[0]=sqrt(f(i,j)[0]*f(i,j)[0]); f(i,j)[1]=sqrt(f(i,j)[1]*f(i,j)[1]); f(i,j)[2]=sqrt(f(i,j)[2]*f(i,j)[2]); } cout<<f(2,3)[0]<<endl<<f(2,3)[1]<<endl<<f(2,3)[2]<<endl; normalize(f,f,0,1,CV_MINMAX); imshow("1",f); waitKey(0); } 因为拉普拉斯算子会算出很多的负值,所以我们有一步将其取了绝对值。拉普拉斯算子一步到位,不需要想sobel一样2步了! 问题15:Canny 边缘检测算法,这个算法被很多人认为是边缘检测的最优化算法 这其实可以看成是一种组合算法,里面包含了高斯滤波,sobel等,最后只要一步 但是它要求输入与输出都是一维的uchar类型的,输出的结果是2值的,边缘是白不是边缘是黑。 Mat_<uchar> f; string image_name="../Lena.jpg"; f=imread(image_name,CV_LOAD_IMAGE_GRAYSCALE); if (f.empty()) { cout<<"failed"<<endl; return; } Canny(f,f,40,120); /*for(i=0;i<f.rows;i++) for (j=0;j<f.cols;j++) { f(i,j)[0]=sqrt(f(i,j)[0]*f(i,j)[0]); f(i,j)[1]=sqrt(f(i,j)[1]*f(i,j)[1]); f(i,j)[2]=sqrt(f(i,j)[2]*f(i,j)[2]); } cout<<f(2,3)[0]<<endl<<f(2,3)[1]<<endl<<f(2,3)[2]<<endl; */ //normalize(f,f,0,1,CV_MINMAX); imshow("1",f); waitKey(0); 若想对彩图,每一维分开做canny,最后再合并,但是由于最终值的2值性(不是0就是255),其彩色的效果应该也不是很好。 问题16:霍夫线性变换 霍夫变换,就是想要判断图像中那些点是直线,它的应用是基于canny的,输入时图像canny后的图像,白色的边缘代表的是空间中存在的点 类似的还有霍夫圆检测,它可将检测出图像中的圆,也是针对边界来做检测的,但是好像把canny函数集成到了里面,并不需要显示的。直接输入灰度图像即可。这里暂且不做深究。