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?
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?
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:
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.
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
Here's a simple approach
Threshold image using cv2.threshold()
Perform Canny edge detection with cv2.Canny()
Find contours using cv2.findContours()
and 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)