Spaces:
Runtime error
Runtime error
| """ | |
| This code is an adaptation that uses Structured 3D for the code base. | |
| Reference: https://github.com/bertjiazheng/Structured3D | |
| """ | |
| import random | |
| import cv2 | |
| import numpy as np | |
| from shapely.geometry import Polygon | |
| type2id = { | |
| "living room": 0, | |
| "kitchen": 1, | |
| "bedroom": 2, | |
| "bathroom": 3, | |
| "balcony": 4, | |
| "corridor": 5, | |
| "dining room": 6, | |
| "study": 7, | |
| "studio": 8, | |
| "store room": 9, | |
| "garden": 10, | |
| "laundry room": 11, | |
| "office": 12, | |
| "basement": 13, | |
| "garage": 14, | |
| "undefined": 15, | |
| "door": 16, | |
| "window": 17, | |
| "outwall": -1, | |
| } | |
| def parse_floor_plan_polys(annos): | |
| planes = [] | |
| for semantic in annos["semantics"]: | |
| for planeID in semantic["planeID"]: | |
| if annos["planes"][planeID]["type"] == "floor": | |
| planes.append({"planeID": planeID, "type": semantic["type"]}) | |
| if semantic["type"] == "outwall": | |
| outerwall_planes = semantic["planeID"] | |
| # extract hole vertices | |
| lines_holes = [] | |
| for semantic in annos["semantics"]: | |
| if semantic["type"] in ["window", "door"]: | |
| for planeID in semantic["planeID"]: | |
| lines_holes.extend(np.where(np.array(annos["planeLineMatrix"][planeID]))[0].tolist()) | |
| lines_holes = np.unique(lines_holes) | |
| # junctions on the floor | |
| junctions = np.array([junc["coordinate"] for junc in annos["junctions"]]) | |
| junction_floor = np.where(np.isclose(junctions[:, -1], 0))[0] | |
| # construct each polygon | |
| polygons = [] | |
| for plane in planes: | |
| lineIDs = np.where(np.array(annos["planeLineMatrix"][plane["planeID"]]))[0].tolist() | |
| junction_pairs = [np.where(np.array(annos["lineJunctionMatrix"][lineID]))[0].tolist() for lineID in lineIDs] | |
| polygon = convert_lines_to_vertices(junction_pairs) | |
| polygons.append([polygon[0], plane["type"]]) | |
| outerwall_floor = [] | |
| for planeID in outerwall_planes: | |
| lineIDs = np.where(np.array(annos["planeLineMatrix"][planeID]))[0].tolist() | |
| lineIDs = np.setdiff1d(lineIDs, lines_holes) | |
| junction_pairs = [np.where(np.array(annos["lineJunctionMatrix"][lineID]))[0].tolist() for lineID in lineIDs] | |
| for start, end in junction_pairs: | |
| if start in junction_floor and end in junction_floor: | |
| outerwall_floor.append([start, end]) | |
| outerwall_polygon = convert_lines_to_vertices(outerwall_floor) | |
| polygons.append([outerwall_polygon[0], "outwall"]) | |
| return polygons | |
| def convert_lines_to_vertices(lines): | |
| """ | |
| convert line representation to polygon vertices | |
| """ | |
| polygons = [] | |
| lines = np.array(lines) | |
| polygon = None | |
| while len(lines) != 0: | |
| if polygon is None: | |
| polygon = lines[0].tolist() | |
| lines = np.delete(lines, 0, 0) | |
| lineID, juncID = np.where(lines == polygon[-1]) | |
| vertex = lines[lineID[0], 1 - juncID[0]] | |
| lines = np.delete(lines, lineID, 0) | |
| if vertex in polygon: | |
| polygons.append(polygon) | |
| polygon = None | |
| else: | |
| polygon.append(vertex) | |
| return polygons | |
| def generate_floorplan( | |
| annos, | |
| polygons, | |
| height, | |
| width, | |
| ignore_types, | |
| include_types=None, | |
| fillpoly=True, | |
| constant_color=False, | |
| shuffle=False, | |
| ): | |
| """ | |
| plot floorplan | |
| """ | |
| floor_map = np.zeros((height, width)) | |
| junctions = np.array([junc["coordinate"][:2] for junc in annos["junctions"]]) | |
| room_ind = 0 | |
| if shuffle: | |
| room_ind = np.random.randint(0, 2) | |
| polygons_list = [] | |
| polygons_type_list = [] | |
| for poly_ind, (polygon, poly_type) in enumerate(polygons): | |
| if poly_type in ignore_types: | |
| continue | |
| if include_types is not None and poly_type not in include_types: | |
| continue | |
| polygon = junctions[np.array(polygon)].astype(np.int32) | |
| poly_shapely = Polygon(polygon) | |
| area = poly_shapely.area | |
| # assert area > 10 | |
| # if area < 100: | |
| # continue | |
| if poly_type not in ["door", "window"] and area < 100: | |
| continue | |
| if poly_type in ["door", "window"] and area < 1: | |
| continue | |
| if poly_type in ["door", "window"]: | |
| assert polygon.shape[0] == 4 | |
| midp_1 = (polygon[0] + polygon[1]) / 2 | |
| midp_2 = (polygon[1] + polygon[2]) / 2 | |
| midp_3 = (polygon[2] + polygon[3]) / 2 | |
| midp_4 = (polygon[3] + polygon[0]) / 2 | |
| dist_1_3 = np.square(midp_1 - midp_3).sum() | |
| dist_2_4 = np.square(midp_2 - midp_4).sum() | |
| if dist_1_3 > dist_2_4: | |
| polygon = np.row_stack([midp_1, midp_3]) | |
| else: | |
| polygon = np.row_stack([midp_2, midp_4]) | |
| polygons_list.append(polygon) | |
| polygons_type_list.append(type2id[poly_type]) | |
| if shuffle: | |
| random.shuffle(polygons_list) | |
| for poly_ind, polygon in enumerate(polygons_list): | |
| if shuffle: | |
| room_ind += np.random.randint(1, 2) | |
| else: | |
| room_ind += 1 | |
| if fillpoly: | |
| if constant_color: | |
| clr = 1.0 | |
| else: | |
| clr = room_ind | |
| cv2.fillPoly(floor_map, [polygon], color=clr) | |
| else: | |
| assert constant_color | |
| cv2.polylines(floor_map, [polygon.astype(np.int32)], isClosed=True, color=1.0, thickness=3) | |
| return floor_map, polygons_list, polygons_type_list | |