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?