3

I'm trying to detect main structures of many floor plan pictures by detecting straight lines and edges, with reference from here.

enter image description here

The example above is one example I need to deal with, is it possible to get main structure by detecting lines with opencv HoughLinesP from it? Thanks for your help at advance.

import cv2
import numpy as np

def get_lines(lines_in):
    if cv2.__version__ < '3.0':
        return lines_in[0]
    return [l[0] for l in lines]

img = cv2.imread('./test.jpg', 1)
img_gray = gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

cannied = cv2.Canny(img_gray, threshold1=50, threshold2=200, apertureSize=3)
lines = cv2.HoughLinesP(cannied, rho=1, theta=np.pi / 180, threshold=80, minLineLength=30, maxLineGap=10)

for line in get_lines(lines):
    leftx, boty, rightx, topy = line
    cv2.line(img, (leftx, boty), (rightx,topy), (255, 255, 0), 2)

cv2.imwrite('./lines.png', img)
cv2.imwrite('./canniedHouse.png', cannied)
cv2.waitKey(0)
cv2.destroyAllWindows()

Results:

lines.png

lines.png

canniedHouse.png

canniedHouse.png

Other references:

How to get the external contour of a floorplan in python?

Floor Plan Edge Detection - Image Processing?

nathancy
  • 42,661
  • 14
  • 115
  • 137
ah bon
  • 9,293
  • 12
  • 65
  • 148

1 Answers1

6

Here's an approach

  • Convert image to grayscale
  • Adaptive threshold to obtain binary image
  • Perform morphological transformations to smooth image
  • Create horizontal kernel and detect horizontal lines
  • Create vertical kernel and detect vertical lines

After converting to grayscale, we adaptive threshold to obtain a binary image

image = cv2.imread('1.jpg')
original = image.copy()
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

enter image description here

From here we perform morphological transformations to smooth the image

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)

enter image description here

Now we create a horizontal kernel with cv2.getStructuringElement() and detect horizontal lines

# Find horizontal lines
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (35,2))
detect_horizontal = cv2.morphologyEx(close, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detect_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(original, [c], -1, (36,255,12), -1)

enter image description here

Similarly, we create a vertical kernel and detect vertical lines

# Find vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,35))
detect_vertical = cv2.morphologyEx(close, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detect_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(original, [c], -1, (36,255,12), -1)

enter image description here

Here's the result

enter image description here

import cv2
import numpy as np

image = cv2.imread('1.jpg')
original = image.copy()
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)

# Find horizontal lines
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (35,2))
detect_horizontal = cv2.morphologyEx(close, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detect_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(original, [c], -1, (36,255,12), -1)

# Find vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,35))
detect_vertical = cv2.morphologyEx(close, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detect_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(original, [c], -1, (36,255,12), -1)

cv2.imshow('thresh', thresh)
cv2.imshow('close', close)
cv2.imshow('original', original)
cv2.waitKey()

If you wanted to just find the external contour you can find contours after the morphological close operation

cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(original, [c], -1, (36,255,12), 3)

enter image description here

nathancy
  • 42,661
  • 14
  • 115
  • 137
  • Thank you very much. This is much better. Sorry, I have one more question, do you know how to create a mask to remove text from it? such as `01, 02, ... 07, 电梯厅` etc. – ah bon Aug 16 '19 at 23:18
  • 1
    I can't think of a robust way to do it but a potential method would be to find contours and filter using contour area – nathancy Aug 17 '19 at 00:05