我的计划是从纸上绘制的平面图中提取信息。我已经设法检测到70-80%的拉门:
现在我想从墙上创建一个数据模型。我已经设法提取它们,你可以在这里看到:
从那我创建了轮廓:
我现在的想法是从该图像中获取线条的交叉点并从中创建数据模型。但是,如果我使用houghlines算法,我会得到这样的结果:
有人对如何获得交叉点或甚至另一个想法如何获得模型有不同的想法?会很好。
PS:我正在使用javacv。但是opencv中的算法也可以正常,因为我可以翻译它。
答案 0 :(得分:4)
首先,您还可以使用线段检测器来检测线条: http://www.ipol.im/pub/art/2012/gjmr-lsd/
如果我理解正确,问题在于你为每条“真实”线路获得了一些不同的短线。您可以获取“短线”的所有端点,并使用fitLine()逼近与之交叉的线: http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=fitline#fitline
答案 1 :(得分:1)
尝试将Hough变换图像或原始轮廓图像中的线条扩展1个像素。您可以通过使用2或3的线条粗线绘制更大的线条(如果您使用霍夫变换来获取线条),或者您可以使用此代码手动扩大它们。
void dilate_one(cv::Mat& grid){
cv::Size sz = grid.size();
cv::Mat sc_copy = grid.clone();
for(int i = 1; i < sz.height -1; i++){
for(int j = 1; j < sz.width -1; j++){
if(grid.at<uchar>(i,j) != 0){
sc_copy.at<uchar>(i+1,j) = 255;
sc_copy.at<uchar>(i-1,j) = 255;
sc_copy.at<uchar>(i,j+1) = 255;
sc_copy.at<uchar>(i,j-1) = 255;
sc_copy.at<uchar>(i-1,j-1) = 255;
sc_copy.at<uchar>(i+1,j+1) = 255;
sc_copy.at<uchar>(i-1,j+1) = 255;
sc_copy.at<uchar>(i+1,j-1) = 255;
}
}
}
grid = sc_copy;
}
在Hough变换后,您有一组向量,表示存储为cv::Vec4i v
这有该行的端点。最简单的解决方案是匹配每条线的终点并找到最接近的线。您可以使用简单的L1或L2规范来计算距离。
p1 = cv::Point2i(v[0],v[1])
和p2 = cv::point2i(v[2],v[3]))
非常接近的点应该是交叉点。唯一的问题是可能没有端点的T交叉点,但这似乎不是您图像中的问题。
答案 2 :(得分:1)
令我印象深刻的是,你真正想要的不一定是墙壁,而是房间 - 它们偶然被墙壁包围。
此外,虽然看起来你的“墙”数据相当嘈杂(即有许多小部分可能会混淆小房间) - 但你的“房间”数据不是(没有很多幻像房间中间的墙壁。)
因此,检测房间(大约在特定阈值内不包含白色像素的轴对齐矩形)可能是有益的,并通过查看附近像素之间的边界来推断墙壁。
我将分三个阶段实现这一点:首先,尝试从houghlines的输出中检测一些主轴(我首先会找到K-means聚类算法,然后按下输出以得到垂直轴)。使用此数据可以更好地对齐图像。
其次,在黑色区域开始随机播种关于图像的小矩形。在所有方向上“增长”这些矩形,直到每一侧在一定阈值上击中白色像素,或者它们进入另一个矩形。继续播种,直到覆盖图像的大部分区域。
第三,找到矩形未覆盖的区域(也希望是矩形),然后将它们折叠成直线:
这种方法有一些缺点:
我为不包含任何代码片段而道歉 - 但我认为传达这个想法更重要,而不是详细信息(如果您希望扩展其中任何一个,请发表评论)。还要注意,几年前我在使用opencv时,我绝不是专家 - 所以它可能已经有了一些基础来为你做这些。
答案 3 :(得分:0)
我只是在这里提出一个想法,但你可以尝试从原始图像的阈值开始(这可能会产生有趣的结果,因为你的图纸是在白纸上)。然后,通过在二进制图像上执行区域增长分割,您可能最终会将房间彼此分割并从背景中分割出来(标识房间和背景的标准可能是区域相似性)。由此,您将能够根据您的问题需要构建不同的模型:例如,房间的相对位置,区域,甚至构图(即整个楼层平面图包含较大的房间,其中包含较小的房间等等)。 / p>