直线检测算法

   直线检测算法中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分割并进行图像校正后效果如图。

opencv识别电子钟表上的数字_直线提取