open cv霍夫变换-圆形检测

一看就懂的霍夫直线检测与圆检测原理
https://blog.csdn.net/shenziheng1/article/details/75307410
一个圆最重要的信息是圆心坐标XY和半径距离

从平面坐标到极坐标转换3个参数C(x0,y0,r)其中x0 ,y0 是圆心 r是半径

假设平面坐标的任意一个圆上的点,转换到极坐标中:
C(x0,y0,r)处有最大值,霍夫变换正是利用这个原理实现圆的检测


霍夫圆检测先检测边缘,将非边缘处都变为零值。遍历所有非零值,
将其投影为(a,b,r)空间的一个圆,笛卡尔坐标中同一个圆上的所有点
投影到(a,b,r)空间将交于一点,这一点为笛卡尔坐标中这个圆的圆心。
(a,b,r)中空间中每一个点有一个累加器,有一条线经过该点,累加器
加1,根据阈值(大于某一个阈值)找到所有可能的圆心。
(x− a)2+(y− b)2 = r2
(a− xo)2 +(b− yo)2 = r2


因为霍夫圆检测对噪声比较敏感,所以首先要对图像做中值滤波
基于效率考虑,opencv中实现的霍夫圆检测是基于图像梯度的实现
分为两步:
(1)检测边缘,发现可能的圆心
(2)基于第一步的基础上从候选圆心开始计算最佳半径大小


相关API cv::HoughCircles

HoughCircles(
InputArray image,//输入图像,必须是8位的单通道灰度图像
OutputArray circles,//输出结果,发现的圆信息,为三元向量组,存储每个可能的圆心坐标和半径信息(a,b,r)
int method,//方法-HOUGH_GRADIENT,求梯度,得到可能的边缘值,其余为零值
double dp,//取dp = 1,代表在原图的尺度下寻找,0.5为在原图的一半尺度上寻找(dpi寻找半径大小)
double mindist,//最短距离可以分辨相隔距离较近的多个圆心是两个圆还是同心圆
double param1,//canny edge detection low threshold 圆检测判断低阈值
double param2,//中心点累加器阈值,候选圆心 通常为30~50
int minradius,//最小半径 范围越大

#include 
#include 
#include 
#include 

using namespace cv;
using namespace std;

Mat src, dst, mblur;
int kksize = 1;
int dp = 1;
int mindist = 30;
int thlow = 100;
int thcp = 15;
int minr = 2;
int maxr = 20;
int Max = 150;

void HoughCircle(int, void*);


int main()
{

	src = imread("D:/实验台/机器视觉/测试图片/霍夫圆检测.jpg");
	if (src.empty())//如果src这个数据库属性为空
	{
		cout << "无法打开" << endl;
		return -1;
	}
	imshow("原图", src);
	namedWindow("霍夫圆检测结果", CV_WINDOW_NORMAL);
	createTrackbar("中值滤波核子大小", "霍夫圆检测结果", &kksize, Max, HoughCircle);
	createTrackbar("检测尺度", "霍夫圆检测结果", &dp, Max, HoughCircle);
	createTrackbar("短距圆心辨别", "霍夫圆检测结果", &mindist, Max, HoughCircle);
	createTrackbar("低阈值过滤", "霍夫圆检测结果", &thlow, Max, HoughCircle);
	createTrackbar("中心点累加器阈值", "霍夫圆检测结果", &thcp, Max, HoughCircle);
	createTrackbar("圆最小半径", "霍夫圆检测结果", &minr, Max, HoughCircle);
	createTrackbar("圆最大半径", "霍夫圆检测结果", &maxr, Max, HoughCircle);
	HoughCircle(0, 0);
	waitKey(0);
	return 0;
}

void HoughCircle(int, void*)
{
	int ksize = kksize * 2 + 1;
	medianBlur(src, mblur, kksize);//中值滤波(高斯滤波也可以)减少噪声对检测结果的影响(中值滤波对椒盐噪声有很好的抑制作用)
	cvtColor(mblur, mblur, CV_BGR2GRAY);//灰度处理转换为8位单通道
	imshow("灰度处理", mblur);
	vector<Vec3f>Pcircles;//定义动态向量3维数组来存储潜在的圆形坐标和半径信息(x0,y0,r)
	//https://blog.csdn.net/dcrmg/article/details/52506538 API及原理详解
	HoughCircles(mblur, Pcircles, CV_HOUGH_GRADIENT, dp, mindist, thlow, thcp, minr, maxr);
	/*霍夫圆检测
	mblur-输入图像 要求为单通道灰度图像
	Pcircles-包含检测到的圆的信息的3维度向量 向量第一个元素为圆的横坐标X0,第二为圆的纵坐标Y0,第三位圆的半径R
	CV_HOUGH_GRADIENT-圆检测算法 只有此算法可选
	dp-累加面与原图相比的分辨率的反比参数 dp=2时累加面分辨率为原图一半(宽高均缩减一半) 为1时两者相同,dp的值不能比1小
	mindist-定义可以分辨相隔距离较近的多个圆心是两个圆还是同心圆的距离
	thlow-低阈值操作 过滤不符合要求的图形
	thcp-圆心阈值 判断累加在圆心上的值是否高于这个阈值 高于阈值的被承认为圆并着色 反之被过滤
	minr&maxr-圆的半径 大小阈值
	*/
	src.copyTo(dst);
	//在调试中程序会不断循环 为了防止画圆在同一张图片中粘合
	//我们需要在每一次数据发生变动时把src图片数据拷贝给dst 
	//实现标记的随时变换并且随操作进行刷新
	for (size_t i = 0; i < Pcircles.size(); i++)//标记圆心和圆 这里的Pcircles.size()是获取的疑似圆心的数量 根据这个数量确认需要绘制几个圆心
	{
		Vec3f cc = Pcircles[i];//传递第i个潜在圆的信息
		circle(dst, Point(cc[0], cc[1]), cc[2], Scalar(0, 0, 255), 2, LINE_AA);
		//画圆(导入图片,Point(圆心x坐标位置 圆心y坐标位置),圆的半径,颜色,线条粗细,线条平滑化);
		circle(dst, Point(cc[0], cc[1]), 2, Scalar(0, 255, 0), 2, LINE_AA);
	}
	imshow("霍夫圆检测结果", dst);
	return;
}

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 );

