计算机视觉讨论群162501053
看本文前,建议先去看
OpenCV2马拉松第22圈——Hough变换直线检测原理与实现
收入囊中
- Hough圆检测
- 通用Hough变换
葵花宝典
我们在之前利用Hough变换实现了直线的检测,因为两个特征(k,b)或者(theta,r)就能确定一条直线,所以我们的Hough空间是二维的。一个圆由3个特征组成,分别是圆心的横坐标,纵坐标,以及圆的半径,因此我们的Hough空间是三维的。
圆的方程:(x-a)^2 + (y-b)^2 = r^2
过一点(x0,y0),a,b,r的关系就是:(x0-a)^2 + (y0-b)^2 = r^2
因此,我们的Hough空间[a是横坐标,b是纵坐标,r是竖坐标]
我们要用一个二重循环去填充Hough空间
跟直线检测一样,我们现在是在三维数组里找局部最大值,确定圆的(x,y,r)
听完之后是不是觉得方法很简单,跟检测直线没什么区别,也用不到极坐标。
但是,三维累加器中会产生许多噪声并且使得结果不稳定的稀疏分布!
因此,由Hough梯度法来改进这个算法。
Hough梯度法
- 利用canny检测提取边缘
- 对每一个边缘点,我们可以计算出梯度[其实就是圆心和边缘点连线方向]
- 计算出梯度后,我们就可以得到一条垂直于该点切线的直线,我们就有一个二维数组H,用来填充这条直线上所有点
- H中出现频率最高的肯定就是圆心
- 对于得到的圆心中的每一个,计算那些边缘点到该圆心的距离,若某个距离很充分出现次数足够,就可以认为这是一个合格的圆
初识API
-
C++:
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 – 8比特单通道灰度图
- circles – 是一个向量,每个都是3元素的浮点数
.
- method – 唯一的方法是CV_HOUGH_GRADIENT
- dp – 如果dp=1 , Hough空间的叠加器就和输入图片的分辨率一致. 如果dp=2 , Hough空间叠加器就只有一半大小.
- minDist – 检测的圆心最小距离间隔。如果设置太小,一些旁边的圆可能就被错误的检测,而正确的就没检测出来。如果设置太大,可能就漏掉很多圆。
- param1 –它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半
- param2 –它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值。它越小的话,就可以检测到更多根本不存在的圆,而它越大的话,能通过检测的圆就更加接近完美的圆形了
- minRadius – 圆最小半径
- maxRadius – 圆最大半径
荷枪实弹
因为算法和直线检测类似,所以自己就不实现了
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
/** @function main */
int main(int argc, char** argv)
{
Mat src, src_gray;
/// Read the image
src = imread( argv[1], 1 );
if( !src.data )
{ return -1; }
/// Convert it to gray
cvtColor( src, src_gray, CV_BGR2GRAY );
/// Reduce the noise so we avoid false circle detection
GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 );
vector<Vec3f> circles;
/// Apply the Hough Transform to find the circles
HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 );
/// Draw the circles detected
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 center
circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 );
// circle outline
circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
/// Show your results
namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE );
imshow( "Hough Circle Transform Demo", src );
waitKey(0);
return 0;
}
举一反三
下面我来稍微讲解一下广义Hough变换
假如我们有一张模版函数
在模版图像中,我们有3种基本图形,我们也确定了一个中心,每种基本图形相对于中心都产生了一些偏移向量
仔细看下面的广义Hough变换图,每张图都对每一个基本图形运用了之前的偏移向量,再在一个二维Hough空间叠加
最右边的圆圈处二维叠加器最大,于是就找到原来的模版图像
再举个例子
左图,我们提取圆的偏移向量
然后,在测试图片中就能找到, 是不是很有趣