目的:
了解OpenCV中canny边缘检测函数的用法,并选取图像进行测试,观察阈值对结果的影响。
实现基于霍夫变换的图像圆检测(边缘检测可以用opencv的canny函数)。
一.Canny边缘检测
1.实验目的:了解OpenCV中canny边缘检测函数的用法,并选取图像进行测试,观察阈值对结果的影响。
2.Canny边缘检测算子是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。更为重要的是 Canny 创立了边缘检测计算理论(Computational theory of edge detection)解释这项技术如何工作。
通常情况下边缘检测的目的是在保留原有图像属性的情况下,显著减少图像的数据规模。
3.步骤:Canny边缘检测算法可以分为以下5个步骤:
(1)应用高斯滤波来平滑图像,目的是去除噪声
(2)找寻图像的强度梯度(intensity gradients)
(3)非最大抑制(non-maximum suppression)技术来消除边误检(本来不是但检测出来是)
(4)使用双阈值的方法来决定可能的(潜在的)边界
(5)利用滞后技术来跟踪边界
3.void Canny(InputArray image,OutputArray edges, double threshold1, double threshold2, int apertureSize=3,bool L2gradient=false )
Mat srcImage = imread(Path);
Mat srcGray;
cvtColor(srcImage, srcGray, CV_BGR2GRAY);
//高斯滤波
GaussianBlur(srcGray, srcGray, Size(3, 3),
0, 0, BORDER_DEFAULT);
//Canny检测
int edgeThresh =100;
Mat Canny_result;
Canny(srcImage, Canny_result, edgeThresh, edgeThresh * 3, 3);
imshow(“src”, srcImage);
imshow(“Canny_result”, Canny_result);
waitKey(0);
下面是阈值从小到大的调节过程:
注意:调用Canny函数的输入和输出图像不能是一个名字,否则就会不断迭代canny:
二.霍夫圆检测
1.实验目的:实现基于霍夫变换的图像圆检测(边缘检测可以用opencv的canny函数)。
对于任意一个圆, 假设中心像素点p(x0, y0)像素点已知, 圆半径已知,则旋转360度,由极坐标方程可以得到每个点上的坐标。同样,如果只是知道图像上像素点, 圆半径,旋转360°,则会有一个集中的交点,即圆心,也就是说圆点处的坐标值最强,这正是霍夫变换检测圆的数学原理。
3.经典方法:
3.1对直线来说, 一条直线能由参数极径极角 (γ, θ) 表示. 而对圆来说, 需要三个参数来表示一个圆。现在原图像的边缘图像的任意点对应的经过这个点的所有可能圆是在三维空间有下面这三个参数来表示了,其对应一条三维空间的曲线. 那么与二维的霍夫线变换同样的道理,对于多个边缘点越多这些点对应的三维空间曲线交于一点那么他们经过的共同圆上的点就越多。
类似的我们也就可以用同样的阈值的方法来判断一个圆是否被检测到, 这就是标准霍夫圆变换的原理, 但也正是在三维空间的计算量大大增加的原因, 标准霍夫圆变化很难被应用到实际中。
3.2 opencv中实现的圆检测算法,一般算法为取参考点,对于边缘像素点计算梯度角,对每一个梯度角,存储对应于参考点的距离和角度;算法具有较好的抗干扰性,但也需要较大的存储空间和计算量,如下是opencv圆检测算法的思路:
4.霍夫变换,两个阶段:
(1)检测圆心:圆心是它所在圆周所有法线的交汇处,因此只要找到这个交点,即可确定圆心:
对输入图像边缘检测;
计算图形的梯度,并确定圆周线,其中圆周的梯度就是它的法线;
在二维霍夫空间内绘出所有图形的梯度直线,坐标点累加和的值越大,则该点上直线相交的次数越多,该点越有可能是圆心;
在霍夫空间的4邻域内进行非最大值抑制;
设定一个阈值,霍夫空间内累加和大于该阈值的点就对应于圆心。
(2)测圆半径的方法是从圆心到圆周上的任意一点的距离相同,首先确定一个阈值,只要计算得到相同距离的数量大于该阈值,就认为该距离就是该圆心所对应的圆半径:
计算某一个圆心到所有圆周线的距离,这些距离中就有该圆心所对应的圆的半径的值,这些半径值当然是相等的,并且这些圆半径的数量要远远大于其他距离值相等的数量;
设定两个阈值:最大半径和最小半径。保留距离在这两个半径之间的值,这意味着我们检测的圆不能太大,也不能太小;
对保留下来的距离进行排序;
找到距离相同的那些值,并计算相同值的数量;
设定一个阈值,只有相同值的数量大于该阈值,就认为该值是该圆心对应的圆半径;
对每一个圆心,完成上面的步骤,得到所有的圆半径。
//边缘检测
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
Mat img,DstPic, edge, grayImage, edge1;
int min1;
int max1;
static void CANNY(int,void*)
{
Canny(edge, edge1, min1, max1, 3);
imshow("canny", edge1);
}
int main()
{
img = imread("D:\\picture\\circle.jpg");
imshow("原始图", img);
namedWindow("canny", 0);
//创建与src同类型和同大小的矩阵
DstPic.create(img.size(), img.type());
DstPic = Scalar::all(0);
//将原始图转化为灰度图
cvtColor(img, grayImage, COLOR_BGR2GRAY);
//先使用3*3内核来降噪
blur(grayImage, edge, Size(5, 5));
//运行canny算子
min1 = 150;
max1 = 230;
//Canny(edge, edge, 70, 100, 3);
createTrackbar("minvalue", "canny", &min1, 200, CANNY);
createTrackbar("maxvalue", "canny", &max1, 300, CANNY);
CANNY(min1,0); CANNY(max1, 0);
waitKey(0);
}
//霍夫变换
#include
#include
using namespace cv;
using namespace std;
int main()
{
Mat edges; //定义转化的灰度图
namedWindow("【效果图】", CV_WINDOW_NORMAL);
while (1)
{
Mat frame;
Mat img = imread("D:\\picture\\circle3.jpg");
//capture >> frame;
if (!img.data)
return -1;
cvtColor(img, edges, CV_BGR2GRAY);
//高斯滤波
GaussianBlur(edges, edges, Size(7, 7), 2, 2);
vector<Vec3f> circles;
//霍夫圆
//HoughCircles(edges, circles, CV_HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);
HoughCircles(edges, circles, CV_HOUGH_GRADIENT, 1, edges.rows / 5, 150, 70, 0, 0);
for (size_t i = 0; i < circles.size(); i++)
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
//绘制圆心
circle(img, center, 3, Scalar(0, 255, 0), -1, 8, 0);
//绘制圆轮廓
circle(img, center, radius, Scalar(155, 50, 255), 2, 8, 0);
}
imshow("【效果图】", img);
waitKey(30);
}
return 0;
}