2

I got a map image here. I need to extract the edges of buildings for further process, the result would be like step 2 for the post here.

Since I am not familiar with this field, can this be done by libraries such as OpenCV?

map image

TylerH
  • 20,799
  • 66
  • 75
  • 101
Pete
  • 247
  • 4
  • 14
  • The colors of buildings' boundary are easily distinguishable. So, I suppose this tutorial is helpful: https://realpython.com/python-opencv-color-spaces/ – Masoud Jun 24 '19 at 12:12
  • Yes, this can be done. Try [canny edge detection](https://docs.opencv.org/3.1.0/da/d22/tutorial_py_canny.html) – T A Jun 24 '19 at 12:35

2 Answers2

5

Seems you want to select individual buildings, so I used color separation. The walls are darker, which makes for good separation in the HSV colorspace. Note that the final result can be improved by zooming in more and/or by using an imagetype with less compression, such as PNG.

Select walls
First I determined good values for separation. For that I used this script. I found that the best result would be to separate the yellow and the gray separately and then combine the resulting masks. Not all walls closed perfectly, so I improved the result by closing the mask a bit. The result is a mask that displays all walls:

enter image description here Left to right: Yellow mask, Gray mask, Combined and solidified mask

Find buildings
Next I used findCountours to separate out buildings. Since the wall contours will probably not be very useful (as walls are interconnected), I used the hierarchy to find the 'lowest' contours (that have no other contours inside of them). These are the buildings.

enter image description here Result of findContours: the outline of all contours in green, the outline of individual buildings in red

Note that buildings on the edge are not detected. This is because using this technique they are not a separate contour, but part of the exterior of the image. This can be solve this by drawing a rectangle in gray on the border of the image. You may not want this in your final application, but I included it in case you do.

Code:

    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() 

Result:
With buildings drawn solid red and all contours as green overlay

enter image description here

J.D.
  • 4,511
  • 2
  • 7
  • 20
  • Hi J.D., this is just perfect for me not only because it solved my problem but the references help a lot as well (that HSV colorspace scripts is awesome), thanks! – Pete Jun 26 '19 at 08:08
0

Here's a simple approach

  • Convert image to grayscale and Gaussian blur to smooth edges
  • Threshold image
  • Perform Canny edge detection
  • Find contours and draw contours

Threshold image using cv2.threshold()

enter image description here

Perform Canny edge detection with cv2.Canny()

enter image description here

Find contours using cv2.findContours() and cv2.drawContours()

enter image description here

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)
nathancy
  • 42,661
  • 14
  • 115
  • 137