C实现hough变换拟合直线

原理:
对于平面上的一个点(x1,y1),满足方程:y1=mx1+b,经过点(x1,y1)的直线有无数条,只要其满足刚才的直线方程。然而,可以把直线方程变形一下,b=-x1 m+y1,在考虑由点(m,b)组成的面,这里叫为参数空间,由(-x1, y1)确定一条直线。同样,由另外一个点(x2,y2)可以确定参数空间的一条直线,b2= -x2m+y2。如果这条直线不平行于b=-x1 m+y1,那么一定与其相交于某点(m’, b’),则可以看出m’、b’分别是由(x1,y2)和(x2,y2)组成的直线的斜率和截距。事实上,所有在此直线上的点在参数空间上都有一条直线,并且这些直线均相交于(m’, b’)。如下图所示,左边为图像空间,右边为参数空间,图像中的一个点,在参数空间对应一条直线,两个点就对应两条直线,在参数空间中的两条直线相交于(m,b)点就对应图像空间中直线的斜率和截距。
C实现hough变换拟合直线_第1张图片

算法实现思想:对图像空间中的所有点将其对应至参数空间,然后找出参数空间中的直线相交最多的点作为图像空间中直线的参数,对应于在图像空间中,这条直线上的点最多。但是不能采用斜率和截距作为在实际中实现霍夫变换,因为在直线垂直于x轴时,直线斜率为无穷大,无论算法的时间和空间复杂度都不允许。
所以,需要换一种直线的参数表示形式,采用坐标原点到直线的距离和直线与x轴的夹角可以唯一表示一条直线。公式如下:
ρ=xcosθ+ysinθ
上式中,(x,y)为直线上某点的坐标。ρ为坐标原点到直线的距离,θ为直线与x轴的夹角。
对于某一图像,x、y的最大值分辨为图像宽、高的最大值,ρ的最大值为图像尺寸的对角线,最小值是个负值,也就是,θ为180度时的值(对图像坐标来说,x、y没有负值)。如下图:
C实现hough变换拟合直线_第2张图片

上面的公式推导如下图:
C实现hough变换拟合直线_第3张图片
不想画,手绘了,这样简单些。
参考冈萨雷斯《数字图像处理第三版》。
代码实现:

typedef struct hline_t
{
  int p;
  int theta;
}hline;

typedef struct _point_t
{
    int x;
    int y;
}_point;

#ifndef max
#define max(a,b)            (((a) > (b)) ? (a) : (b))
#endif
#define PI 3.14159265

void hough_line(_point *points, int count, int width, int height, hline* line)
{
    int i, j;
    int p;
    int theta;
    int maxCnt = 0;
    int maxP, maxTheta;
    int maxd;
    int mind;
    int** m;
    int* buf;

    maxd = max(width, height);
    mind = maxd;
    maxd = maxd + (maxd >> 1);
    maxd += mind;
    m = (int**)malloc(181*sizeof(int*));
    if (!m)
        return;
    buf = (int*)malloc(181*maxd*sizeof(int));
    if(!buf)
    {   
        free(m);
        return;
    }
    memset(buf, 0, 181*maxd*sizeof(int));
    for (i = 0; i < 181; i++)
    {
        m[i] = &buf[i*maxd];
    }

    for(i = 0; i < count; i++)
    {   
        for(theta=0; theta < 181; theta++)
        {
            p = points[i].x * cos(theta * PI / 180.0) + points[i].y * sin(theta * PI / 180.0) + mind;
            m[theta][p]++;
            assert(p < maxd + mind);
        }
    }
    for (i = 0; i < 181; i++) {
        for (j = 0; j < maxd; j++) {
            if (m[i][j] > maxCnt) {
                maxCnt = m[i][j];
                maxTheta = i;
                maxP = j;
            }
        }
    }
    line->p = maxP - mind;
    line->theta = maxTheta;
    free(buf);
    free(m);
}

测试效果:
C实现hough变换拟合直线_第4张图片
绿色为绘制的拟合结果,红色部分为原始直线。

优化上的考虑:
可以将正弦、余弦值扩大1024倍做成表格查询,得到的结果右移10位即可。

你可能感兴趣的:(图像处理)