直线检测算法
直线检测算法中Hough算法是比较常用的一种, 在opencv中Hough变换有多个函数。
void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )
void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength=0, double maxLineGap=0 )
//遍历每一列的图像灰度值,查找每一行255的值
for (int col = 20; col < width - 20; ++col)
{
for (int row = 20; row < height - 20; ++row)
{
cnt_segment_line = 0;//记录纵向线段的个数
perPixelValue = binImg.at<uchar>(row, col); //at坐标是相反的
if (perPixelValue != 0){
int i = 1;
int j = 1;
}
perpendicular_line_len = 0;//每次垂直线段长度初始化赋值
detect_per_flag = 0;
tmp_beg_record_yiu = row; //设置初始y坐标
if (row == 2210&&col==49){
int x = 4;
}
if (perPixelValue == 255){
perpendicular_line_len = 1;
while (perPixelValue == 255){
if (row + 1 <= height - 20)
row = row + 1;//向下移动一格,判断接下来是不是黑色
else
break;
perPixelValue = binImg.at<uchar>(row, col); //at坐标是相反的
if (perPixelValue == 255){
perpendicular_line_len++;
tmp_beg_record_yid = row;
}
if (perpendicular_line_len <= 30){// 小于一个大阈值检测到可能是线段
detect_per_flag = 1;
}
else{ //过长则舍去
detect_per_flag = 0;
break;
}
}
}
if (detect_per_flag == 1){ //大于一个小阈值,可能是起始线段;且如果是直线上的点,则将值设置为0//开始线段的检测
if (perpendicular_line_len >= 0){
//record_detect_array[cnt_perpendicular_line][cnt_line_segment][0] = col;
//record_detect_array[cnt_perpendicular_line][cnt_line_segment][1] = tmp_beg_record_yiu;
//record_detect_array[cnt_perpendicular_line][cnt_line_segment][2] = tmp_beg_record_yid;
//cnt_line_segment++;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][0] = col;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][1] = tmp_beg_record_yiu;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][2] = tmp_beg_record_yid;
cnt_segment_line++;
/*for (int tmp_hue_change = tmp_beg_record_yiu; tmp_hue_change <= tmp_beg_record_yid; tmp_hue_change++){
binImg.at<uchar>(row, col) = 200;
}*/
each_horizontal_len = 1;//线段长度计数
/开始向右检测
tmp_base_x = col + 1;
tmp_base_y = (tmp_beg_record_yiu + tmp_beg_record_yid) / 2;
startdetect:
perpendicular_up_line_len = 0;//检测up
tmp_up_yiu = 0;
tmp_up_yid = 0;
detect_up_line(tmp_base_x, tmp_base_y, binImg, perpendicular_up_line_len, tmp_up_yiu, tmp_up_yid);
perpendicular_down_line_len = 0;//检测down
tmp_down_yiu = height;
tmp_down_yid = height;
detect_down_line(tmp_base_x, tmp_base_y, binImg, perpendicular_down_line_len, tmp_down_yiu, tmp_down_yid, height);
if (perpendicular_down_line_len == 0 && perpendicular_up_line_len == 0){
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
goto end;
}
if (perpendicular_down_line_len != 0 && perpendicular_up_line_len == 0){ //下方线段不为0
if ((tmp_down_yiu - tmp_base_y) > Q){
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
goto end;
}
else if ((tmp_down_yiu - tmp_base_y <= Q) && (tmp_down_yid - tmp_down_yiu <= P)){
each_horizontal_len++;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][0] = tmp_base_x;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][1] = tmp_down_yiu;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][2] = tmp_down_yid;
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
cnt_segment_line++;
/*for (int tmp_hue_change = tmp_down_yiu; tmp_hue_change <= tmp_down_yid; tmp_hue_change++){
binImg.at<uchar>(tmp_hue_change, tmp_base_x) = 200;
}*/
tmp_base_x = tmp_base_x + 1;
tmp_base_y = (tmp_down_yiu + tmp_down_yid) / 2;
goto startdetect;
}
else if ((tmp_down_yiu - tmp_base_y <= Q) && (tmp_down_yid - tmp_down_yiu > P)){
each_horizontal_len++;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][0] = tmp_base_x;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][1] = record_detect_array[cnt_perpendicular_line][cnt_segment_line-1][1];
record_detect_array[cnt_perpendicular_line][cnt_segment_line][2] = record_detect_array[cnt_perpendicular_line][cnt_segment_line-1][2];
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
cnt_segment_line++;
/*for (int tmp_hue_change = record_detect_array[cnt_perpendicular_line][1][1]; tmp_hue_change <= record_detect_array[cnt_perpendicular_line][1][2]; tmp_hue_change++){
binImg.at<uchar>(tmp_hue_change, tmp_base_x) = 200;
}*/
tmp_base_x = tmp_base_x + 1;
goto startdetect;
}
}
if (perpendicular_up_line_len != 0 && perpendicular_down_line_len == 0){ //上方线段不为0
if ((tmp_base_y - tmp_up_yid) > Q){
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
goto end;
}
else if ((tmp_base_y - tmp_up_yid <= Q) && (tmp_up_yid - tmp_up_yiu <= P)){
each_horizontal_len++;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][0] = tmp_base_x;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][1] = tmp_up_yiu;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][2] = tmp_up_yid;
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
cnt_segment_line++;
/*for (int tmp_hue_change = tmp_up_yiu; tmp_hue_change <= tmp_up_yid; tmp_hue_change++){
binImg.at<uchar>(tmp_hue_change, tmp_base_x) = 200;
}*/
tmp_base_x = tmp_base_x + 1;
tmp_base_y = (tmp_up_yiu + tmp_up_yid) / 2;
goto startdetect;
}
else if ((tmp_base_y - tmp_up_yid <= Q) && (tmp_up_yid - tmp_up_yiu > P)){
each_horizontal_len++;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][0] = tmp_base_x;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][1] = record_detect_array[cnt_perpendicular_line][cnt_segment_line - 1][1];
record_detect_array[cnt_perpendicular_line][cnt_segment_line][2] = record_detect_array[cnt_perpendicular_line][cnt_segment_line - 1][2];
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
cnt_segment_line++;
/*for (int tmp_hue_change = record_detect_array[cnt_perpendicular_line][1][1]; tmp_hue_change <= record_detect_array[cnt_perpendicular_line][1][2]; tmp_hue_change++){
binImg.at<uchar>(tmp_hue_change, tmp_base_x) = 200;
}*/
tmp_base_x = tmp_base_x + 1;
goto startdetect;
}
}
if (perpendicular_down_line_len != 0 && perpendicular_up_line_len != 0){ //均不为0
if ((tmp_down_yiu - tmp_base_y > Q) && (tmp_base_y - tmp_up_yid > Q)){
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
goto end;
}
else if ((tmp_down_yiu - tmp_base_y > Q) && (tmp_base_y - tmp_up_yid <= Q)){//下方离太远,上方正常
if ((tmp_base_y - tmp_up_yid <= Q) && (tmp_up_yid - tmp_up_yiu <= P)){
each_horizontal_len++;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][0] = tmp_base_x;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][1] = tmp_up_yiu;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][2] = tmp_up_yid;
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
cnt_segment_line++;
/*for (int tmp_hue_change = tmp_up_yiu; tmp_hue_change <= tmp_up_yid; tmp_hue_change++){
binImg.at<uchar>(tmp_hue_change, tmp_base_x) = 200;
}*/
tmp_base_x = tmp_base_x + 1;
tmp_base_y = (tmp_up_yiu + tmp_up_yid) / 2;
goto startdetect;
}
else if ((tmp_base_y - tmp_up_yid <= Q) && (tmp_up_yid - tmp_up_yiu > P)){
each_horizontal_len++;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][0] = tmp_base_x;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][1] = record_detect_array[cnt_perpendicular_line][cnt_segment_line - 1][1];
record_detect_array[cnt_perpendicular_line][cnt_segment_line][2] = record_detect_array[cnt_perpendicular_line][cnt_segment_line - 1][2];
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
cnt_segment_line++;
/*for (int tmp_hue_change = record_detect_array[cnt_perpendicular_line][1][1]; tmp_hue_change <= record_detect_array[cnt_perpendicular_line][1][2]; tmp_hue_change++){
binImg.at<uchar>(tmp_hue_change, tmp_base_x) = 200;
}*/
tmp_base_x = tmp_base_x + 1;
goto startdetect;
}
}
else if ((tmp_down_yiu - tmp_base_y <= Q) && (tmp_base_y - tmp_up_yid > Q)){//上方离太远,下方正常
if ((tmp_down_yiu - tmp_base_y <= Q) && (tmp_down_yid - tmp_down_yiu <= P)){
each_horizontal_len++;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][0] = tmp_base_x;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][1] = tmp_down_yiu;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][2] = tmp_down_yid;
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
cnt_segment_line++;
/*for (int tmp_hue_change = tmp_down_yiu; tmp_hue_change <= tmp_down_yid; tmp_hue_change++){
binImg.at<uchar>(tmp_hue_change, tmp_base_x) = 200;
}*/
tmp_base_x = tmp_base_x + 1;
tmp_base_y = (tmp_down_yiu + tmp_down_yid) / 2;
goto startdetect;
}
else if ((tmp_down_yiu - tmp_base_y <= Q) && (tmp_down_yid - tmp_down_yiu > P)){
each_horizontal_len++;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][0] = tmp_base_x;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][1] = record_detect_array[cnt_perpendicular_line][cnt_segment_line - 1][1];
record_detect_array[cnt_perpendicular_line][cnt_segment_line][2] = record_detect_array[cnt_perpendicular_line][cnt_segment_line - 1][2];
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
cnt_segment_line++;
/*for (int tmp_hue_change = record_detect_array[cnt_perpendicular_line][1][1]; tmp_hue_change <= record_detect_array[cnt_perpendicular_line][1][2]; tmp_hue_change++){
binImg.at<uchar>(tmp_hue_change, tmp_base_x) = 200;
}*/
tmp_base_x = tmp_base_x + 1;
goto startdetect;
}
}
else if (((tmp_down_yiu - tmp_base_y <= Q) && (tmp_down_yid - tmp_down_yiu > P)) || ((tmp_base_y - tmp_up_yid <= Q) && (tmp_up_yid - tmp_up_yiu > P))){
each_horizontal_len++;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][0] = tmp_base_x;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][1] = record_detect_array[cnt_perpendicular_line][cnt_segment_line - 1][1];
record_detect_array[cnt_perpendicular_line][cnt_segment_line][2] = record_detect_array[cnt_perpendicular_line][cnt_segment_line - 1][2];
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
cnt_segment_line++;
/*for (int tmp_hue_change = record_detect_array[cnt_perpendicular_line][1][1]; tmp_hue_change <= record_detect_array[cnt_perpendicular_line][1][2]; tmp_hue_change++){
binImg.at<uchar>(tmp_hue_change, tmp_base_x) = 200;
}*/
tmp_base_x = tmp_base_x + 1;
goto startdetect;
}
else if (((tmp_down_yiu - tmp_base_y <= Q) && (tmp_down_yid - tmp_down_yiu <= P)) && ((tmp_base_y - tmp_up_yid <= Q) && (tmp_up_yid - tmp_up_yiu <= P))){
if (tmp_down_yid - tmp_down_yiu + tmp_up_yid - tmp_up_yiu <= P){
each_horizontal_len++;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][0] = tmp_base_x;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][1] = tmp_up_yiu;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][2] = tmp_down_yid;
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
cnt_segment_line++;
for (int tmp_hue_change = tmp_up_yiu; tmp_hue_change <= tmp_down_yid; tmp_hue_change++){
binImg.at<uchar>(tmp_hue_change, tmp_base_x) = 200;
}
tmp_base_x = tmp_base_x + 1;
tmp_base_y = (tmp_up_yiu + tmp_down_yid) / 2;
goto startdetect;
}
else if (tmp_down_yid - tmp_down_yiu + tmp_up_yid - tmp_up_yiu > P){
each_horizontal_len++;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][0] = tmp_base_x;
record_detect_array[cnt_perpendicular_line][cnt_segment_line][1] = record_detect_array[cnt_perpendicular_line][cnt_segment_line - 1][1];
record_detect_array[cnt_perpendicular_line][cnt_segment_line][2] = record_detect_array[cnt_perpendicular_line][cnt_segment_line - 1][2];
detect_each_horizontal_len[cnt_perpendicular_line] = each_horizontal_len;
cnt_segment_line++;
/*for (int tmp_hue_change = record_detect_array[cnt_perpendicular_line][1][1]; tmp_hue_change <= record_detect_array[cnt_perpendicular_line][1][2]; tmp_hue_change++){
binImg.at<uchar>(tmp_hue_change, tmp_base_x) = 200;
}*/
tmp_base_x = tmp_base_x + 1;
goto startdetect;
}
}
}
}
detect_per_flag = 0;
end:
if (each_horizontal_len > 1500){//如果足够长,阈值
cnt_perpendicular_line++;
}
else{ //清空
for (int cnt_out = 0; cnt_out < each_horizontal_len; cnt_out++){
for (int cnt_in = 0; cnt_in < 3; cnt_in++){
record_detect_array[cnt_perpendicular_line][cnt_out][cnt_in] = 0;
}
}
detect_each_horizontal_len[cnt_perpendicular_line] = 0;
}
}
}
}
实验效果
虽然代码中用了C++中不建议使用的goto语句,但检测效果鲁棒性相对Hough变换要强。加上Rect分割并进行图像校正后效果如图。