前言
利用霍夫变换提取图像中的直线, 具体代码如下所示。霍夫变换的原理在此不多赘述,重点想讲述一下直线筛选的过程。
由于霍夫变换之后得到的直线数量很多,为了得到符合条件的直线,我们有必要对直线进行一定的筛选。在 draw_lane()函数种对直线进行比较精确地筛选,首先根据车道线的淘汰画面中较为平行的直线,接着设定 rho 和 angle 的阈值,淘汰重复的直线,使得每条车道仅有一条直线保留。
应用
话不多说直接上代码
输入
传入的参数为cv::Mat img 和阈值 threshold
在我的车道线检测项目中传入边缘提取后的二值图像
具体代码
std::vector<int> hough_line_detect(cv::Mat img, int threshold)
{
int row, col;
int i, k;
//参数空间的参数极角angle(角度),极径p;
int angle, p;
//累加器
int** socboard;
int* buf;
int w, h;
w = img.cols;
h = img.rows;
int Size;
int offset;
std::vector<int> lines;
//申请累加器空间并初始化
Size = w * w + h * h;
Size = 2 * sqrt(Size) + 100;
offset = Size / 2;
cout << "offset: " << offset << endl;
socboard = (int**)malloc(Size * sizeof(int*));
if (!socboard)
{
printf("mem err\n");
return lines;
}
for (i = 0; i < Size; i++)
{
socboard[i] = (int*)malloc(181 * sizeof(int));
if (socboard[i] == NULL)
{
printf("buf err\n");
return lines;
}
memset(socboard[i], 0, 181 * sizeof(int));
}
//遍历图像并投票
int src_data;
p = 0;
for (row = 0; row < img.rows; row++)
{
for (col = 0; col < img.cols; col++)
{
//获取像素点
src_data = img.at<uchar>(row, col);
if (src_data == 255)
{
for (angle = 0; angle < 181; angle++)
{
p = col * cos(angle * PI / 180.0) + row * sin(angle * PI /180.0) + offset;
//错误处理
if (p < 0)
{
printf("at (%d,%d),angle:%d,p:%d\n", col, row, angle, p);
printf("warrning!");
printf("size:%d\n", Size / 2);
continue;
}
//投票计分
socboard[p][angle]++;
}
}
}
}
//遍历计分板,选出符合阈值条件的直线
//int count = 0;
int Max = 0;
int kp, kt, r;
kp = 0;
kt = 0;
for (i = 0; i < Size; i++)//p
{
for (k = 0; k < 181; k++)//角度0-180
{
if (socboard[i][k] > Max)
{
Max = socboard[i][k];
kp = i - offset;
kt = k;
}
if (socboard[i][k] >= threshold)
{
r = i - offset;
lines.push_back(i - Size / 2);//rho
lines.push_back(k);//angle
}
}
}
//释放资源
for (int e = 0; e < Size; e++)
{
free(socboard[e]);
}
free(socboard);
return lines;
}
效果
【注】threshold需要自己好好调一调
附录
- 查看完整车道线检测项目代码
- 查看完整车道线检测项目思路