Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
373 views
in Technique[技术] by (71.8m points)

how to get the cardinal directions for each room in a floor plan using opencv and python?

I wanted to get the cardinal direction of each room in a floor plan. For that, I followed a number of steps.

Step 01 -

Break the floor plan into individual rooms. The code for step 01 as follows.

import cv2
import math
import numpy as np 
import pymysql


def find_rooms(img, noise_removal_threshold=25, corners_threshold=0.1,
            room_closing_max_length=100, gap_in_wall_threshold=500):


assert 0 <= corners_threshold <= 1
# Remove noise left from door removal

img[img < 128] = 0
img[img > 128] = 255
contours, hierarchy  = cv2.findContours(~img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
mask = np.zeros_like(img)
for contour in contours:
    area = cv2.contourArea(contour)
    if area > noise_removal_threshold:
        cv2.fillPoly(mask, [contour], 255)

img = ~mask

# Detect corners 
dst = cv2.cornerHarris(img ,2,3,0.04)
dst = cv2.dilate(dst,None)
corners = dst > corners_threshold * dst.max()

# Draw lines to close the rooms off by adding a line between corners on the same x or y coordinate
for y,row in enumerate(corners):
    x_same_y = np.argwhere(row)
    for x1, x2 in zip(x_same_y[:-1], x_same_y[1:]):

        if x2[0] - x1[0] < room_closing_max_length:
            color = 0
            cv2.line(img, (x1, y), (x2, y), color, 1)

for x,col in enumerate(corners.T):
    y_same_x = np.argwhere(col)
    for y1, y2 in zip(y_same_x[:-1], y_same_x[1:]):
        if y2[0] - y1[0] < room_closing_max_length:
            color = 0
            cv2.line(img, (x, y1), (x, y2), color, 1)


# Mark the outside of the house as black
contours,  hierarchy = cv2.findContours(~img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contour_sizes = [(cv2.contourArea(contour), contour) for contour in contours]
biggest_contour = max(contour_sizes, key=lambda x: x[0])[1]
mask = np.zeros_like(mask)
cv2.fillPoly(mask, [biggest_contour], 255)
img[mask == 0] = 0

# Find the connected components in the house
ret, labels = cv2.connectedComponents(img)
img = cv2.cvtColor(img,cv2.COLOR_GRAY2RGB)
unique = np.unique(labels)
rooms = []
for label in unique:
    component = labels == label
    if img[component].sum() == 0 or np.count_nonzero(component) < gap_in_wall_threshold:
        color = 0
    else:
        rooms.append(component)
        color = np.random.randint(0, 255, size=3)
    img[component] = color

return rooms, img

# crop the images
for room in rooms:
    crop = np.zeros_like(room).astype(np.uint8)
    # crop[room] = original_img[room]  # Get the original image from somewhere
    # if you need to crop the image into smaller parts as big as each room
    r, c = np.nonzero(room)
    min_r, max_r = r.argmin(), r.argmax()
    min_c, max_c = c.argmin(), c.argmax()
    crop = crop[min_r:max_r, min_c:max_c]
    cv2.imshow("cropped room", crop)


    #Read gray image
   img = cv2.imread("floor_plan_02.png", 0)
   rooms, colored_house = find_rooms(img.copy())


   cv2.imshow('result', colored_house)
   cv2.imwrite('color_plan.png', colored_house)


    #add the co-ordinate segment
    # Load image, grayscale, Otsu's threshold
    image = cv2.imread('color_plan.png')
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

    # Remove text
    cnts = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    for c in cnts:
         area = cv2.contourArea(c)
     if area < 1000:
           cv2.drawContours(thresh, [c], -1, 0, -1)

     thresh = 255 - thresh
     result = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR)

     #pass the x-axis and y-axis coordinates values into an array called coordinates.
     coordinates = []

step 02 - Find the central point of each room of the floor plan. For this step, I used moments in OpenCV.By using moments, I found the x and y co-ordinate values of the central points of each room.Code as follows

     # Find rectangular boxes and obtain centroid coordinates
     cnts = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
     cnts = cnts[0] if len(cnts) == 2 else cnts[1]
     for c in cnts:
          area = cv2.contourArea(c)
          peri = cv2.arcLength(c, True)
          approx = cv2.approxPolyDP(c, 0.05 * peri, True)
      if len(approx) == 4 and area < 10000:
         # cv2.drawContours(result, [c], -1, (36,255,12), 1)
         M = cv2.moments(c)
         cx = int(M['m10']/M['m00'])
         # print(cx)
         cy = int(M['m01']/M['m00'])
        # print(cy)
        coordinates.append((cx, cy))
        cv2.circle(result, (cx, cy), 3, (36,255,12), -1)
        cv2.putText(result, '({}, {})'.format(int(cx), int(cy)), (int(cx) -40, int(cy) -10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (36,255,12), 2)


        print(coordinates)

Step 03 -

In step 03, I was calculated the degree between each x-axis and y-axis for each room and found the cardinal direction for each room from the direction array.

#find the cardinal direction

def direction_lookup(coordinates): #difference of x axis deltaX = coordinates[0][0] deltaX1 = coordinates[1][0] deltaX2 = coordinates[2][0] deltaX3 = coordinates[3][0] deltaX4 = coordinates[4][0] deltaX5 = coordinates[5][0] deltaX6 = coordinates[6][0] deltaX7 = coordinates[7][0]

# print(deltaX)
#diference of y axis
deltaY = coordinates[0][1]
deltaY1 = coordinates[1][1]
deltaY2 = coordinates[2][1]
deltaY3 = coordinates[3][1]
deltaY4 = coordinates[4][1]
deltaY5 = coordinates[5][1]
deltaY6 = coordinates[6][1]
deltaY7 = coordinates[7][1]
# print(deltaY)

#degrees
degrees_temp = math.atan2(deltaX, deltaY)/math.pi* 180
degrees_temp1 = math.atan2(deltaX1, deltaY1)/math.pi* 180
degrees_temp2 = math.atan2(deltaX2, deltaY2)/math.pi* 180
degrees_temp3 = math.atan2(deltaX3, deltaY3)/math.pi* 180
degrees_temp4 = math.atan2(deltaX4, deltaY4)/math.pi* 180
degrees_temp5 = math.atan2(deltaX5, deltaY5)/math.pi* 180
degrees_temp6 = math.atan2(deltaX6, deltaY6)/math.pi* 180
degrees_temp7 = math.atan2(deltaX7, deltaY7)/math.pi* 180

# print degrees values 
print(degrees_temp)
print(degrees_temp1)
print(degrees_temp2)
print(degrees_temp3)
print(degrees_temp4)
print(degrees_temp5)
print(degrees_temp6)
print(degrees_temp7)


#condition
if degrees_temp < 0:
    degrees_final = 360 + degrees_temp
else:
    degrees_final = degrees_temp

if degrees_temp1 < 0:
    degrees_final1 = 360 + degrees_temp1
else:
    degrees_final1 = degrees_temp1

if degrees_temp2 < 0:
    degrees_final2 = 360 + degrees_temp2
else:
    degrees_final2 = degrees_temp2


if degrees_temp3 < 0:
    degrees_final3 = 360 + degrees_temp3
else:
    degrees_final3 = degrees_temp3

if degrees_temp4 < 0:
    degrees_final4 = 360 + degrees_temp4
else:
    degrees_final4 = degrees_temp4


if degrees_temp5 < 0:
    degrees_final5 = 360 + degrees_temp5
else:
    degrees_final5 = degrees_temp5


if degrees_temp6 < 0:
    degrees_final6 = 360 + degrees_temp6
else:
    degrees_final6 = degrees_temp6


if degrees_temp7 < 0:
    degrees_final7 = 360 + degrees_temp7
else:
    degrees_final7 = degrees_temp7



#directions collection
compass_brackets = ["NORTH", "NORTH-EAST","EAST","SOUTH-EAST","SOUTH","SOUTH-WEST","WEST","NORTH-WEST"]

#round the values 
compass_lookup = round(degrees_final/45)
compass_lookup1 = round(degrees_final1/45)
compass_lookup2 = round(degrees_final2/45)
compass_lookup3 = round(degrees_final3/45)
compass_lookup4 = round(degrees_final4/45)
compass_lookup5 = round(degrees_final4/45)
compass_lookup6 = round(degrees_final4/45)
compass_lookup7 = round(degrees_final4/45)

#cardinal directions
final_direction = compass_brackets[compass_lookup]
final_direction1 = compass_brackets[compass_lookup1]
final_direction2 = compass_brackets[compass_lookup2]
final_direction3 = compass_brackets[compass_lookup3]
final_direction4 = compass_brackets[compass_lookup4]
final_direction5 = compass_brackets[compass_lookup5]
final_direction6 = compass_brackets[compass_lookup6]
final_direction7 = compass_brackets[compass_lookup7]

# print the cardinal directions
print(final_direction + " is the direction For living room ")
print(final_direction1 + " is the direction for kitchen ")
print(final_direction2 + " is the direction for Master bedroom")
print(final_direction3 + " is the direction for bedroom one")
print(final_direction4 + " is the direction for bedroom two")
print(final_direction5 + " is the direction for dining room")
print(final_direction6 + " is the direction for bathroom")
print(final_direction7 + " is the direction for closet")

#return the cardinal directions and degree values to the function
return final_direction,final_direction1,final_direction3, final_direction4, final_direction5, final_direction6, final_direction7

 #create the list for the cardinal directions
 direction_list = []

 direction_list= direction_lookup(coordinates)
 print(direction_list)

 # cardinal direction of living room
 direction_living_room = direction_list[0]
 print(type(direction_living_room))

 #cadinal direction of kitchen
 direction_kitchen_room = direction_list[1]
 print(direction_kitchen_room)

 #cardinal direction of master bed room
 direction_master_bed_room = direction_list[2]
 print(direction_master_bed_room)

 #cardinal direction of bed room 1
 direction_bed_room_one = direction_list[3]
 print(direction_bed_room_one)

 # cardinal direction of bed room 2
 direction_bed_room_two = direction_list[4]
 print(direction_bed_room_two)

 #cardinal direction of dining room
 direction_dining_room = direction_list[5]
 print(direction_dining_room)

 # cardinal direction of bathroom
 direction_bathroom = direction_list[6]
 print(direction_bathroom)

But My problem is that I got only two directions as cardinal directions. The cardinal directions I got were north, east, north-east. But it needs to get different cardinal directions for each room. What could be the problem with the above code?

The floor plan entered for the code - floor plan here

The output cardinal directions for the rooms - output


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
等待大神答复

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...