OpenCV标准霍夫直线检测详解
Posted OpenCV学堂
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV标准霍夫直线检测详解相关的知识,希望对你有一定的参考价值。
霍夫直线检测
对于图像来说可以从笛卡尔坐标系统转换到霍夫空间,对于一条直线来说
在笛卡尔坐标系统中表示一条直线有两个参数斜率k与截距b
在霍夫空间中表示一条直线也有两个参数到原点的距离d与角度theta
对于给定任意theta值,都有一个r与之对应,对于点x0=8, y0=6,在霍夫空间有如下的曲线:
当有很多点在霍夫空间的曲线相交于一点时候
就说明这些点具有相同的theta与r,即它们都属于同一条直线,而参数theta与r就是该直线在霍夫空间的直线参数方程。
OpenCV中标准霍夫直线检测源码部分:// 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]++;
}
}
// stage 2. find local maximums
findLocalMaximums( numrho, numangle, threshold, accum, _sort_buf );
// stage 3. sort the detected lines by accumulator value
std::sort(_sort_buf.begin(), _sort_buf.end(), hough_cmp_gt(accum));
// 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]);
}
}相关API使用
OpenCV中关于霍夫直线检测有两个API,一个被称为标准霍夫变换直线检测,另外一个叫霍夫直线检测。二者之间的区别在于,前者会直接输出theta与r,还有累加和,后者会直接输出相关线段的平面坐标。
void cv::HoughLines(
InputArray image, // 输入参数
OutputArray lines, // 输出结果vector<Vec2f>, vector<Vec3f>
double rho, // 距离步长d=1, 是指该直线到原点距离,对于屏幕坐标是左上角点
double theta, // 角度步长1°
int threshold, // 阈值,是指累加数目
double srn = 0, // 多尺度检测需要,默认为0
double stn = 0, // 多尺度检测需要,默认为0
double min_theta = 0, // 直线旋转角度
double max_theta = CV_PI // 直线旋转角度
)对输出的结果是Vec2f的话为(r, theta)如果是Vec3f的话为(r, theta, votes)
当r值大于零的时候表示直线在X轴下方有垂直距离
当r值小于零的时候表示直线在X轴上方有垂直距离首先对输入图像进行二值化
// 二值化
Mat dst, gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
imshow("binary", binary);标准霍夫直线检测代码如下
// 绘制直线
Point pt1, pt2;
for (size_t i = 0; i < lines.size(); i++)
{
float rho = lines[i][0]; // 距离
float theta = lines[i][1]; // 角度
float votes = lines[i][2]; // 累加
printf("rho %.2f, theta : %.2f, votes : %.2f \n", rho, theta, votes);
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000 * (-b));
pt1.y = cvRound(y0 + 1000 * (a));
pt2.x = cvRound(x0 - 1000 * (-b));
pt2.y = cvRound(y0 - 1000 * (a));
line(src, pt1, pt2, Scalar(0, 0, 255), 1, LINE_AA);
}
imshow("contours", src);对上述的代码解释,其中x0与y0是直线上的点,1000是表示对改点延长到直线上距离,上述代码计算公式很多人不理解,特手绘白纸一张如下:
使用霍夫直线变换
假设有如下图像:
通过标准霍夫直线变换实现如下直线分类与最大直线提取
左侧倾斜直线
右侧倾斜直线
水平或者垂直线
长度最大直线
代码实现如下
void hough_lines_demo(Mat &image, Mat &binary) {
// 标准霍夫直线检测
vector<Vec3f> lines;
HoughLines(binary, lines, 1, CV_PI / 180, 100, 0, 0);
// 绘制直线
Point pt1, pt2;
for (size_t i = 0; i < lines.size(); i++)
{
float rho = lines[i][0]; // 距离
float theta = lines[i][1]; // 角度
float votes = lines[i][2]; // 累加
printf("rho %.2f, theta : %.2f, votes : %.2f \n", rho, theta, votes);
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000 * (-b));
pt1.y = cvRound(y0 + 1000 * (a));
pt2.x = cvRound(x0 - 1000 * (-b));
pt2.y = cvRound(y0 - 1000 * (a));
int angle = round((theta / CV_PI) * 180);
printf("angle : %d\n", angle);
if (i == 0) {
line(image, pt1, pt2, Scalar(0, 255, 0), 1, LINE_AA);
putText(image, "max-line", Point((pt1.x + pt2.x) / 2, (pt1.y + pt2.y) / 2), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 2, 8);
continue;
}
if (rho > 0) { // 右倾
line(image, pt1, pt2, Scalar(0, 0, 255), 1, LINE_AA);
if (angle == 90) { // 水平线
line(image, pt1, pt2, Scalar(255, 255, 0), 1, LINE_AA);
}
if (angle <= 1) { // 垂直线
line(image, pt1, pt2, Scalar(0, 255, 255), 1, LINE_AA);
}
}
else { // 左倾
line(image, pt1, pt2, Scalar(255, 0, 0), 1, LINE_AA);
}
}
imshow("result", image);
}运行结果如下:
欢迎扫码加入【OpenCV研习社】
- 学习OpenCV+tensorflow开发技术
- 与更多伙伴相互交流、一起学习进步
- 每周一到每周五分享知识点学习(音频+文字+源码)
- 系统化学习知识点,从易到难、由浅入深
- 直接向老师提问、每天答疑辅导
推荐阅读
关注【OpenCV学堂】
长按或者扫码即可关注
以上是关于OpenCV标准霍夫直线检测详解的主要内容,如果未能解决你的问题,请参考以下文章
pyhton—opencv直线检测(HoughLines)找到最长的一条线
利用OpenCV的霍夫变换线检测函数HoughLines()得到直线的ρ和θ值后绘制直线的原理详解