简单户型图处理—20180606-20180623

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);//Canny
	canny_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)绑定标尺数值,建立标尺与数字的一一对应关系

猜你喜欢

转载自blog.csdn.net/qq_42517195/article/details/81037118