原理:

image

       设已知一黑白图像上画了一条直线,要求出这条直线所在的位置。我们知道,直线的方程可以用y=k*x+b 来表示,其中k和b是参数,通过变换可以得到b=-kx+y。过某一点(x0,y0)的所有直线的参数都会满足方程y0=kx0+b,即点(x0,y0)在x-y图像上对应着一族直线,但是,点(x0,y0)在k-b图像上对应的是一条直线。我们举个例子说明解决前面那个问题的原理。设图像上的直线是y=x, 我们先取上面的三个点:A(0,0), B(1,1), C(22)。可以求出,过A点的直线的参数要满足方程b=0, 过B点的直线的参数要满足方程1=k+b, 过C点的直线的参数要满足方程2=2k+b, 这三个方程就对应着参数平面上的三条直线,而这三条直线会相交于一点(k=1,b=0)。 同理,原图像上直线y=x上的其它点(如(3,3),(4,4)等) 对应参数平面上的直线也会通过点(k=1,b=0)。这个性质就为我们解决问题提供了方法,就是把图像平面上的点对应到参数平面上的线,最后通过统计特性来解决问题。假如图像平面上有两条直线,那么最终在参数平面上就会看到两个峰值点,依此类推。

       简而言之,Hough变换思想为:在原始图像坐标系下的一个点对应了参数坐标系中的一条直线,同样参数坐标系的一条直线对应了原始坐标系下的一个点,然后,原始坐标系下呈现直线的所有点,它们的斜率和截距是相同的,所以它们在参数坐标系下对应于同一个点。这样在将原始坐标系下的各个点投影到参数坐标系下之后,看参数坐标系下有没有聚集点,这样的聚集点就对应了原始坐标系下的直线。

       在实际应用中,y=k*x+b形式的直线方程没有办法表示x=c形式的直线(这时候,直线的斜率为无穷大)。所以实际应用中,是采用参数方程p=x*cos(theta)+y*sin(theta)。这样,图像平面上的一个点就对应到参数p---theta平面上的一条曲线上,其它的还是一样。

image   

上图(a)所示为原始的图像空间中一个点(x0, y0);(b)所示为直角坐标系当中为过同一四条直线;(c)所示为这四条直线在极坐标参数空间可以表示为四个点

      为了检测出直角坐标X-Y中由点所构成的直线,可以将极坐标a-p量化成许多小格。根据直角坐标中每个点的坐标(x,y),在a = 0-180°内以小格的步长计算各个p值,所得值落在某个小格内,便使该小格的累加记数器加1。当直角坐标中全部的点都变换后,对小格进行检验,计数值最大的小格,其(a,p)值对应于直角坐标中所求直线。

  通过上述原理,可以分析一下函数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:定义检测图像中圆的方法。目前唯一实现的方法是HOUGH_GRADIENT;
  dp:累加器分辨率与图像分辨率的反比。由于图像分辨率是固定的,因此dp越大,累加器分辨率(单位图像中累加器的数量)越小,划分的小格越少,格子越大(格子越大,计数越多);当dp=1时,累加器分辨率等于图像分辨率,即一个像素有一个累加器;
  minDist:检测到的圆的圆心之间的最小距离。如果minDist太小,则可能导致检测到多个相邻的圆。如果minDist太大,则可能导致很多圆检测不到。
  param1:该函数里面调用了边缘检测Canny,而Canny里面需要用到两个阈值(这里我们用大阈值和小阈值来表示),param1就是大阈值,通过查找HoughCircles定义可知,小阈值等于param1的一半;
  param2:累加器阈值,即大于param2的累加器才被选中;
  minRadius:半径的最小值(以像素为单位);
  maxRadius:半径的最小值(以像素为单位);