霍夫圆变换的基本原理和霍夫线变换类似,只是点对应的二维极径极角空间
被三维的圆心点x, y还有半径r空间取代

霍夫圆变换的基本思路是认为图像上每一个非零像素点都有可能是
一个潜在的圆上的一点,跟霍夫线变换一样,也是通过投票,生成
累积坐标平面,设置一个累积权重来定位圆


霍夫圆变换是将二维图像空间中一个圆转换为该圆半径、圆心
横纵坐标所确定的三维参数空间中一个点的过程,因此,圆周
上任意三点所确定的圓,经Hough变换后在 三维参数空间应对
应一点。该过程类似于选举投票过程,圆周上任意三个点为一选
举人,而这三个点所确定的圆则为一侯选人(以下称为候选圆〉
遍历圆周上所有点,任意三个点所确定的候选圆进行投票。
遍历结束后,得票数最高点(理论上圆周上任意三点确定的圆在
Hough变换后均对应三维参数空间中的同一点)所确定的圓即为
该圆周上,绝大多数点所确定的圆(以下称为当选圆),即绝大
多数点均在该当选圆的圆周上,以此确定该圆


CV_HOUGH_GRADIENT算法详解
https://www.cnblogs.com/ql698214/p/5412822.html

为什么需要霍夫变换?

Hough变换能够查找任意的曲线,只要你给定它的方程。Hough变换
在检验已知形状的目标方面具有受曲线间断影响小和不受图形旋转的
影响的优点,即使目标有稍许缺损或污染也能被正确识别。

你可能感兴趣的:(Open,CV,opencv,算法,计算机视觉)