20180606-20180623
1、预处理
针对简单无背景背景图,
(1)阈值分割 wall_thresh(Mat &src)
(2)去标尺 ReturnImgWithoutRuler(Mat& image1, Mat& imgWithoutR)
(3)腐蚀膨胀,dilate_erode(Mat&src)
(4)遍历找到行列边界
2、识别门窗的位置
(5)对原图进行LSD直线提取
Mat wall_2 = image.clone();Ptr<LineSegmentDetector> ls = createLineSegmentDetector(LSD_REFINE_STD, 1, 0.6, 2.0, 10, 0, 0.7, 1024);vector<Vec4i> lines_std;ls->detect(wall_2, lines_std);
(6)通过腐蚀膨胀后的墙体图对提取出来的直线进行掩膜处理
(7)用掩膜图过滤提取的直线,保留起点和终点都在墙体内(包含门窗)的直线
(8)利用墙体二值化的图像膨胀一圈作为掩膜得到门窗线
(9)利用sobel算子锐化门窗线
Mat image_Nd_Sobel;Mat grad_x, grad_y;Mat grad;Mat abs_grad_x, abs_grad_y;Sobel(image_Nd, grad_y, CV_16S, 0, 1, 3, 1, 0, BORDER_DEFAULT);Sobel(image_Nd, grad_x, CV_16S, 1, 0, 3, 1, 0, BORDER_DEFAULT);convertScaleAbs(grad_x, abs_grad_x);convertScaleAbs(grad_y, abs_grad_y);addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
(10)将门窗线进行膨胀腐蚀,然后OSTU二值化分割背景和前景,得到墙体所在位置
(11)找到外轮廓,
findContours(image_out, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
计算每个轮廓的最小外接矩形,minAreaRect(Mat(contours[i]))
(12)输出矩形短边中心点,作为门窗两点坐标
(13)将门窗点位作为先验知识,放入image_out_dilate,墙体二值图进行验证
两端点开始,沿垂直于门窗线的位置开始搜索同墙体区域边界的角点
设置搜索阈值20像素,没有搜到两个端点则不改变原点位
若两端都搜索到,则以较短处的中点作为结果输出
比较纠正结果与原点位差距,小于2个像素则不更改
3、处理墙体(旧-基于边缘检测)
(14)canny边缘检测,Canny(wall_all, cannyb, 3, 9, 3)
(15)手动写模板对边角进行校正,canny_fix(Mat&src)
(16)灰度图像矢量化,起点终点都为灰度断点,
vectorize(Mat&src, vector <Vec4i> &lines_x, vector <Vec4i> &lines_y, vector<Vec4i>&lines)
(17)画出单通道矢量化的直线
(18)画三通道矢量化直线,便于后续可视化表示墙体线段
Mat background12(image.rows, image.cols, CV_8UC3, Scalar(255, 255, 255));draw_Lines(background12, lines_x, Scalar(0, 0, 0));//0表示黑色墙外线draw_Lines(background12, lines_y, Scalar(0, 0, 0));//0表示黑色墙外线
(19)检测墙体中线,
wall_skeleton(Mat&mask,vector<Vec4i>&lines_x,vector<Vec4i>&lines_y,vector<Vec4i>&walls_x,vector<Vec4i>&walls_y)
(20)先把x、y方向上的门窗线段放到墙体线段容器中方便一起优化
(21)矢量化直线的校正优化
//第一步优化:合并基本相同的线段(方向相同,距离为0,且有重复部分) lines_single(image, wall_lines_x);//合并基本相同的线段(方向相同,距离为0,且有重复部分)lines_single(image, wall_lines_y);//合并基本相同的线段(方向相同,距离为0,且有重复部分)//第二步优化:平行且距离相近的两条直线,按照所在水平(垂直)位置所有直线的总长度大小进行校正lines_fix(wall_lines_x, dis_thresh);lines_fix(wall_lines_y, dis_thresh);//第三步优化:合并基本相同的线段(方向相同,距离为0,且有重复部分)lines_single(image, wall_lines_x);lines_single(image, wall_lines_y);//第四步优化:去除较短直线并放入wall_lines中wall_lines.clear();lines_filter(wall_lines_x, wall_lines, length_thresh);lines_filter(wall_lines_y, wall_lines, length_thresh);//第五步优化:延长直线两端lines_merge(wall_lines, merge_thresh);//延长直线两端//第六步优化:搜索交点作为直线端点,重新矢量化线段lines_split(image, wall_lines);draw_Lines(background12, wall_lines, Scalar(0, 0, 255));
(22)特殊矢量化,起点终点包含十字型或丁字型节点,用于区分承重墙和非承重墙
sp_vectorize(Mat&src, Mat&mask, vector<Vec6i>&lines, int gray, int check)
最终结果如上。
4、墙体处理(新-基于像素,更准确)
(23)去标尺
ReturnImgWithoutRuler(image, ImageWithoutR)
(24)二值化
threshold(ImageWithoutR, BinaryWithoutR, 210, 255, THRESH_BINARY_INV);
(25)腐蚀膨胀
int g_nStructElementSize = 2;Mat element = getStructuringElement(MORPH_RECT,Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1),Point(g_nStructElementSize, g_nStructElementSize));erode(BinaryWithoutR, BinaryWithoutR, element);dilate(BinaryWithoutR, BinaryWithoutR, element);
(26)边缘检测及校正
Canny(BinaryWithoutR, cannyWithoutR, 3, 9, 3);//Cannycanny_fix(cannyWithoutR);
(27)矢量化,vectorize(cannyb, lines_x, lines_y, lines);
(28)找到xy方向外轮廓
Mat imageOutContoursX(image.rows, image.cols, CV_8UC1, Scalar(255));FindOutContours(lines_x, 1, ImgSize, ImageWithoutR, imageOutContoursX); //1 for 水平方向Mat imageOutContoursY(image.rows, image.cols, CV_8UC1, Scalar(255));FindOutContours(lines_y, 0, ImgSize, ImageWithoutR, imageOutContoursY); //0 for 竖直方向
(29)腐蚀膨胀去噪
(30)矢量化,vectorize_xy(Mat&src, vector <Vec4i> &lines, int IsHor)
(31)找墙体中线(根据找出的轮廓线,圈矩形逐像素找正确的边界然后,算中线),去除重复并存储
NeighborRectX(vector<Vec4i> lines, int index, vector<Vec6i>& MediumLines)
(32)搜索交点作为直线端点,重新矢量化中线
lines_split_new(backgroundMediumLines, MediumLines);
(33)特殊矢量化,区分承重墙与非承重墙
sp_vectorize(Mat&src, Mat&mask, vector<Vec6i>&lines, int gray, int check)
(34)根据标尺绑定中线真实长度(未实现)。
5、识别门窗(新-能识别门和窗的位置及种类)
//检测门窗中线vector<Vec6i>win_door_temp;vector<Vec6i>win_door_mid;findWinDoorMidL(wall_all, walls, win_door_temp);lines_filter6(win_door_temp, win_door_mid, 15);//伸出门窗分类vector<Vec6i>win_door_out_sort_temp;windoor_out_sort(wall_th_windoor, win_door_mid, win_door_out_sort_temp);//查找未伸出门窗vector<Vec6i>win_door_in_sort_temp;find_windoor_in(wall_th_windoor, win_door_mid, win_door_in_sort_temp);vector<Vec6i>win_door_out_sort;vector<Vec6i>win_door_in_sort_temp2;lines_minus(win_door_out_sort_temp, win_door_in_sort_temp, win_door_out_sort);lines_minus(win_door_mid, win_door_out_sort, win_door_in_sort_temp2);//未伸出门窗分类vector<Vec6i>win_door_in_sort;windoor_in_sort(wall_th_windoor, win_door_in_sort_temp2, win_door_in_sort);vector<Vec6i>win_door_sort;for (int i = 0; i < win_door_out_sort.size(); i++){win_door_sort.push_back(win_door_out_sort[i]);}for (int j = 0; j < win_door_in_sort.size(); j++){win_door_sort.push_back(win_door_in_sort[j]);}
(35)先找到门窗中线,墙体中线 - 墙体腐蚀膨胀图得。
(36)找到飘窗、门、正常窗等的结构特征进行识别。
6、处理标尺,将标尺与数值绑定
(37)提取标尺
(38)将数字提取出来,然后调用baiduOCR,用python代码进行文字识别
(39)将标尺提取出来,标尺分段并标记
(40)绑定标尺数值,建立标尺与数字的一一对应关系