Spaces:
Runtime error
Runtime error
| import torch | |
| from torch.utils.data import Dataset | |
| import numpy as np | |
| import scipy.io as sio | |
| import cv2 | |
| import copy | |
| from model.utils import * | |
| class FloorPlan(): | |
| def __init__(self, data, rot=None,fliplr=False): | |
| self.data = copy.deepcopy(data) | |
| ''' transform ''' | |
| if rot is not None: | |
| theta = self._get_rot() | |
| self.data.gtBoxNew = align_box(self.data.gtBoxNew[:,[1,0,3,2]],theta,rot)[:,[1,0,3,2]] | |
| self.data.boundary[:,[1,0]] = align_points(self.data.boundary[:,[1,0]],theta,rot) | |
| if fliplr: | |
| self.data.gtBoxNew[:,[1,0,3,2]] = fliplr_box(self.data.gtBoxNew[:,[1,0,3,2]]) | |
| self.data.boundary[:,[1,0]] = fliplr_2D(self.data.boundary[:,[1,0]]) | |
| def _get_rot(self): | |
| door_line = self.data.boundary[:2, :2] # [:,[1,0]] | |
| c = door_line.mean(0) - np.array([127.5,127.5]) | |
| theta = np.arctan2(c[1], c[0]) + np.pi # [-pi,pi] | |
| return theta | |
| def get_input_boundary(self, tensor=True): | |
| external = self.data.boundary[:, :2] | |
| door = self.data.boundary[:2, :2] | |
| boundary = np.zeros((128, 128), dtype=float) | |
| inside = np.zeros((128, 128), dtype=float) | |
| front = np.zeros((128, 128), dtype=float) | |
| pts = np.concatenate([external, external[:1]]) // 2 | |
| pts_door = door // 2 | |
| cv2.fillPoly(inside, pts.reshape(1, -1, 2), 1.0) | |
| cv2.polylines(boundary, pts.reshape(1, -1, 2), True, 1.0, 3) | |
| cv2.polylines(boundary, pts_door.reshape(1, -1, 2), True, 0.5, 3) | |
| cv2.polylines(front, pts_door.reshape(1, -1, 2), True, 1.0, 3) | |
| input_image = np.stack([inside, boundary, front], -1) | |
| if tensor: input_image = torch.tensor(input_image).permute((2, 0, 1)).float() | |
| return input_image | |
| def get_inside_box(self, tensor=True): | |
| boundary = self.data.boundary[:, :2] | |
| X, Y = np.linspace(0, 1, 256), np.linspace(0, 1, 256) | |
| x0, x1 = np.min(boundary[:, 0]), np.max(boundary[:, 0]) | |
| y0, y1 = np.min(boundary[:, 1]), np.max(boundary[:, 1]) | |
| box = np.array([[X[x0], Y[y0], X[x1], Y[y1]]]) | |
| if tensor: box = torch.tensor(box).float() | |
| return box | |
| def get_rooms(self, tensor=True): | |
| rooms = self.data.rType | |
| if tensor: rooms = torch.tensor(rooms).long() | |
| return rooms | |
| def get_attributes(self, gsize=5, alevel=10, relative=True, tensor=True): | |
| boxes = self.data.gtBoxNew[:,[1,0,3,2]] | |
| boundary = self.data.boundary[:,:2] | |
| h, w = 256, 256 | |
| if relative: | |
| x0, x1 = np.min(boundary[:, 0]), np.max(boundary[:, 0])+1 | |
| y0, y1 = np.min(boundary[:, 1]), np.max(boundary[:, 1])+1 | |
| h, w = y1 - y0, x1 - x0 | |
| boxes = boxes - np.array([y0, x0, y0, x0], dtype=float) | |
| boxes /= np.array([h, w, h, w]) | |
| boxes[:, 2:] -= boxes[:, :2] # y1,x1->h,w | |
| boxes[:, :2] += boxes[:, 2:] / 2 # y0,x0->yc,xc | |
| l = len(boxes) | |
| gbins = np.linspace(0,1,gsize+1) # [1,gsize] | |
| gbins[0],gbins[-1]=-np.inf,np.inf | |
| abins = np.linspace(0,1,alevel+1) # [1,gsize] | |
| abins[0],abins[-1]=-np.inf,np.inf | |
| attributes = np.zeros((l,gsize*gsize+alevel)) | |
| # pos: xc*gsize+yc*gsize*gsize | |
| attributes[range(l),(np.digitize(boxes[:,0],gbins)-1)*gsize+np.digitize(boxes[:,1],gbins)-1]=1 | |
| # area:(w*h) | |
| attributes[range(l),gsize*gsize+np.digitize(boxes[:,2:].prod(1),abins)-1]=1 | |
| if tensor: attributes = torch.tensor(attributes).float() | |
| return attributes | |
| def get_triples(self, random=False, tensor=True): | |
| boxes = self.data.gtBoxNew[:, [1, 0, 3, 2]] | |
| vocab = get_vocab() | |
| triples = [] | |
| # add edge relation | |
| for u, v, _ in self.data.rEdge: | |
| # Todo: random order for edge | |
| # if random and np.random.random() > 0.5: | |
| # u, v = v, u | |
| uy0, ux0, uy1, ux1 = boxes[u] | |
| vy0, vx0, vy1, vx1 = boxes[v] | |
| uc = (uy0 + uy1) / 2, (ux0 + ux1) / 2 | |
| vc = (vy0 + vy1) / 2, (vx0 + vx1) / 2 | |
| # surrounding/inside -> X four quadrants | |
| if ux0 < vx0 and ux1 > vx1 and uy0 < vy0 and uy1 > vy1: | |
| relation = 'surrounding' | |
| elif ux0 >= vx0 and ux1 <= vx1 and uy0 >= vy0 and uy1 <= vy1: | |
| relation = 'inside' | |
| else: | |
| relation = point_box_relation(uc, boxes[v]) | |
| triples.append([u, vocab['pred_name_to_idx'][relation], v]) | |
| triples = np.array(triples, dtype=int) | |
| if tensor: triples = torch.tensor(triples).long() | |
| return triples | |
| def get_layout_image(self,tensor=True): | |
| img = np.full((128,128),13,dtype=np.uint8) | |
| boundary = self.data.boundary[:,:2] | |
| boundary = np.concatenate([boundary, boundary[:1]]) | |
| cv2.fillPoly(img, (boundary//2).reshape(1, -1, 2), 0) | |
| order = self.data.order-1 | |
| rType = self.data.rType[order] | |
| rBox = self.data.gtBoxNew[order] | |
| for i in range(len(rType)): | |
| t = rType[i] | |
| if t==0: continue | |
| b = rBox[i]//2 | |
| img[b[1]:b[3],b[0]:b[2]]=t | |
| cv2.polylines(img, (boundary//2).reshape(1, -1, 2), True,14) | |
| if tensor: img = torch.tensor(img).long() | |
| return img | |
| def get_boxes(self,relative=True,tensor=True): | |
| boxes = self.data.gtBoxNew[:, [1, 0, 3, 2]] | |
| boundary = self.data.boundary[:,:2] | |
| X,Y = np.linspace(0,1,256),np.linspace(0,1,256) | |
| if relative: | |
| x0, x1 = np.min(boundary[:, 0]), np.max(boundary[:, 0])+1 | |
| y0, y1 = np.min(boundary[:, 1]), np.max(boundary[:, 1])+1 | |
| h, w = y1 - y0, x1 - x0 | |
| X,Y = np.linspace(0,1,w),np.linspace(0,1,h) | |
| boxes = boxes-np.array([y0,x0,y0,x0]) | |
| norm = lambda box:np.array([ | |
| X[max(box[1],0)], | |
| Y[max(box[0],0)], | |
| X[min(box[3]-1,w-1)], | |
| Y[min(box[2]-1,h-1)] | |
| ]) | |
| boxes = np.apply_along_axis(norm,1,boxes) | |
| boxes[:,2:]-=boxes[:,:2] | |
| boxes[:,:2]+=boxes[:,2:]/2 | |
| if tensor: | |
| boxes = torch.tensor(boxes).float() | |
| return boxes | |
| def get_inside_coords(self,size=(32,32),tensor=True): | |
| h,w = size | |
| X = np.linspace(0,1,w) | |
| Y = np.linspace(0,1,h) | |
| img = np.zeros(size) | |
| boundary = self.data.boundary[:,:2] | |
| boundary = boundary*np.array(size)//256 | |
| cv2.fillPoly(img, boundary.reshape(1, -1, 2), 1) | |
| coords = np.where(img>0) | |
| coords = np.stack((X[coords[1]],Y[coords[0]]),1) | |
| if tensor: coords = torch.tensor(coords).unsqueeze(0).float() | |
| return coords | |
| def get_test_data(self, tensor=True): | |
| name = self.data.name | |
| boundary = self.get_input_boundary(tensor=tensor) | |
| inside_box = self.get_inside_box(tensor=tensor) | |
| rooms = self.get_rooms(tensor=tensor) | |
| attrs = self.get_attributes(tensor=tensor) | |
| triples = self.get_triples(random=False, tensor=tensor) | |
| return boundary, inside_box, rooms, attrs, triples, name | |
| def get_train_data(self, tensor=True): | |
| name = self.data.name | |
| boundary = self.get_input_boundary(tensor=tensor) | |
| inside_box = self.get_inside_box(tensor=tensor) | |
| rooms = self.get_rooms(tensor=tensor) | |
| attrs = self.get_attributes(tensor=tensor) | |
| triples = self.get_triples(random=False, tensor=tensor) | |
| # gt | |
| layout = self.get_layout_image(tensor=tensor) | |
| boxes = self.get_boxes(tensor=tensor) | |
| # constrains | |
| inside_coords = self.get_inside_coords(tensor=tensor) | |
| return boundary,inside_box,rooms,attrs,triples,layout,boxes,inside_coords,name | |
| class FloorPlanDataset(Dataset): | |
| def __init__(self,data_path): | |
| self.data = sio.loadmat(data_path, squeeze_me=True, struct_as_record=False)['data'] | |
| self.train = True if 'train' in data_path else False | |
| def __len__(self): | |
| return len(self.data) | |
| def __getitem__(self,i): | |
| if self.train: | |
| rot = np.random.randint(0,4) | |
| fliplr = np.random.random()>0.5 | |
| fp = FloorPlan(self.data[i],rot=rot,fliplr=fliplr) | |
| return fp.get_train_data() | |
| else: | |
| fp = FloorPlan(self.data[i]) | |
| return fp.get_train_data() | |
| def floorplan_collate_fn(batch): | |
| all_boundary = [] | |
| all_inside_box = [] | |
| all_objs = [] | |
| all_attrs = [] | |
| all_triples = [] | |
| all_layout = [] | |
| all_boxes = [] | |
| all_inside_coords = [] | |
| all_obj_to_img = [] | |
| all_triple_to_img = [] | |
| all_name = [] | |
| obj_offset = 0 | |
| for i, ( | |
| boundary, | |
| inside_box, | |
| rooms, | |
| attrs, | |
| triples, | |
| layout, | |
| boxes, | |
| inside_coords, | |
| name | |
| ) in enumerate(batch): | |
| if rooms.dim() == 0 or triples.dim() == 0: | |
| continue | |
| O, T = rooms.size(0), triples.size(0) | |
| all_boundary.append(boundary[None]) | |
| all_inside_box.append(inside_box) | |
| all_objs.append(rooms) | |
| all_attrs.append(attrs) | |
| triples = triples.clone() | |
| triples[:, 0] += obj_offset | |
| triples[:, 2] += obj_offset | |
| all_triples.append(triples) | |
| all_layout.append(layout[None]) | |
| all_boxes.append(boxes) | |
| all_inside_coords.append(inside_coords) | |
| all_name.append(name) | |
| all_obj_to_img.append(torch.LongTensor(O).fill_(i)) | |
| all_triple_to_img.append(torch.LongTensor(T).fill_(i)) | |
| obj_offset += O | |
| all_boundary = torch.cat(all_boundary) | |
| all_inside_box = torch.cat(all_inside_box) | |
| all_objs = torch.cat(all_objs) | |
| all_attrs = torch.cat(all_attrs) | |
| all_triples = torch.cat(all_triples) | |
| all_layout = torch.cat(all_layout) | |
| all_boxes = torch.cat(all_boxes) | |
| all_obj_to_img = torch.cat(all_obj_to_img) | |
| all_triple_to_img = torch.cat(all_triple_to_img) | |
| out = ( | |
| all_boundary, | |
| all_inside_box, | |
| all_objs, | |
| all_attrs, | |
| all_triples, | |
| all_layout, | |
| all_boxes, | |
| all_inside_coords, | |
| all_obj_to_img, | |
| all_triple_to_img, | |
| all_name | |
| ) | |
| return out | |
| def vis_fp(fp,size=(256,256)): | |
| cmap = get_color_map() | |
| img = np.full((256, 256, 4), 0, dtype=np.uint8) | |
| boundary = fp.data.boundary[:,:2] | |
| boundary = np.concatenate([boundary, boundary[:1]]) | |
| door = fp.data.boundary[:2, :2] | |
| c = cmap[0].tolist() | |
| cv2.fillPoly(img, boundary.reshape(1, -1, 2), (c[0],c[1],c[2],255)) | |
| order = fp.data.order-1 | |
| rType = fp.data.rType[order] | |
| rBox = fp.data.gtBoxNew[order] | |
| for i in range(len(rType)): | |
| t = rType[i] | |
| if t==0: continue | |
| b = rBox[i] | |
| c = cmap[t].tolist() | |
| cv2.rectangle(img, (b[0],b[1]),(b[2]-1,b[3]-1), (c[0],c[1],c[2],255),-1) | |
| c = cmap[-1].tolist() | |
| cv2.rectangle(img, (b[0],b[1]),(b[2]-1,b[3]-1), (c[0],c[1],c[2],255),3) | |
| cv2.putText(img,f"{i}",((b[0]+b[2])//2,(b[1]+b[3])//2),cv2.FONT_HERSHEY_PLAIN,1,(0,0,0,255)) | |
| c = cmap[-3].tolist() | |
| cv2.polylines(img, boundary.reshape(1, -1, 2), True, (c[0],c[1],c[2],255),3) | |
| c = cmap[-2].tolist() | |
| cv2.polylines(img, door.reshape(1, -1, 2), True, (c[0],c[1],c[2],255),3) | |
| if size!=(256,256): return cv2.resize(img,size) | |
| return img | |
| if __name__ == "__main__": | |
| pass | |