第一部分:函数介绍
1、标准霍夫线变换
void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )
参数:
image:边缘检测的输出图像. 它应该是个灰度图 (但事实上是个二值化图)
lines:储存着检测到的直线的参数对 的容器
rho:参数极径 以像素值为单位的分辨率. 我们使用 1 像素.
theta:参数极角 以弧度为单位的分辨率. 我们使用 1度 (即CV_PI/180)
theta:要”检测” 一条直线所需最少的的曲线交点
srn and stn: 参数默认为0.
2、统计概率霍夫线变换
void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold,double minLineLength=0, double maxLineGap=0 )
参数:
image: 边缘检测的输出图像. 它应该是个灰度图 (但事实上是个二值化图) *
lines: 储存着检测到的直线的参数对 的容器,也就是线段两个端点的坐标
rho : 参数极径 以像素值为单位的分辨率. 我们使用 1 像素.
theta: 参数极角 以弧度为单位的分辨率. 我们使用 1度 (即CV_PI/180)
threshold: 要”检测” 一条直线所需最少的的曲线交点
minLinLength: 能组成一条直线的最少点的数量. 点数量不足的直线将被抛弃.线段的最小长度
maxLineGap:线段上最近两点之间的阈值
备注:
(1)霍夫线变换是一种用来寻找直线的方法.
(2)霍夫线变换之前, 首先要对图像进行边缘检测的处理,即霍夫线变换的直接输入只能是边缘二值图像.
第二部分:原理
上面的5和6是重点,笛卡尔坐标系中,同一条直线上的点,转到极坐标系下,会相交于一个点。
第三部分:代码实现
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
const char* filename = argc >= 2 ? argv[1] : "1.jpg";
Mat src = imread(filename,0);//1表示读取原图像,0表示将原图像转化为灰度图
printf("src.channels: %d\n",src.channels());
if(src.empty())
{
cout << "can not open " << filename << endl;
return -1;
}
Mat dst, cdst;
Canny(src, dst, 50, 200, 3);//用Canny算子对图像进行边缘检测
cvtColor(dst, cdst, CV_GRAY2BGR);
#if 0
vector<Vec2f> lines;
HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 );
for( size_t i = 0; i < lines.size(); i++ )
{
float rho = lines[i][0], theta = lines[i][1];
Point pt1, pt2;
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( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
}
#else
vector<Vec4i> lines;//储存着检测到的直线的参数对 (X1, Y1, X2, Y2) 的容器,也就是线段的两个端点
HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 );
//dst:边缘检测的输出图像. 它应该是个灰度图,作为我们的输入图像
//1:参数极径 r 以像素值为单位的分辨率. 我们使用 1 像素.
//CV_PI/180:参数极角 \theta 以弧度为单位的分辨率. 我们使用 1度 (即CV_PI/180)
//50:要”检测” 一条直线所需最少的的曲线交点
//50:能组成一条直线的最少点的数量. 点数量不足的直线将被抛弃.
//10:线段上最近两点之间的阈值,也就是能被认为在一条直线上的亮点的最大距离.
//通过画出检测到的直线来显示结果.
for( size_t i = 0; i < lines.size(); i++ )
{
Vec4i l = lines[i];//Vec4i 就是Vec,里面存放4个int
line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, CV_AA);
//要划的线所在的图像:cdst, 起点:Point(l[0], l[1]), 终点:Point(l[2], l[3]), 颜色:Scalar(0,0,255),
}
#endif
imshow("source", src);
imshow("detected lines", cdst);
waitKey();
return 0;//等待用户按键推出程序
}