滤波是图像处理中的一个基本操作。滤波去除图像中的噪声,提取感兴趣的特征,允许图像重采样。
图像中的频率和空域:空间域指用图像的灰度值来描述衣服图像,而频域指用图像灰度值的变化来描述一幅图像。
低通滤波器和高通滤波器的概念是在频率中产生的。低通滤波器指去除图像中的高频成分,而高通滤波器指去除图像中的低频成分。
Mat image = imread("1.jpg",1);
Mat result;
blur(image,result,Size(5,5));//模板大小 5*5
namedWindow("均值滤波");
imshow("均值滤波",result);
GaussianBlur(image,result,Size(7,7),1.5);//1.5 是sigma系数
namedWindow("高斯滤波");
imshow("高斯滤波",result);
低通滤波器的效果是对图像进行模糊和平滑,减弱了物体边缘可见的快速变化。它是一种线性滤波器,原理是与核进行卷积运算,此时的核是内定的。如果你需要自定义核,我们就可以使用filter2D指定 Mask模板。
medianBlur(image,result,5);// 5 是ksize
namedWindow("中值滤波");
imshow("中值滤波",result);
y方向可以这么记:
下减上。 在模板中的第三行减去第一行,就是求导了。
x方向同理。右减左。
Sobel(InputArray src, OutputArray dst, int ddepth,int dx, int dy, int
ksize=3,doublescale=1, double delta=0,int borderType=BORDER_DEFAULT );
ddepth为图像类型,(dx,dy) = (1,0)为x方向导数,(dx,dy) = (0,1)为y方向导数。 scale和delta的作用是在对图像保存前可以对图像进行缩放操作。
即为dst = dst*scale+delta;
示例代码如下:
Mat sobel_x;
image = imread("1.jpg",1);
Sobel(image,sobel_x,CV_8U,1,1,3);
namedWindow("sobel滤波");
imshow("sobel滤波",sobel_x);
Mat matLaplacian;
image = imread("1.jpg",1);
Laplacian(image,matLaplacian,CV_16S,3);
//Laplacian(image,matLaplacian,CV_16S,3);或者直接CV_16S类型,这样不需要进行转变,但是此时计算的值会失去精度
matLaplacian = abs(matLaplacian);//二阶导数肯定含有负数
matLaplacian.convertTo(matLaplacian,CV_8U);
namedWindow("拉普拉斯");
imshow("拉普拉斯",matLaplacian);
Sobel算子和拉普拉斯变换可以进行边缘检测,但是这样的二值边缘图像有两个缺点:第一,检测到的边缘过粗,这意味着难以实现物体的精确定位。第二,难以找到这样的阈值,即能够检测到所有重要的边缘,同时不至于包含过多次要的边缘。
高斯滤波器的大小:第一步所用的平滑滤波器将会直接影响 Canny 算法的结果。opencv中没有这个参数的设定,matlab中有。
Mat bw;
image = imread("1.jpg",0);
threshold(image,bw,100,255,THRESH_BINARY);//进行二值化
vector<vector > contours;
findContours(bw,contours,CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE,Point(0,0));
//可以进一步处理 移除过小或过大的轮廓
int cmin = 100;
int cmax = 1000;
vector<vector >::const_iterator itc = contours.begin();
while (itc!=contours.end())
{
if (itc->size()size()>cmax)
{
itc = contours.erase(itc); //这个是STL中的技术点,删除元素后一定要记住返回的迭代器值,因为删除后,
//原始迭代器的值就立刻失效了,返回的才是一个有效迭代器
}
else itc++;
}
Mat conresult(image.size(),CV_8U,Scalar(255));
drawContours(conresult,contours,-1,Scalar(0),2);
namedWindow("轮廓");
imshow("轮廓",conresult);
//原始hough变换
Mat image = imread("1.jpg",0);
Mat result;
Canny(image,result,150,220);
vector lines;
HoughLines(result,lines,1,3.1415926/180,50);
for (size_t i =0;ifloat rho = lines[i][0],theta = lines[i][1];
Point pt1(rho/cos(theta),0),pt2((rho-result.rows*sin(theta))/cos(theta),result.rows);
line(image,pt1,pt2,Scalar(255),3,CV_AA);
}
namedWindow("基本hough");
imshow("基本hough",image);
houghlines的计算效率比较低O(n*n*m),耗时较长,而且没有检测出直线的端点。概论霍夫直线检测houghlinesP是一个改进,不仅执行效率较高,而且能检测到直线的两个端点。
houghlinesP不是系统的进行扫描图像,而是随机挑选像素点,一旦累加器中某一项达到给定的最小值,那么扫描沿着对应像素并移除所有经过的像素点。得到的是一条线段。会将一条直线(表示为x0,y0,x1,y1)放入vector中。
image = imread("1.jpg",0);
vector linesHoughP;
HoughLinesP(result,linesHoughP,1,3.1415926/180,50,50,10);//最小投票为50(直线上的点不少于50),线条不短于50,间隙不小于10
for (size_t i =0;i0],I[1]),Point(I[2],I[3]),Scalar(255),3,CV_AA);
}
namedWindow("概念hough");
imshow("概念hough",image);
其实hough变换理论可以检测任何可以使用参数表示的图形,比如常用的还有hough圆检测,类似。
vector circles;
HoughCircles(result,circles,CV_HOUGH_GRADIENT,
2,//累加器的分辨率
50,//两个圆之间的最小距离
200,//canny高阈值
100,//最小投票数
);
HoughCircles整合了canny检测和hough变换。