1、概述
2、分析
2.1、建立三角函数查找表
为了避免三角函数的反复计算,根据离散后的角度信息,提前计算出所需的三角函数值。
static void
createTrigTable( int numangle, double min_theta, double theta_step,
float irho, float *tabSin, float *tabCos )
{
float ang = static_cast<float>(min_theta);
for(int n = 0; n < numangle; ang += (float)theta_step, n++ )
{
tabSin[n] = (float)(sin((double)ang) * irho);
tabCos[n] = (float)(cos((double)ang) * irho);
}
}
2.2、 计算离散点数
根据极经和极角的步长,极经和极角的范围,计算离散点数。
int numangle = cvRound((max_theta - min_theta) / theta);
int numrho = cvRound(((max_rho - min_rho) + 1) / rho);
2.3、 填充累加器
计算图像中每个像素点的霍夫变换,其中极角 θ \theta θ按照离散化的点采样,计算极经值rho,并更新对应的累加器accum的值。
// stage 1. fill accumulator
for( i = 0; i < height; i++ )
for( j = 0; j < width; j++ )
{
if( image[i * step + j] != 0 )
for(int n = 0; n < numangle; n++ )
{
int r = cvRound( j * tabCos[n] + i * tabSin[n] );
r += (numrho - 1) / 2;
accum[(n+1) * (numrho+2) + r+1]++;
}
}
2.4、查找局部极大值
static void
findLocalMaximums( int numrho, int numangle, int threshold,
const int *accum, std::vector<int>& sort_buf )
{
for(int r = 0; r < numrho; r++ )
for(int n = 0; n < numangle; n++ )
{
int base = (n+1) * (numrho+2) + r+1;
if( accum[base] > threshold &&
accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&
accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] )
sort_buf.push_back(base);
}
}
2.5、 排序
对累加器内部的数据进行排序,由大到小进行排序。
// stage 3. sort the detected lines by accumulator value
std::sort(_sort_buf.begin(), _sort_buf.end(), hough_cmp_gt(accum));
2.6、输出直线
根据设定的最小直线数量和实际缓存的直线数量,求取最小的直线数。根据直线数从排过序的缓存中取最大的几组数据,并将这些数据转换成直线参数存储。
// stage 4. store the first min(total,linesMax) lines to the output buffer
linesMax = std::min(linesMax, (int)_sort_buf.size());
double scale = 1./(numrho+2);
lines.create(linesMax, 1, type);
Mat _lines = lines.getMat();
for( i = 0; i < linesMax; i++ )
{
LinePolar line;
int idx = _sort_buf[i];
int n = cvFloor(idx*scale) - 1;
int r = idx - (n+1)*(numrho+2) - 1;
line.rho = (r - (numrho - 1)*0.5f) * rho;
line.angle = static_cast<float>(min_theta) + n * theta;
if (type == CV_32FC2)
{
_lines.at<Vec2f>(i) = Vec2f(line.rho, line.angle);
}
else
{
CV_DbgAssert(type == CV_32FC3);
_lines.at<Vec3f>(i) = Vec3f(line.rho, line.angle, (float)accum[idx]);
}
}