单向准连通的表格线检测 opencv
来源:互联网 发布:工资核算软件 编辑:程序博客网 时间:2024/06/06 02:20
直线检测算法
直线检测算法中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 )
HoughLines(),可以返回检测的直线坐标对,通过坐标对画出直线。
HoughLinesP(),在HoughLines的基础上加入了概率,并且可以通过设置判断直线间的距离将相近的多条直线合成一条直线。
虽然Hough检测不受断线的影响,但Hough变换检测的鲁棒性不强,如果图像中出现下列几种情况则检测效果会很差:
1.直线过粗(会出现检测出多条直线的情况,虽然HoughLineP可以一定程度解决这个问题,但是阈值的设置与输入的图片十分相关)
2.直线有角度变换(是指拍摄后无校正的图像,直线会出现扭曲的情况)
3.除了目标直线外,有干扰直线
单向准连通的表格检测直线算法
《单向准连通的表格检测直线算法》一文中,提出了一种检测算法。用这种算法检测直线可以很好的解决以下问题:
1.有断线的直线
2.有角度倾斜的直线
3.过粗的直线
并且通过阈值的设置,可以大体排除干扰直线。
基于Opencv的代码
以下图为例,输入二值化后的图像,需要检测出的目标区域为图中标注出的红色区域,检测的直线为区域中两条黑直线。最终实现目标为分割出两
直线间区域。
//遍历每一列的图像灰度值,查找每一行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;//向下移动一格,判断接下来是不是黑色elsebreak;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;//检测uptmp_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;//检测downtmp_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){ //下方线段不为0if ((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){ //上方线段不为0if ((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){ //均不为0if ((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分割并进行图像校正后效果如图。
0 0
- 单向准连通的表格线检测 opencv
- OpenCV: 图像连通域检测的递归算法
- OpenCV-检测并提取表格
- POJ 2762 单向的连通图
- 【离散数学】单向连通和弱连通的区别
- OpenCv的连通域操作
- OpenCV编程案例:使用轮廓函数检测连通区域
- opencv结构分析与形状识别-轮廓检测和填充(连通区域-边缘与整个图像的目标)
- cvCanny检测边缘,连通重要的非连通区域
- 如何编程求有向图的单向连通分支
- opencv vs 下 车道线的检测
- 网络管理之检测网络的连通
- opencv自动光学检测、目标分割和检测(连通区域和findContours)
- opencv 连通区域的最小外接矩形
- OpenCV求得图像的最大连通域
- OpenCV找图像的连通域
- opencv 连通域需要的函数解析
- opencv车道线检测
- LeetCode-M-Unique Binary Search Trees II
- Python
- Android自动关机
- 集合框架-ArrayList存储字符串、自定义对象并遍历泛型版
- poj 1852 Ants 发现问题,解决问题
- 单向准连通的表格线检测 opencv
- 523. Continuous Subarray Sum
- zoom元素用来设置缩放比例的
- FALSE/TRUE与false/true的区别
- 把排序数组转换为高度最小的二叉搜索树
- jquery\json\ajax
- c++中输出小数格式控制(c++中怎么控制浮点型小数点后输出的位数)
- ubuntu live555测试
- pb实现增删改查