0 概要
本文主要介绍三部分内容:
1、霍夫直线检测;
2、直线聚类;
3、直线跟踪;
1 霍夫直线基本数学原理
1.1 直线描述
1.1.1 霍夫直线参数含义
霍夫直线参数位rho,theta。
其中,
rho代表图像原点至直线的距离;
theta代表直线的角度,垂直为0度,顺时针旋转逐渐增大,水平位90度。
theta的取值范围:大于等于0度, 小于180度。
1.1.2 数学方程表示直线
已知: rho,theta;
直线系数:a = cos(theta), b = sin(theta);
垂点坐标:x0 = a * rho, y0 = b * rho;
直线方程:x = x0 - bt, y = y0 + at;
1.2 直线运算
1.2.1 直线反侧变换
标准直线参数的theta范围位[0,PI),在直线之间进行运算时会用到theta在此范围外的值,例如将1度的直线变换为181度,或者将179度的直线变换为-1度,这种变换成为反侧变换,反侧变换前后的直线等效,为同一直线。
- 反侧变换一:
new_theta = old_theta - PI;
new_rho = - old_rho;
- 反侧变换二:
new_theta = old_theta + PI;
new_rho = - old_rho;
1.2.2 直线规范化操作
将直线参数的角度值控制在[0,PI)范围内。
while (center_theta > PI)
{
center_theta -= PI;
center_rho = - center_rho;
}
while (center_theta < 0)
{
center_theta += PI;
center_rho = - center_rho;
}
1.2.3 霍夫直线间求差
在霍夫直线聚类时,需要将直线参数看作二维点,在此计算二维点之间的距离。
设两直线参数为(rho1, theta1)、(rho2, theta2),求取绝对误差:
error_theta = abs(theta1-theta2);
if error_theta <= PI/2 时:
error_rho = abs(rho1 - rho2);
if error_theta > PI/2 时:
error_theta = PI - error_theta;
error_rho = abs(rho1 + rho2);
计算归一化直线误差(距离):
d0 = drho/Rho_max;
d1 = dtheta/(CV_PI*0.5);
error_cj = sqrtf(d0*d0 + d1*d1);
1.2.4 霍夫直线求和与均值
在霍夫直线聚类求取中心点时,需要计算多直线参数累加和、均值。
- 计算累加和:
当样本直线距离该聚类中心直线的角度差大于90度时,需要做反侧变换,伪代码描述过程如下。
sum_theta = 0;
sum_rho = 0;
this_cluster_num = 0
for every lines in this cluster center:
this_cluster_num ++;
# 直线角度距离大于90度,则做反侧变换
if (this_theta - center_theta) > PI/2:
this_theta = this_theta - PI;
this_rho = - this_rho;
else if (this_theta - center_theta) < - PI/2:
this_theta = this_theta + PI;
this_rho = - this_rho;
sum_theta += this_theta;
sum_rho += this_rho;
- 求取均值(中心点)
center_theta = sum_theta/this_cluster_num;
center_rho = sum_rho/this_cluster_num;
- 结果规范化操作
为了保持中心直线参数在多伦的聚类迭代运算时,始终保持在一定的范围内,需要对其进行常规化操作,将其范围控制在[0,PI)之间。
1.2.5 霍夫直线滤波
在直线跟踪时,为了保证目标直线的平滑行,需要加入滤波处理。
普通一阶低通滤波的方法: y = y_1 + k*(x - y_1);
霍夫直线滤波时需要考虑直线反侧变换,过程用伪代码表示:
# 偏差检测与反侧变换
error_theta = x_theta - y_theta;
if (error_theta > PI/2):
# 直线反侧变换
x_u_theta = x_theta - PI;
x_u_rho = - x_rho;
else if (error_theta < -PI/2):
# 直线反侧变换
x_u_theta = x_theta + PI;
x_u_rho = - x_rho;
else:
x_u_theta = x_theta;
x_u_rho = -x_rho;
# 滤波处理
y_line = y_line + k*(x_u_line - y_line);
2 霍夫直线检测函数
2.1 函数HoughLines()
void HoughLines(InputArray image, OutputArray lines,
double rho, double theta, int threshold,
double srn=0, double stn=0,
double min_theta = 0, double max_theta = CV_PI )
参数解释:
第一个参数:InputArray类型的image,输入图像,即源图像,需为8位的单通道二进制图像,可以将任意的源图载入进来后由函数修改成此格式后,再填在这里。
第二个参数:InputArray类型的lines,经过调用HoughLines函数后储存了霍夫线变换检测到线条的输出矢量。每一条线由具有两个元素的矢量表示,其中,是离坐标原点((0,0)(也就是图像的左上角)的距离。 是弧度线条旋转角度(0垂直线,π/2水平线)。
第三个参数:double类型的rho,以像素为单位的距离精度。另一种形容方式是直线搜索时的进步尺寸的单位半径。PS:Latex中/rho就表示 。
第四个参数:double类型的theta,以弧度为单位的角度精度。另一种形容方式是直线搜索时的进步尺寸的单位角度。
第五个参数:int类型的threshold,累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值。大于阈值threshold的线段才可以被检测通过并返回到结果中。
第六个参数:double类型的srn,有默认值0。对于多尺度的霍夫变换,这是第三个参数进步尺寸rho的除数距离。粗略的累加器进步尺寸直接是第三个参数rho,而精确的累加器进步尺寸为rho/srn。
第七个参数:double类型的stn,有默认值0,对于多尺度霍夫变换,srn表示第四个参数进步尺寸的单位角度theta的除数距离。且如果srn和stn同时为0,就表示使用经典的霍夫变换。否则,这两个参数应该都为正数。
第八个参数:double类型的 min_theta,对于标准和多尺度Hough变换,检查线条的最小角度。必须介于0和max_theta之间。
第九个参数:double类型的 max_theta, 对于标准和多尺度Hough变换,检查线条的最大角度。必须介于min_theta和CV_PI之间.
2.2 函数HoughLinesP()
void HoughLinesP(InputArray image, OutputArray lines,
double rho, double theta, int threshold,
double minLineLength=0, double maxLineGap=0 )
参数解释:
第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的单通道二进制图像,可以将任意的源图载入进来后由函数修改成此格式后,再填在这里。
第二个参数,InputArray类型的lines,经过调用HoughLinesP函数后后存储了检测到的线条的输出矢量,每一条线由具有四个元素的矢量(x_1,y_1, x_2, y_2) 表示,其中,(x_1, y_1)和(x_2, y_2) 是是每个检测到的线段的结束点。
第三个参数,double类型的rho,以像素为单位的距离精度。另一种形容方式是直线搜索时的进步尺寸的单位半径。
第四个参数,double类型的theta,以弧度为单位的角度精度。另一种形容方式是直线搜索时的进步尺寸的单位角度。
第五个参数,int类型的threshold,累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值。大于阈值threshold的线段才可以被检测通过并返回到结果中。
第六个参数,double类型的minLineLength,有默认值0,表示最低线段的长度,比这个设定参数短的线段就不能被显现出来。
第七个参数,double类型的maxLineGap,有默认值0,允许将同一行点与点之间连接起来的最大的距离。
2.3 函数使用说明
HoughLines检测到的直线参数是(rho, theta),表示一条直线的参数;不区分直线上的线段。HoughLinesP检测返回值是线段两端点的点坐标值,表示的是一条线段。
本文采用的是HoughLines函数,使用前需要做预处理:
image颜色通道分离;
红色引导线提取:(red - sat) > (blue + green)
3 直线聚类
直线聚类的算法流程
聚类中心数量cluster_center_num = 1;
while 聚类未完成:
for 聚类N次数:
聚类初始化工作;
随机分布聚类中心点:在数据样本集中随机选取cluster_center_num 个点,作为数据中心点;
while 本次聚类未达到收敛状态:
根据当前聚类中心值,计算每一个点归属于哪一个聚类中心;
根据归属关系,计算新的聚类中心值;
当新的聚类中心与上次聚类中心一致时,本次聚类达到收敛状态;
计算本次聚类完成后的样本点均方差,并记录;
选取N次聚类结果中,均方差最小的那一次数据,作为聚类结果。
若聚类均方差小于设定阈值,则聚类完成;否则,cluster_center_num ++,开启新的N轮聚类。
随机分布聚类中心点的方法:
(1)在取值空间中随机取值坐标点,产生cluster_center_num 个数据点;
(2)在数据样本集中随机选取cluster_center_num 个点,作为数据中心点;
如果样本点在空间中分布非常不均匀的情况下,方法(1)产生的数据中心点有些偏离数据较远,则很难达到较好的收敛状态,即某些聚类中心可能没有隶属样本点。
需要考虑的问题:
- 聚类的总类别个数不确定
因为事先不知道图形中存在多少真实的直线,所以要自适应寻找聚类的类别数,判断依据是聚类后的均方差是否足够小; - 霍夫直线参数误差计算时的特殊处理
(1) 角度处理
由霍夫直线参数物理含义可知,1度的直线与179度的直线,在斜率上仅仅差别2度。所以,
当两直线的误差error = | theta1 - theta2 |大于90度时,
其真实误差是| PI - error|。
(2) 距离处理
当两个直线的角度偏差计算经过折算处理时,其斜率计算也需要进行折算处理。
4 直线跟踪
直线跟踪的本质是动态跟踪直线参数,或者是实时寻找距离上次参考直线最近的直线,并不断迭代的过程。跟踪的本质原理,在连续的视频拍摄中,直线在视野中的位置是连续变化的,那么被跟踪直线的参数(或其反侧变换)应该是连续变化的,即前后误差较小。
直线跟踪算法的伪代码表示:
# 初始设定:
# 设定被追踪直线的参考参数(rho,theta)
set_track_line_param(rho, theta);
# 实时跟踪:
# 遍历所有直线参数,寻找最近的直线参数;
for every lines in image:
# 若最近直线与参考直线参数偏差小于阈值,则跟踪成功,参考直线参数 := 最近直线参数;
if (this_line - track_line) < line_error_sat:
track_succsess;
track_line = this_line;
# 否则,跟踪失败
else:
track_failure;