计算机视觉——边缘检测与霍夫变换

目的:
了解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);
在这里插入图片描述
下面是阈值从小到大的调节过程:

在这里插入图片描述在这里插入图片描述

(70,200)
在这里插入图片描述
(40,60)
尝试加入滑动条:

在这里插入图片描述在这里插入图片描述

注意:调用Canny函数的输入和输出图像不能是一个名字,否则就会不断迭代canny:

在这里插入图片描述

二.霍夫圆检测

1.实验目的:实现基于霍夫变换的图像圆检测(边缘检测可以用opencv的canny函数)。

  1. 实验原理:在笛卡尔坐标下,圆的表示方程为:(x-a)²+(y-b)²=r²;但在极坐标下,假设已知圆心(x0,y0),那么圆上的点可以表示为:

对于任意一个圆, 假设中心像素点p(x0, y0)像素点已知, 圆半径已知,则旋转360度,由极坐标方程可以得到每个点上的坐标。同样,如果只是知道图像上像素点, 圆半径,旋转360°,则会有一个集中的交点,即圆心,也就是说圆点处的坐标值最强,这正是霍夫变换检测圆的数学原理。

3.经典方法:

3.1对直线来说, 一条直线能由参数极径极角 (γ, θ) 表示. 而对圆来说, 需要三个参数来表示一个圆。现在原图像的边缘图像的任意点对应的经过这个点的所有可能圆是在三维空间有下面这三个参数来表示了,其对应一条三维空间的曲线. 那么与二维的霍夫线变换同样的道理,对于多个边缘点越多这些点对应的三维空间曲线交于一点那么他们经过的共同圆上的点就越多。

类似的我们也就可以用同样的阈值的方法来判断一个圆是否被检测到, 这就是标准霍夫圆变换的原理, 但也正是在三维空间的计算量大大增加的原因, 标准霍夫圆变化很难被应用到实际中。

3.2 opencv中实现的圆检测算法,一般算法为取参考点,对于边缘像素点计算梯度角,对每一个梯度角,存储对应于参考点的距离和角度;算法具有较好的抗干扰性,但也需要较大的存储空间和计算量,如下是opencv圆检测算法的思路:

4.霍夫变换,两个阶段:

(1)检测圆心:圆心是它所在圆周所有法线的交汇处,因此只要找到这个交点,即可确定圆心:
对输入图像边缘检测;
 计算图形的梯度,并确定圆周线,其中圆周的梯度就是它的法线;
 在二维霍夫空间内绘出所有图形的梯度直线,坐标点累加和的值越大,则该点上直线相交的次数越多,该点越有可能是圆心;
 在霍夫空间的4邻域内进行非最大值抑制;
 设定一个阈值,霍夫空间内累加和大于该阈值的点就对应于圆心。

(2)测圆半径的方法是从圆心到圆周上的任意一点的距离相同,首先确定一个阈值,只要计算得到相同距离的数量大于该阈值,就认为该距离就是该圆心所对应的圆半径:
 计算某一个圆心到所有圆周线的距离,这些距离中就有该圆心所对应的圆的半径的值,这些半径值当然是相等的,并且这些圆半径的数量要远远大于其他距离值相等的数量;
 设定两个阈值:最大半径和最小半径。保留距离在这两个半径之间的值,这意味着我们检测的圆不能太大,也不能太小;
 对保留下来的距离进行排序;
 找到距离相同的那些值,并计算相同值的数量;
 设定一个阈值,只有相同值的数量大于该阈值,就认为该值是该圆心对应的圆半径;
 对每一个圆心,完成上面的步骤,得到所有的圆半径。

  1. HoughCircles函数的原型为:
    void HoughCircles(InputArray image,OutputArray circles, int method, double dp, double minDist, double param1=100, double param2=100, int minRadius=0,int maxRadius=0 )
    image为输入图像,要求是灰度图像
    circles为输出圆向量,每个向量包括三个浮点型的元素——圆心横坐标,圆心纵坐标和圆半径
    method为使用霍夫变换圆检测的算法,Opencv2.4.9只实现了2-1霍夫变换,它的参数是CV_HOUGH_GRADIENT
    dp为第一阶段所使用的霍夫空间的分辨率,dp=1时表示霍夫空间与输入图像空间的大小一致,dp=2时霍夫空间是输入图像空间的一半,以此类推
    minDist为圆心之间的最小距离,如果检测到的两个圆心之间距离小于该值,则认为它们是同一个圆心
    param1、param2为阈值
    minRadius和maxRadius为所检测到的圆半径的最小值和最大。
    特定参数检测效果:
    在这里插入图片描述在这里插入图片描述6.发现的一些问题:
    (1)对一些不是很规整的图片是很难找到圆的
    在这里插入图片描述(2)依赖于参数的调节,参数不当会出现如下情况
    在这里插入图片描述调整后Mindist= edges.rows / 5

在这里插入图片描述

//边缘检测
#include<cv.h>
#include<highgui.h>
#include<iostream>
#include<io.h>
#include<opencv2\opencv.hpp>   

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 <opencv2/opencv.hpp>  
#include <opencv2/imgproc/imgproc.hpp>  

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;
}
©️2020 CSDN 皮肤主题: 黑客帝国 设计师:上身试试 返回首页