使用 Python 从地图图像中提取建筑物边缘

Posted

技术标签:

【中文标题】使用 Python 从地图图像中提取建筑物边缘【英文标题】:Extract building edges from map image using Python 【发布时间】:2019-06-24 11:56:47 【问题描述】:

我在这里得到了一张地图图像。 我需要提取建筑物的边缘以进行进一步处理,结果类似于here 帖子的第 2 步。

由于我对这个领域不熟悉,这可以通过OpenCV之类的库来完成吗?

【问题讨论】:

建筑物边界的颜色很容易区分。所以,我想这个教程很有帮助:realpython.com/python-opencv-color-spaces 是的,这可以做到。试试canny edge detection 【参考方案1】:

您似乎想选择单个建筑物,所以我使用了颜色分离。墙壁较暗,这使得HSV colorspace 的分离效果很好。请注意,可以通过进一步放大和/或使用压缩较少的图像类型(例如 PNG)来改进最终结果。

选择墙壁 首先,我确定了良好的分离值。为此,我使用了this script。我发现最好的结果是将黄色和灰色分别分开,然后组合生成的蒙版。并非所有墙壁都完美关闭,所以我通过 closing 稍微改进了结果。结果是一个显示所有墙壁的蒙版:

从左到右:黄色蒙版、灰色蒙版、组合固化蒙版

寻找建筑物 接下来我使用findCountours 来分隔建筑物。由于墙壁轮廓可能不是很有用(因为墙壁是相互连接的),我使用hierarchy 来查找“最低”轮廓(其中没有其他轮廓)。这些是建筑物。

findContours的结果:绿色为所有轮廓的轮廓,红色为单个建筑物的轮廓

请注意,边缘上的建筑物不会被检测到。这是因为使用这种技术,它们不是单独的轮廓,而是图像外部的一部分。这可以通过在图像的边框上绘制一个灰色的rectangle 来解决。您可能不希望在您的最终申请中使用它,但我将其包含在您的最终应用程序中。

代码:

    import cv2
    import numpy as np  

    #load image and convert to hsv
    img = cv2.imread("fLzI9.jpg")

    # draw gray box around image to detect edge buildings
    h,w = img.shape[:2]
    cv2.rectangle(img,(0,0),(w-1,h-1), (50,50,50),1)

    # convert image to HSV
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    # define color ranges
    low_yellow = (0,28,0)
    high_yellow = (27,255,255)

    low_gray = (0,0,0)
    high_gray = (179,255,233)

    # create masks
    yellow_mask = cv2.inRange(hsv, low_yellow, high_yellow )
    gray_mask = cv2.inRange(hsv, low_gray, high_gray)

    # combine masks
    combined_mask = cv2.bitwise_or(yellow_mask, gray_mask)
    kernel = np.ones((3,3), dtype=np.uint8)
    combined_mask = cv2.morphologyEx(combined_mask, cv2.MORPH_DILATE,kernel)

    # findcontours
    contours, hier = cv2.findContours(combined_mask,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    # find and draw buildings
    for x in range(len(contours)):
            # if a contour has not contours inside of it, draw the shape filled
            c = hier[0][x][2]
            if c == -1:
                    cv2.drawContours(img,[contours[x]],0,(0,0,255),-1)

    # draw the outline of all contours
    for cnt in contours:
            cv2.drawContours(img,[cnt],0,(0,255,0),2)

    # display result
    cv2.imshow("Result", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows() 

结果:建筑物被绘制为纯红色,所有轮廓为绿色覆盖

【讨论】:

嗨,J.D.,这对我来说非常完美,不仅因为它解决了我的问题,而且参考资料也很有帮助(HSV 色彩空间脚本很棒),谢谢!【参考方案2】:

这是一个简单的方法

将图像转换为灰度,将高斯模糊转换为平滑边缘 阈值图像 执行 Canny 边缘检测 查找轮廓并绘制轮廓

使用cv2.threshold()的阈值图像

使用 cv2.Canny() 执行 Canny 边缘检测

使用cv2.findContours()cv2.drawContours() 查找轮廓

import cv2

image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
thresh = cv2.threshold(blurred, 240 ,255, cv2.THRESH_BINARY_INV)[1]
canny = cv2.Canny(thresh, 50, 255, 1)

cnts = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

for c in cnts:
    cv2.drawContours(image,[c], 0, (36,255,12), 2)

cv2.imshow('thresh', thresh)
cv2.imshow('canny', canny)
cv2.imshow('image', image)
cv2.imwrite('thresh.png', thresh)
cv2.imwrite('canny.png', canny)
cv2.imwrite('image.png', image)
cv2.waitKey(0)

【讨论】:

以上是关于使用 Python 从地图图像中提取建筑物边缘的主要内容,如果未能解决你的问题,请参考以下文章

5分钟,ArcGIS 简单几步从天地图中提取出建筑物轮廓的矢量数据

建筑物高度数据的获取的几种方法

R中是不是有显示建筑物的基本地图包?

HERE-API识别建筑物的地板/地平面

全球建筑物轮廓数据

高分辨率图像建筑物提取数据集制作