Spaces:
Runtime error
Runtime error
Amirhosein
commited on
Commit
·
eb9da7f
1
Parent(s):
2177524
First try
Browse files- Map.py +493 -0
- app.py +12 -0
- axis_finder.py +142 -0
- config.py +124 -0
- inputs/.DS_Store +0 -0
- inputs/Sample_test120-70_FiFa_mask.bmp +0 -0
- inputs/Sample_test120-70_FiFa_mask_fringe.bmp +0 -0
- inputs/Sample_test120-70_boundry_mask.bmp +0 -0
- inputs/Sample_test120-70_boundry_mask_fringe.bmp +0 -0
- inputs/Sample_test120-70_total_map.bmp +0 -0
- inputs/Sample_test120-70_total_map_fringe.bmp +0 -0
- inputs/rectangle_6-15.bmp +0 -0
- inputs/white.bmp +0 -0
- outputs/.DS_Store +0 -0
Map.py
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import cv2
|
| 2 |
+
import numpy as np
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import random
|
| 5 |
+
from functools import singledispatchmethod
|
| 6 |
+
import math
|
| 7 |
+
import os
|
| 8 |
+
|
| 9 |
+
from sympy import false
|
| 10 |
+
import config
|
| 11 |
+
|
| 12 |
+
class MapIn:
|
| 13 |
+
# thickness configs
|
| 14 |
+
tree_safe_dist = config.TREE_SAFE_DIST
|
| 15 |
+
facility_safe_dist = config.FACILITY_SAFE_DIST
|
| 16 |
+
# parcel min area
|
| 17 |
+
parcel_minimum_area = config.AXIS_MIN_AREA
|
| 18 |
+
# ratio of access to boundry to stop halving
|
| 19 |
+
access_ratio = config.ACCESS_RATIO
|
| 20 |
+
|
| 21 |
+
"""
|
| 22 |
+
map class to handle raw inputs
|
| 23 |
+
RGB (round access, green factor, boundary)
|
| 24 |
+
Background is white by deafult
|
| 25 |
+
Black shows fixed facilities
|
| 26 |
+
"""
|
| 27 |
+
@singledispatchmethod
|
| 28 |
+
def __init__(self) -> None:
|
| 29 |
+
assert False, 'bad input'
|
| 30 |
+
@__init__.register(str)
|
| 31 |
+
def _first__(self,src:str,src_block:str,src_ff:str,parcel_cnt:int,arch_choice:config.ArchStyles,map_id:int) -> None:
|
| 32 |
+
self.roud_thickness = config.ROAD_SIZE_MAX
|
| 33 |
+
self.map_id = map_id
|
| 34 |
+
self.frame = cv2.imread(src)
|
| 35 |
+
self.frame_shape = self.frame.shape
|
| 36 |
+
self.arch_choice = arch_choice
|
| 37 |
+
self.parcel_cnt = parcel_cnt
|
| 38 |
+
self.centers = (int(self.frame_shape[0]/2),int(self.frame_shape[1]/2))
|
| 39 |
+
self.trees_mask, self.fixed_f_mask,self.access_mask, self.boundry_mask = self.create_masks()
|
| 40 |
+
self.trees_binary_mask = cv2.threshold(self.trees_mask, 127, 255, cv2.THRESH_BINARY)[1]
|
| 41 |
+
# read block mask
|
| 42 |
+
self.block_mask = cv2.imread(src_block)
|
| 43 |
+
self.block_mask = cv2.cvtColor(self.block_mask,cv2.COLOR_BGR2GRAY)
|
| 44 |
+
# read facility filled mask
|
| 45 |
+
self.facility_filled_mask = cv2.imread(src_ff)
|
| 46 |
+
self.facility_filled_mask = cv2.cvtColor(self.facility_filled_mask,cv2.COLOR_BGR2GRAY)
|
| 47 |
+
self.print_report()
|
| 48 |
+
|
| 49 |
+
# Axis maps initialization
|
| 50 |
+
@__init__.register(np.ndarray)
|
| 51 |
+
def _second__(self,split_mask:np.ndarray,parent_map,line_mask:np.ndarray,map_id:int,dir:int,line_p) -> None:
|
| 52 |
+
self.line_p = line_p
|
| 53 |
+
# self.axis_center = parent_map.axis_center
|
| 54 |
+
self.split_mask = split_mask
|
| 55 |
+
self.dir = dir # 0 up 1 down
|
| 56 |
+
self.roud_thickness = config.ROAD_SIZE_MAX - config.ROAD_STEP*int(math.log(map_id+1,2))
|
| 57 |
+
if self.roud_thickness <= config.ROAD_STEP: self.roud_thickness=config.ROAD_SIZE_MIN
|
| 58 |
+
config.log(f"roud thickness:{self.roud_thickness} map_id:{map_id}")
|
| 59 |
+
self.map_id = map_id
|
| 60 |
+
# split_mask_3d = np.zeros((self.frame_shape))
|
| 61 |
+
# self.frame = parent_map.frame & split_mask
|
| 62 |
+
split_3d_mask = np.zeros(parent_map.frame_shape, dtype=np.uint8)
|
| 63 |
+
split_3d_mask[:,:,:] = split_mask[:,:,np.newaxis]
|
| 64 |
+
self.frame = parent_map.frame & split_3d_mask
|
| 65 |
+
self.frame_shape = self.frame.shape
|
| 66 |
+
self.arch_choice = parent_map.arch_choice
|
| 67 |
+
self.centers = (int(self.frame_shape[0]/2),int(self.frame_shape[1]/2))
|
| 68 |
+
self.trees_mask = parent_map.trees_mask & split_mask
|
| 69 |
+
self.trees_binary_mask = parent_map.trees_binary_mask & split_mask
|
| 70 |
+
self.fixed_f_mask = parent_map.fixed_f_mask & split_mask
|
| 71 |
+
self.boundry_mask = parent_map.boundry_mask & split_mask
|
| 72 |
+
self.old_boundry_mask = parent_map.boundry_mask & split_mask
|
| 73 |
+
self.block_mask = parent_map.block_mask & split_mask
|
| 74 |
+
self.facility_filled_mask = parent_map.facility_filled_mask & split_mask
|
| 75 |
+
# add new line to access
|
| 76 |
+
new_access_line = self.block_mask & line_mask
|
| 77 |
+
self.access_mask = parent_map.access_mask & split_mask
|
| 78 |
+
self.access_mask = self.access_mask | new_access_line
|
| 79 |
+
# add new line to boundries
|
| 80 |
+
self.boundry_mask = self.boundry_mask | new_access_line
|
| 81 |
+
self.new_access_line = new_access_line
|
| 82 |
+
if map_id > 2:
|
| 83 |
+
self.parent_access_line = parent_map.new_access_line
|
| 84 |
+
self.parent_line_p = parent_map.line_p
|
| 85 |
+
else:
|
| 86 |
+
self.parent_access_line = self.new_access_line
|
| 87 |
+
self.parent_line_p = self.line_p
|
| 88 |
+
self.save_map()
|
| 89 |
+
self.print_report()
|
| 90 |
+
|
| 91 |
+
# Parcels initilization
|
| 92 |
+
@__init__.register(int)
|
| 93 |
+
def _third__(self,parcel_id:int,split_mask:np.ndarray,parent_map,parcel_area,lines_points_tup,parcel_type) -> None:
|
| 94 |
+
self.dir = parent_map.dir
|
| 95 |
+
self.parent_line_p = parent_map.parent_line_p
|
| 96 |
+
self.line_p = parent_map.line_p
|
| 97 |
+
self.parent_access_line = parent_map.parent_access_line & split_mask
|
| 98 |
+
self.access_line = parent_map.new_access_line & split_mask
|
| 99 |
+
self.parcel_id = parcel_id
|
| 100 |
+
self.curr_size = parcel_area
|
| 101 |
+
self.bounding_lines = lines_points_tup
|
| 102 |
+
self.parcel_type = parcel_type
|
| 103 |
+
self.map_id = parent_map.map_id
|
| 104 |
+
split_3d_mask = np.zeros(parent_map.frame_shape, dtype=np.uint8)
|
| 105 |
+
split_3d_mask[:,:,:] = split_mask[:,:,np.newaxis]
|
| 106 |
+
self.frame = parent_map.frame & split_3d_mask
|
| 107 |
+
self.frame_shape = self.frame.shape
|
| 108 |
+
self.arch_choice = parent_map.arch_choice
|
| 109 |
+
self.trees_mask = parent_map.trees_mask & split_mask
|
| 110 |
+
self.trees_binary_mask = parent_map.trees_binary_mask & split_mask
|
| 111 |
+
self.fixed_f_mask = parent_map.fixed_f_mask & split_mask
|
| 112 |
+
self.boundry_mask = parent_map.boundry_mask & split_mask
|
| 113 |
+
self.block_mask = parent_map.block_mask & split_mask
|
| 114 |
+
self.facility_filled_mask = parent_map.facility_filled_mask & split_mask
|
| 115 |
+
# make center of new parcel
|
| 116 |
+
block_mask = self.block_mask.astype(np.uint8)
|
| 117 |
+
contours, _ = cv2.findContours(block_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
|
| 118 |
+
cnts = sorted(contours, key=cv2.contourArea, reverse=True)
|
| 119 |
+
M = cv2.moments(cnts[0])
|
| 120 |
+
cX = int(M["m10"] / M["m00"])
|
| 121 |
+
cY = int(M["m01"] / M["m00"])
|
| 122 |
+
self.parcel_center = (cY,cX)
|
| 123 |
+
# self.save_map()
|
| 124 |
+
self.print_report()
|
| 125 |
+
|
| 126 |
+
def print_report(self):
|
| 127 |
+
config.log(f"Map {self.map_id} Area : {np.sum(self.block_mask)/255}")
|
| 128 |
+
config.log(f"Map {self.map_id} Tree Area : {np.sum(self.trees_binary_mask)/255}")
|
| 129 |
+
config.log(f"Map {self.map_id} Fixed-Facility Area : {np.sum(self.facility_filled_mask)/255}")
|
| 130 |
+
config.log(f"Map {self.map_id} Sparse Area : {np.sum(self.block_mask & np.bitwise_not(self.facility_filled_mask) & np.bitwise_not(self.trees_binary_mask))/255}")
|
| 131 |
+
|
| 132 |
+
def set_map_axis_center(self,point):
|
| 133 |
+
self.axis_center = point
|
| 134 |
+
def set_line_point(self,point:tuple):
|
| 135 |
+
self.line_points = point
|
| 136 |
+
|
| 137 |
+
def save_map(self) -> None:
|
| 138 |
+
if config.WRITE_UNNECESSARY:
|
| 139 |
+
cv2.imwrite(f'outputs/map{self.map_id}.bmp',self.frame)
|
| 140 |
+
cv2.imwrite(f'outputs/access_mask{self.map_id}.bmp',self.access_mask)
|
| 141 |
+
cv2.imwrite(f'outputs/boundry_mask{self.map_id}.bmp',self.boundry_mask)
|
| 142 |
+
|
| 143 |
+
def create_masks(self) -> tuple:
|
| 144 |
+
res = []
|
| 145 |
+
img_re = self.frame.reshape(-1,3)
|
| 146 |
+
df = pd.DataFrame(img_re,columns=['b','g','r'])
|
| 147 |
+
df['r'].astype(np.uint8)
|
| 148 |
+
df['g'].astype(np.uint8)
|
| 149 |
+
df['b'].astype(np.uint8)
|
| 150 |
+
|
| 151 |
+
indx_trees = df.apply(lambda x: x.b==0 and 0<x.g<=255 and x.r==0, axis=1)
|
| 152 |
+
df_trees = df.copy()
|
| 153 |
+
df_trees[np.logical_not(indx_trees)] = [0,0,0]
|
| 154 |
+
# df_trees[indx_trees] = [255,255,255]
|
| 155 |
+
out = df_trees.values.reshape(self.frame_shape)
|
| 156 |
+
out = out.astype(np.uint8)
|
| 157 |
+
out[:,:,0] = 0
|
| 158 |
+
out[:,:,2] = 0
|
| 159 |
+
out = cv2.threshold(out, 127, 255, cv2.THRESH_BINARY)[1][:,:,1]
|
| 160 |
+
res.append(out)
|
| 161 |
+
cv2.imwrite('outputs/tree_mask.bmp',out)
|
| 162 |
+
|
| 163 |
+
indx_fixed_fac = df.apply(lambda x: x.b==0 and x.g==0 and x.r==0, axis=1)
|
| 164 |
+
df_ff = df.copy()
|
| 165 |
+
df_ff[np.logical_not(indx_fixed_fac)] = [0,0,0]
|
| 166 |
+
df_ff[indx_fixed_fac] = [255,255,255]
|
| 167 |
+
out = df_ff.values.reshape(self.frame_shape)
|
| 168 |
+
out = out.astype(np.uint8)
|
| 169 |
+
out = cv2.cvtColor(out,cv2.COLOR_BGR2GRAY)
|
| 170 |
+
res.append(out)
|
| 171 |
+
cv2.imwrite('outputs/facility_mask.bmp',out)
|
| 172 |
+
|
| 173 |
+
indx_access = df.apply(lambda x: x.g==0 and x.r==255, axis=1)
|
| 174 |
+
df_ac = df.copy()
|
| 175 |
+
df_ac[np.logical_not(indx_access)] = [0,0,0]
|
| 176 |
+
df_ac[indx_access] = [255,255,255]
|
| 177 |
+
out = df_ac.values.reshape(self.frame_shape)
|
| 178 |
+
out = out.astype(np.uint8)
|
| 179 |
+
out = cv2.cvtColor(out,cv2.COLOR_BGR2GRAY)
|
| 180 |
+
res.append(out)
|
| 181 |
+
cv2.imwrite('outputs/access_mask.bmp',out)
|
| 182 |
+
|
| 183 |
+
indx_boundry = df.apply(lambda x: x.b==255 and x.g==0, axis=1)
|
| 184 |
+
df_b = df.copy()
|
| 185 |
+
df_b[np.logical_not(indx_boundry)] = [0,0,0]
|
| 186 |
+
df_b[indx_boundry] = [255,255,255]
|
| 187 |
+
out = df_b.values.reshape(self.frame_shape)
|
| 188 |
+
out = out.astype(np.uint8)
|
| 189 |
+
out = cv2.cvtColor(out,cv2.COLOR_BGR2GRAY)
|
| 190 |
+
res.append(out)
|
| 191 |
+
cv2.imwrite('outputs/boundary_mask.bmp',out)
|
| 192 |
+
return tuple(res)
|
| 193 |
+
|
| 194 |
+
def correct_input(self) -> None:
|
| 195 |
+
img_re = self.frame.reshape(-1,3)
|
| 196 |
+
df = pd.DataFrame(img_re,columns=['b','g','r'])
|
| 197 |
+
df['r'].astype(np.uint8)
|
| 198 |
+
df['g'].astype(np.uint8)
|
| 199 |
+
df['b'].astype(np.uint8)
|
| 200 |
+
# ----set tree values to random
|
| 201 |
+
random.seed(13)
|
| 202 |
+
df = df.apply(lambda x: [0,random.randint(1,255),0] if x['b']==0 and x['g']==255 and x['r']==0 else x,axis=1)
|
| 203 |
+
# ----convert white to black
|
| 204 |
+
# indx = df.apply(lambda x: x['b']==255 and x['g']==255 and x['r']==255,axis=1)
|
| 205 |
+
# df[indx] = [0,0,0]
|
| 206 |
+
# ----set rgb(0,255,255) to rgb(255,0,255)
|
| 207 |
+
# indx = df.apply(lambda x: x['b']==255 and x['g']==255 and x['r']==0,axis=1)
|
| 208 |
+
# df[indx] = [255,0,255]
|
| 209 |
+
# ----save output
|
| 210 |
+
out = df.values.reshape(self.frame_shape)
|
| 211 |
+
out = out.astype(np.uint8)
|
| 212 |
+
cv2.imwrite('outputs/kan_pre.bmp',out)
|
| 213 |
+
self.frame = out
|
| 214 |
+
# ----print
|
| 215 |
+
# cv2.imshow("kan_pre_out", out)
|
| 216 |
+
# cv2.waitKey(0)
|
| 217 |
+
# cv2.destroyAllWindows()
|
| 218 |
+
|
| 219 |
+
"""
|
| 220 |
+
returns above the line mask and below the line mask
|
| 221 |
+
"""
|
| 222 |
+
def line_split_mask_maker(self,p0:tuple,p1:tuple):
|
| 223 |
+
# points are (y,x) oriented
|
| 224 |
+
img_pixels = self.frame_shape[0]*self.frame_shape[1]
|
| 225 |
+
img_x = self.frame_shape[1]
|
| 226 |
+
# numpy image is (y*x*3)
|
| 227 |
+
# !! unit16 may not be enough
|
| 228 |
+
y_index = (np.arange(img_pixels).reshape(self.frame_shape[:2])/img_x).astype(np.uint32)
|
| 229 |
+
x_index = np.arange(img_pixels).reshape(self.frame_shape[:2])%img_x
|
| 230 |
+
if p1[1] == p0[1]:
|
| 231 |
+
up_down_line = x_index - p0[1]
|
| 232 |
+
else:
|
| 233 |
+
slope = (p1[0]-p0[0])/(p1[1]-p0[1])
|
| 234 |
+
intercept = p0[0] - (slope*p0[1])
|
| 235 |
+
up_down_line = x_index*slope + intercept - y_index
|
| 236 |
+
# down part (becareful about center)
|
| 237 |
+
down_mask = np.where(up_down_line>=0,255,0).reshape(self.frame_shape[:2])
|
| 238 |
+
up_mask = np.where(up_down_line>=0,0,255).reshape(self.frame_shape[:2])
|
| 239 |
+
return (up_mask,down_mask)
|
| 240 |
+
"""
|
| 241 |
+
returns only line mask on main image
|
| 242 |
+
"""
|
| 243 |
+
def line_mask_maker(self,p0:tuple,p1:tuple):
|
| 244 |
+
plain = np.zeros((self.block_mask.shape))
|
| 245 |
+
plain = cv2.line(plain,(p0[1],p0[0]),(p1[1],p1[0]),255,2)
|
| 246 |
+
return plain.astype(np.uint8)
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
"""
|
| 250 |
+
check whether the half map has a feasible condition
|
| 251 |
+
or supports the finishing condtion.
|
| 252 |
+
"""
|
| 253 |
+
def isfeasible(self):
|
| 254 |
+
# check if the part has more than 60% access
|
| 255 |
+
access = np.sum(self.access_mask)/255
|
| 256 |
+
boundry = np.sum(self.boundry_mask)/255
|
| 257 |
+
access_ratio = access/boundry
|
| 258 |
+
access_cond = access_ratio<self.access_ratio
|
| 259 |
+
# area of part not smaller than standard
|
| 260 |
+
block_size = np.sum(self.block_mask)/255
|
| 261 |
+
size_cond = block_size>self.parcel_minimum_area
|
| 262 |
+
config.log(f'block size:{block_size} access_ratio:{access_ratio} map_id:{self.map_id}')
|
| 263 |
+
self.curr_access = access_ratio
|
| 264 |
+
self.curr_size = block_size
|
| 265 |
+
return access_cond and size_cond
|
| 266 |
+
|
| 267 |
+
class CVLineThickness:
|
| 268 |
+
"""
|
| 269 |
+
method selects cv2line arg
|
| 270 |
+
depending on the pixel width
|
| 271 |
+
"""
|
| 272 |
+
@staticmethod
|
| 273 |
+
def thickness_solver(desired_thickness):
|
| 274 |
+
if desired_thickness == 1:
|
| 275 |
+
return 1
|
| 276 |
+
if desired_thickness == 2:
|
| 277 |
+
# assert false, f"change road size or road step to odd number: {desired_thickness}"
|
| 278 |
+
return 2
|
| 279 |
+
if desired_thickness == 3:
|
| 280 |
+
return 2
|
| 281 |
+
if desired_thickness % 2 == 0:
|
| 282 |
+
# assert false, f"change road size or road step to odd number: {desired_thickness}"
|
| 283 |
+
return desired_thickness - 1
|
| 284 |
+
|
| 285 |
+
return desired_thickness - 2
|
| 286 |
+
|
| 287 |
+
|
| 288 |
+
class MapOut:
|
| 289 |
+
def __init__(self,src:str,lines_axis:list) -> None:
|
| 290 |
+
self.img = cv2.imread(src)
|
| 291 |
+
self.img_axised = self.img.copy()
|
| 292 |
+
self.img_partitioned = None
|
| 293 |
+
self.img_built = None
|
| 294 |
+
self.img_last = None
|
| 295 |
+
self.axis_lines = lines_axis
|
| 296 |
+
self.partitioning_lines = None
|
| 297 |
+
self.parcels_dic = {}
|
| 298 |
+
self.building_masks = None
|
| 299 |
+
# export details
|
| 300 |
+
self.total_carbon = 0
|
| 301 |
+
self.total_trees = 0
|
| 302 |
+
self.total_carbon_loss = 0
|
| 303 |
+
self.total_cut_tree = 0
|
| 304 |
+
self.total_axis_length = 0
|
| 305 |
+
self.total_axis_per_block_pr = 0
|
| 306 |
+
self.total_num_parcels = 0
|
| 307 |
+
self.total_num_parcels_types = {p_type:0 for p_type in config.ParcelType._member_names_}
|
| 308 |
+
self.total_sum_ff = 0
|
| 309 |
+
|
| 310 |
+
def reset_map_for_partitioning(self):
|
| 311 |
+
self.total_num_parcels = 0
|
| 312 |
+
self.total_num_parcels_types = {p_type:0 for p_type in config.ParcelType._member_names_}
|
| 313 |
+
self.total_sum_ff = 0
|
| 314 |
+
self.partitioning_lines = None
|
| 315 |
+
if self.img_partitioned is not None:
|
| 316 |
+
self.img_partitioned = None
|
| 317 |
+
self.img_last = self.img_axised.copy()
|
| 318 |
+
|
| 319 |
+
def reset_map_for_location_finding(self):
|
| 320 |
+
self.total_sum_ff = 0
|
| 321 |
+
self.building_masks = None
|
| 322 |
+
if self.img_built is not None:
|
| 323 |
+
self.img_built = None
|
| 324 |
+
self.img_last = self.img_partitioned.copy()
|
| 325 |
+
|
| 326 |
+
def add_partition_report(self,report):
|
| 327 |
+
self.total_num_parcels += report['cnt']
|
| 328 |
+
report.pop('cnt')
|
| 329 |
+
for p_type in report.keys():
|
| 330 |
+
self.total_num_parcels_types[p_type] += report[p_type]
|
| 331 |
+
|
| 332 |
+
def report(self):
|
| 333 |
+
self.block_mask = cv2.imread(config.MAIN_MAP_FILLED_BLOCK_MASK)
|
| 334 |
+
self.tree_mask = cv2.imread('outputs/tree_mask.bmp')
|
| 335 |
+
self.binary_tree_mask = cv2.threshold(self.tree_mask, 127, 255, cv2.THRESH_BINARY)[1]
|
| 336 |
+
self.facility_filled_mask = cv2.imread(config.MAIN_MAP_FILLED_F_F_MASK)
|
| 337 |
+
# total trees carbon
|
| 338 |
+
self.total_carbon = np.sum(self.tree_mask)/3
|
| 339 |
+
self.total_trees = np.sum(self.binary_tree_mask)/(255*3)
|
| 340 |
+
# calculate tree cut and carbon
|
| 341 |
+
self.img_last = self.img_last & self.block_mask
|
| 342 |
+
self.img_last = self.img_last.astype(np.uint8)
|
| 343 |
+
self.img_mask = cv2.threshold(self.img_last, 127, 255, cv2.THRESH_BINARY)[1]
|
| 344 |
+
# omit roads mask and building mask from it
|
| 345 |
+
self.roads_mask = cv2.imread('outputs/roads_mask.bmp')
|
| 346 |
+
collision3dmask = self.roads_mask
|
| 347 |
+
if os.path.exists('outputs/buildings_mask.bmp'):
|
| 348 |
+
collision3dmask = collision3dmask | cv2.imread('outputs/buildings_mask.bmp')
|
| 349 |
+
if os.path.exists('outputs/partitioning_mask.bmp'):
|
| 350 |
+
collision3dmask = collision3dmask | cv2.imread('outputs/partitioning_mask.bmp')
|
| 351 |
+
cv2.imwrite('outputs/constructed_mask.bmp', collision3dmask)
|
| 352 |
+
self.total_carbon_loss = np.sum(collision3dmask & self.tree_mask)/3
|
| 353 |
+
self.total_cut_tree = np.sum(collision3dmask & self.binary_tree_mask)/(255*3)
|
| 354 |
+
config.log(f"Total Trees:{self.total_trees} Total Carbon Values:{self.total_carbon}")
|
| 355 |
+
config.log(f"Total Cut Trees:{self.total_cut_tree} Total Carbon Loss:{self.total_carbon_loss}")
|
| 356 |
+
config.log(f"Total Cut Precentage:{self.total_cut_tree/self.total_trees}")
|
| 357 |
+
# calculate axis reports
|
| 358 |
+
img_re = self.img_last.reshape(-1,3)
|
| 359 |
+
df = pd.DataFrame(img_re,columns=['b','g','r'])
|
| 360 |
+
df['r'].astype(np.uint8)
|
| 361 |
+
df['g'].astype(np.uint8)
|
| 362 |
+
df['b'].astype(np.uint8)
|
| 363 |
+
indx_axis = df.apply(lambda x:x.g == 0 and 0<x.r<=255 and x.b == 0, axis=1)
|
| 364 |
+
df_axis = df.copy()
|
| 365 |
+
df_axis[np.logical_not(indx_axis)] = [0,0,0]
|
| 366 |
+
out = df_axis.values.reshape(self.img_last.shape)
|
| 367 |
+
out = out.astype(np.uint8)
|
| 368 |
+
out = cv2.cvtColor(out,cv2.COLOR_BGR2GRAY)
|
| 369 |
+
out = cv2.threshold(out, 1, 255, cv2.THRESH_BINARY)[1]
|
| 370 |
+
self.total_axis_length = np.sum(out)/255
|
| 371 |
+
self.total_axis_per_block_pr = self.total_axis_length / (np.sum(self.block_mask)/(255*3))
|
| 372 |
+
sparse_area = np.sum(self.block_mask & np.bitwise_not(self.facility_filled_mask) & np.bitwise_not(self.binary_tree_mask))/(255*3)
|
| 373 |
+
self.total_axis_per_sparse_pr = self.total_axis_length / sparse_area
|
| 374 |
+
config.log(f"Total Axis Area:{self.total_axis_length}")
|
| 375 |
+
config.log(f"Total Block Area:{np.sum(self.block_mask)/(255*3)}")
|
| 376 |
+
config.log(f"Total Sparse Area:{sparse_area}")
|
| 377 |
+
config.log(f"Total Axis Per Block Precentage:{self.total_axis_per_block_pr}")
|
| 378 |
+
config.log(f"Total Axis Per Sparse Precentage:{self.total_axis_per_sparse_pr}")
|
| 379 |
+
# Parcels number plus types
|
| 380 |
+
config.log(f"Total Parcels:{self.total_num_parcels}")
|
| 381 |
+
config.log(f"Total Parcel types:{self.total_num_parcels_types}")
|
| 382 |
+
config.log(f"Total Parcels With FF:{self.total_sum_ff}")
|
| 383 |
+
|
| 384 |
+
|
| 385 |
+
|
| 386 |
+
def draw_axis(self):
|
| 387 |
+
for line in self.axis_lines:
|
| 388 |
+
p0=line[0][0]
|
| 389 |
+
p1=line[0][1]
|
| 390 |
+
thickness=config.ROAD_SIZE_MAX - config.ROAD_STEP*int(math.log(line[1]+1,2))
|
| 391 |
+
if thickness <= config.ROAD_SIZE_MIN:
|
| 392 |
+
thickness=config.ROAD_SIZE_MIN
|
| 393 |
+
# draw line of axis
|
| 394 |
+
self.img_axised = cv2.line(self.img_axised,(p0[1],p0[0]),(p1[1],p1[0]),(0,0,127),CVLineThickness.thickness_solver(thickness+2))
|
| 395 |
+
# rotate points
|
| 396 |
+
self.img_axised = cv2.line(self.img_axised,(p0[1],p0[0]),(p1[1],p1[0]),(0,0,255),CVLineThickness.thickness_solver(thickness))
|
| 397 |
+
cv2.imwrite('outputs/final_axis.bmp',self.img_axised)
|
| 398 |
+
# save road lines mask
|
| 399 |
+
img_re = self.img_axised.reshape(-1,3).copy()
|
| 400 |
+
df = pd.DataFrame(img_re,columns=['b','g','r'])
|
| 401 |
+
df['r'].astype(np.uint8)
|
| 402 |
+
df['g'].astype(np.uint8)
|
| 403 |
+
df['b'].astype(np.uint8)
|
| 404 |
+
indx_axis = df.apply(lambda x:x.g == 0 and 0<x.r<=255 and x.b == 0, axis=1)
|
| 405 |
+
df[np.logical_not(indx_axis)] = [0,0,0]
|
| 406 |
+
out = df.values.reshape(self.img_axised.shape)
|
| 407 |
+
out = out.astype(np.uint8)
|
| 408 |
+
out = cv2.cvtColor(out,cv2.COLOR_BGR2GRAY)
|
| 409 |
+
out = cv2.threshold(out, 1, 255, cv2.THRESH_BINARY)[1]
|
| 410 |
+
self.img_last = self.img_axised.copy()
|
| 411 |
+
cv2.imwrite('outputs/roads_mask.bmp', out)
|
| 412 |
+
|
| 413 |
+
def draw_partitions(self,iteration:int,map:MapIn,lines_parcels:list):
|
| 414 |
+
map_id = map.map_id
|
| 415 |
+
if lines_parcels is not None:
|
| 416 |
+
self.parcels_dic[map_id] = lines_parcels
|
| 417 |
+
lines_mask = np.zeros(self.img_last.shape, dtype=np.uint8)
|
| 418 |
+
for line in lines_parcels:
|
| 419 |
+
p0=line[0]
|
| 420 |
+
p1=line[1]
|
| 421 |
+
# rotate points
|
| 422 |
+
lines_mask = cv2.line(lines_mask,(p0[1],p0[0]),(p1[1],p1[0]),(120,120,120),1)
|
| 423 |
+
split_3d_mask = np.zeros(self.img_last.shape, dtype=np.uint8)
|
| 424 |
+
split_3d_mask[:,:,:] = map.block_mask[:,:,np.newaxis]
|
| 425 |
+
lines_mask = lines_mask & split_3d_mask
|
| 426 |
+
self.img_partitioned = self.img_last.astype(np.uint8) & np.bitwise_not(lines_mask)
|
| 427 |
+
# write partitioning mask
|
| 428 |
+
lines_mask = np.where(lines_mask>0,(255,255,255), (0,0,0))
|
| 429 |
+
if self.partitioning_lines is not None:
|
| 430 |
+
self.partitioning_lines |= lines_mask
|
| 431 |
+
else:
|
| 432 |
+
self.partitioning_lines = lines_mask
|
| 433 |
+
if config.WRITE_UNNECESSARY:
|
| 434 |
+
cv2.imwrite(f'outputs/final_map_{iteration}_{map_id}.bmp',self.img_partitioned)
|
| 435 |
+
self.img_last = self.img_partitioned.copy()
|
| 436 |
+
|
| 437 |
+
def draw_partitioning_results(self):
|
| 438 |
+
cv2.imwrite(f'outputs/partitioning_mask.bmp',self.partitioning_lines)
|
| 439 |
+
cv2.imwrite(f'outputs/final_map_partitioning.bmp',self.img_partitioned)
|
| 440 |
+
|
| 441 |
+
|
| 442 |
+
def draw_building(self,building_mask,iteration,map_id,parcel_id,has_building,parcel_type,block_mask):
|
| 443 |
+
color3d_mask = np.zeros(self.img_last.shape, dtype=np.uint8)
|
| 444 |
+
color3d_mask[:,:,:] = block_mask[:,:,np.newaxis]
|
| 445 |
+
if has_building:
|
| 446 |
+
self.total_sum_ff += 1
|
| 447 |
+
color3d_mask = np.where(color3d_mask>0,(100,100,100),(255,255,255))
|
| 448 |
+
elif parcel_type == config.ParcelType.O:
|
| 449 |
+
color3d_mask = np.where(color3d_mask>0,(0,255,255),(255,255,255))
|
| 450 |
+
elif parcel_type == config.ParcelType.A:
|
| 451 |
+
color3d_mask = np.where(color3d_mask>0,(51,255,255),(255,255,255))
|
| 452 |
+
elif parcel_type == config.ParcelType.B:
|
| 453 |
+
color3d_mask = np.where(color3d_mask>0,(102,255,255),(255,255,255))
|
| 454 |
+
elif parcel_type == config.ParcelType.C:
|
| 455 |
+
color3d_mask = np.where(color3d_mask>0,(153,255,255),(255,255,255))
|
| 456 |
+
elif parcel_type == config.ParcelType.U:
|
| 457 |
+
color3d_mask = np.where(color3d_mask>0,(40,0,255),(255,255,255))
|
| 458 |
+
|
| 459 |
+
build3d_mask = np.zeros(self.img.shape, dtype=np.uint8)
|
| 460 |
+
build3d_mask[:,:,:] = building_mask[:,:,np.newaxis]
|
| 461 |
+
if self.building_masks is not None:
|
| 462 |
+
self.building_masks &= build3d_mask
|
| 463 |
+
self.img_last &= self.img_partitioned & build3d_mask
|
| 464 |
+
self.img_built &= self.img_partitioned & build3d_mask & color3d_mask
|
| 465 |
+
else:
|
| 466 |
+
self.building_masks = build3d_mask
|
| 467 |
+
self.img_last = self.img_partitioned & build3d_mask
|
| 468 |
+
self.img_built = self.img_partitioned & build3d_mask & color3d_mask
|
| 469 |
+
if config.WRITE_UNNECESSARY:
|
| 470 |
+
cv2.imwrite(f'outputs/final_map_{iteration}_{map_id}_{parcel_id}.bmp',self.img_built)
|
| 471 |
+
|
| 472 |
+
def draw_building_results(self):
|
| 473 |
+
cv2.imwrite(f'outputs/buildings_mask.bmp',np.bitwise_not(self.building_masks))
|
| 474 |
+
cv2.imwrite(f'outputs/final_map_location_finding.bmp',self.img_built)
|
| 475 |
+
|
| 476 |
+
|
| 477 |
+
def draw_collision(self):
|
| 478 |
+
trees_mask = cv2.imread('outputs/tree_mask.bmp')
|
| 479 |
+
fixed_facility_mask = cv2.imread('outputs/facility_mask.bmp')
|
| 480 |
+
roads_mask = cv2.imread('outputs/roads_mask.bmp')
|
| 481 |
+
collide_mask = roads_mask
|
| 482 |
+
if os.path.exists('outputs/buildings_mask.bmp'):
|
| 483 |
+
collide_mask |= cv2.imread('outputs/buildings_mask.bmp')
|
| 484 |
+
if os.path.exists('outputs/partitioning_mask.bmp'):
|
| 485 |
+
collide_mask |= cv2.imread('outputs/partitioning_mask.bmp')
|
| 486 |
+
# change here when building mask is av
|
| 487 |
+
collision3dmask = trees_mask | fixed_facility_mask
|
| 488 |
+
collision3dmask = collide_mask & collision3dmask
|
| 489 |
+
img = self.img_last.copy()
|
| 490 |
+
pixels = [100,50,100]*int(len(img[collision3dmask>0])/3)
|
| 491 |
+
img[collision3dmask>0] = pixels
|
| 492 |
+
|
| 493 |
+
cv2.imwrite(f'outputs/collision_map.bmp',img)
|
app.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from axis_finder import gradio_inference
|
| 3 |
+
|
| 4 |
+
def run_axis_finder(input_str):
|
| 5 |
+
input_str = input_str.split(' ')
|
| 6 |
+
return gradio_inference(input_str[0], input_str[1], input_str[2])
|
| 7 |
+
|
| 8 |
+
demo = gr.Interface(
|
| 9 |
+
run_axis_finder,
|
| 10 |
+
gr.Textbox(value="Road Access[0.1:0.9], Starting Point(y,x), Carbon Prefix[0:7], \n exp:0.7 (44, 119) 2"),
|
| 11 |
+
"image")
|
| 12 |
+
demo.launch()
|
axis_finder.py
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from Map import MapIn,MapOut
|
| 2 |
+
from Axis import AxisFinder
|
| 3 |
+
import cv2
|
| 4 |
+
import pickle
|
| 5 |
+
import config
|
| 6 |
+
import time
|
| 7 |
+
|
| 8 |
+
def run_axis_finder(total_execution_time):
|
| 9 |
+
maps_list = []
|
| 10 |
+
lines_list = []
|
| 11 |
+
axis_division_cond = True
|
| 12 |
+
maps_processing_queue = []
|
| 13 |
+
map_id = 0
|
| 14 |
+
iteration = 0
|
| 15 |
+
# axis finding process (1.1)
|
| 16 |
+
config.log_axis_finding_settings()
|
| 17 |
+
config.log(f"------Axis Finder------")
|
| 18 |
+
start_time = time.time()
|
| 19 |
+
while axis_division_cond:
|
| 20 |
+
config.log(f"----Step {iteration}----")
|
| 21 |
+
if (map_id == 0):
|
| 22 |
+
# read map and make masks
|
| 23 |
+
mymap = MapIn(config.MAIN_MAP_ADDR,config.MAIN_MAP_FILLED_BLOCK_MASK,config.MAIN_MAP_FILLED_F_F_MASK,
|
| 24 |
+
config.PARCELS_COUNT,config.ARCH,map_id=map_id)
|
| 25 |
+
# set random values for carbon
|
| 26 |
+
# mymap.correct_input()
|
| 27 |
+
else:
|
| 28 |
+
mymap = maps_processing_queue.pop(0)
|
| 29 |
+
|
| 30 |
+
# makes axis_finder object to split
|
| 31 |
+
myaxis = AxisFinder(mymap)
|
| 32 |
+
# Arch Selection on start division is the same
|
| 33 |
+
if mymap.arch_choice == config.ArchStyles.Customized:
|
| 34 |
+
# axis_center = myaxis.get_center(mymap.block_mask)
|
| 35 |
+
# mymap.set_map_axis_center(axis_center)
|
| 36 |
+
cv2.imshow(f'Map{mymap.map_id}', mymap.frame)
|
| 37 |
+
cv2.setMouseCallback(f'Map{mymap.map_id}', AxisFinder.click_callback)
|
| 38 |
+
cv2.waitKey(0)
|
| 39 |
+
cv2.destroyAllWindows()
|
| 40 |
+
p_f = AxisFinder.clicked_points.pop(0)
|
| 41 |
+
p_s = AxisFinder.clicked_points.pop(0)
|
| 42 |
+
points=[]
|
| 43 |
+
points.append((1,p_f,p_s,p_f,p_s))
|
| 44 |
+
elif map_id == 0 and mymap.arch_choice == config.ArchStyles.Human_Centered_AI:
|
| 45 |
+
p_f = ()
|
| 46 |
+
if config.ARCH_FIRST_INPUT == None:
|
| 47 |
+
cv2.imshow(f'Map{mymap.map_id}', mymap.frame)
|
| 48 |
+
cv2.setMouseCallback(f'Map{mymap.map_id}', AxisFinder.click_callback)
|
| 49 |
+
cv2.waitKey(0)
|
| 50 |
+
cv2.destroyAllWindows()
|
| 51 |
+
p_f = AxisFinder.clicked_points.pop(0)
|
| 52 |
+
else:
|
| 53 |
+
p_f = config.ARCH_FIRST_INPUT
|
| 54 |
+
points = myaxis.iterate_throughall(mymap,p_f)
|
| 55 |
+
elif map_id == 0:
|
| 56 |
+
points = myaxis.iterate_throughall(mymap)
|
| 57 |
+
else:
|
| 58 |
+
points = myaxis.iterate_old_boundries_new_york()
|
| 59 |
+
|
| 60 |
+
# dump axis if hit fixed_facility
|
| 61 |
+
if points[-1][0] == -1:
|
| 62 |
+
if not maps_processing_queue:
|
| 63 |
+
axis_division_cond = False
|
| 64 |
+
continue
|
| 65 |
+
|
| 66 |
+
# draw the found line carbon_fitness
|
| 67 |
+
config.log(f"Map div best score:{points[-1][0]} map_id:{mymap.map_id}")
|
| 68 |
+
config.log(f"Map div best access split fitness:{points[-1][5][0]}")
|
| 69 |
+
config.log(f"Map div best area split fitness:{points[-1][5][1]}")
|
| 70 |
+
config.log(f"Map div best fixed facilities fitness:{points[-1][5][2]}")
|
| 71 |
+
config.log(f"Map div best carbon fitness:{points[-1][5][3]}")
|
| 72 |
+
|
| 73 |
+
lines_list.append((points[-1][3:5],mymap.map_id))
|
| 74 |
+
# make map for split two parts (add line as access)
|
| 75 |
+
split_mask_u,split_mask_d = mymap.line_split_mask_maker(points[-1][1],points[-1][2])
|
| 76 |
+
line_mask = mymap.line_mask_maker(points[-1][1],points[-1][2])
|
| 77 |
+
up_map = MapIn(split_mask_u,mymap,line_mask,map_id+1,0,points[-1][1:3])
|
| 78 |
+
down_map = MapIn(split_mask_d,mymap,line_mask,map_id+2,1,points[-1][1:3])
|
| 79 |
+
parcels = AxisFinder.cal_split_parcels(up_map,down_map,mymap.parcel_cnt)
|
| 80 |
+
up_map.parcel_cnt,down_map.parcel_cnt = parcels
|
| 81 |
+
config.log(f"Map:{map_id+1} Parcels:{up_map.parcel_cnt}")
|
| 82 |
+
config.log(f"Map:{map_id+2} Parcels:{down_map.parcel_cnt}")
|
| 83 |
+
# check finishing condition
|
| 84 |
+
up_feasibility, down_feasibility = (up_map.isfeasible(), down_map.isfeasible())
|
| 85 |
+
# add new maps to processing queue
|
| 86 |
+
if up_feasibility:
|
| 87 |
+
config.log(f"Map:{map_id+1} Added!")
|
| 88 |
+
up_map.set_line_point(points[-1][1:])
|
| 89 |
+
maps_processing_queue.append(up_map)
|
| 90 |
+
# was the last axis so add axis to final answer
|
| 91 |
+
else:
|
| 92 |
+
config.log(f"Map:{map_id+1} Added As Answer")
|
| 93 |
+
up_map.set_line_point(points[-1][1:])
|
| 94 |
+
maps_list.append(up_map)
|
| 95 |
+
if down_feasibility:
|
| 96 |
+
config.log(f"Map:{map_id+2} Added!")
|
| 97 |
+
down_map.set_line_point(points[-1][1:])
|
| 98 |
+
maps_processing_queue.append(down_map)
|
| 99 |
+
else:
|
| 100 |
+
config.log(f"Map:{map_id+2} Added As Answer")
|
| 101 |
+
down_map.set_line_point(points[-1][1:])
|
| 102 |
+
maps_list.append(down_map)
|
| 103 |
+
|
| 104 |
+
if not maps_processing_queue:
|
| 105 |
+
axis_division_cond = False
|
| 106 |
+
map_id += 2
|
| 107 |
+
iteration+=1
|
| 108 |
+
config.log('-'*8)
|
| 109 |
+
|
| 110 |
+
# sort maps by size
|
| 111 |
+
maps_list.sort(key=lambda x: x.curr_size,reverse=True)
|
| 112 |
+
cv2.destroyAllWindows()
|
| 113 |
+
# save maps
|
| 114 |
+
with open('outputs/maps_list.pickle', 'wb') as f:
|
| 115 |
+
pickle.dump(maps_list, f)
|
| 116 |
+
with open('outputs/lines_list.pickle', 'wb') as f:
|
| 117 |
+
pickle.dump(lines_list, f)
|
| 118 |
+
|
| 119 |
+
# export split result
|
| 120 |
+
config.log(f"------Axis Result------")
|
| 121 |
+
export_map = MapOut(config.MAIN_MAP_ADDR,lines_list)
|
| 122 |
+
export_map.draw_axis()
|
| 123 |
+
export_map.draw_collision()
|
| 124 |
+
export_map.report()
|
| 125 |
+
# save
|
| 126 |
+
with open('outputs/export_map.pickle', 'wb') as f:
|
| 127 |
+
pickle.dump(export_map, f)
|
| 128 |
+
|
| 129 |
+
config.log("--- Axis Finder Finished In %s seconds ---" % (time.time() - start_time))
|
| 130 |
+
total_execution_time += time.time() - start_time
|
| 131 |
+
return total_execution_time
|
| 132 |
+
|
| 133 |
+
def gradio_inference(access_ratio,start_point,carbon_weight):
|
| 134 |
+
config.ACCESS_RATIO = float(access_ratio)
|
| 135 |
+
config.ARCH_FIRST_INPUT = tuple(start_point)
|
| 136 |
+
config.A_CARBON_WEIGHT = int(carbon_weight)
|
| 137 |
+
run_axis_finder(0)
|
| 138 |
+
image = cv2.imread(f'outputs/collision_map.bmp')
|
| 139 |
+
return image
|
| 140 |
+
|
| 141 |
+
if __name__ == "__main__":
|
| 142 |
+
run_axis_finder(0)
|
config.py
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import enum
|
| 2 |
+
import datetime
|
| 3 |
+
# enum classes
|
| 4 |
+
class ArchStyles(enum.Enum):
|
| 5 |
+
New_York = 1
|
| 6 |
+
Human_Centered_AI = 2
|
| 7 |
+
Customized = 3
|
| 8 |
+
class ParcelType(enum.Enum):
|
| 9 |
+
O = 0 # oversize
|
| 10 |
+
A = 1
|
| 11 |
+
B = 2
|
| 12 |
+
C = 3
|
| 13 |
+
U = 4 # undersize
|
| 14 |
+
|
| 15 |
+
# main run input args
|
| 16 |
+
MAIN_MAP_ADDR = 'inputs/Sample_test120-70_total_map_fringe.bmp'
|
| 17 |
+
MAIN_MAP_FILLED_BLOCK_MASK = 'inputs/Sample_test120-70_boundry_mask_fringe.bmp'
|
| 18 |
+
MAIN_MAP_FILLED_F_F_MASK = 'inputs/Sample_test120-70_FiFa_mask_fringe.bmp'
|
| 19 |
+
PARCELS_COUNT = 12
|
| 20 |
+
ARCH = ArchStyles.Human_Centered_AI
|
| 21 |
+
ARCH_FIRST_INPUT = (44, 119) #(70, 120) #(Y,X) or None
|
| 22 |
+
|
| 23 |
+
# Axis finding args
|
| 24 |
+
VALID_POINT_DISTANCE = 10
|
| 25 |
+
ROAD_SIZE_MAX = 3 # can be: 1,3,5,7,...
|
| 26 |
+
ROAD_SIZE_MIN = 1 # can be: 1,3,5,...
|
| 27 |
+
ROAD_STEP = 2 # can be multiplication of 2
|
| 28 |
+
|
| 29 |
+
ACCESS_RATIO = 0.6 # 0.55 for newyork # 0.7 for star
|
| 30 |
+
|
| 31 |
+
AXIS_MIN_AREA = 1000 # 12000 for newyork # 75000 for star
|
| 32 |
+
|
| 33 |
+
FACILITY_SAFE_DIST = 2
|
| 34 |
+
TREE_SAFE_DIST = 1
|
| 35 |
+
|
| 36 |
+
# axis finder fitness weights
|
| 37 |
+
A_ACCESS_SPLIT_WEIGHT = 1
|
| 38 |
+
A_AREA_SPLIT_WEIGHT = 1
|
| 39 |
+
A_FIXED_FACILITIES_WEIGHT = 1
|
| 40 |
+
A_CARBON_WEIGHT = 1
|
| 41 |
+
|
| 42 |
+
# Partitioning args
|
| 43 |
+
PROCESSING_CORES = 8
|
| 44 |
+
|
| 45 |
+
P_GA_LOSS_THOLD = 0.3
|
| 46 |
+
|
| 47 |
+
TYPE_A_AREA = 700
|
| 48 |
+
TYPE_B_AREA = 500
|
| 49 |
+
TYPE_C_AREA = 400
|
| 50 |
+
|
| 51 |
+
TYPE_AREA_STEP = 100
|
| 52 |
+
|
| 53 |
+
# partiotioning fitness weights
|
| 54 |
+
P_FF_WEIGHT = 2
|
| 55 |
+
P_AREA_WEIGHT = 2
|
| 56 |
+
P_TREE_WEIGHT = 1
|
| 57 |
+
|
| 58 |
+
# location finding args
|
| 59 |
+
BUILDING_ADDR = ['inputs/rectangle_6-15.bmp','inputs/rectangle_6-15.bmp','inputs/rectangle_6-15.bmp','inputs/white.bmp']
|
| 60 |
+
BUILDING_BORDER_GAP = 10
|
| 61 |
+
|
| 62 |
+
# location finding fitness weights
|
| 63 |
+
L_DIST_WEIGHT = 1
|
| 64 |
+
L_OUT_BORDER_WEIGHT = 2
|
| 65 |
+
L_CARBON_WEIGHT = 1
|
| 66 |
+
L_ON_ROAD_WEIGHT = 2
|
| 67 |
+
|
| 68 |
+
def building_sel(p_type:ParcelType):
|
| 69 |
+
if p_type == ParcelType.O: return BUILDING_ADDR[0]
|
| 70 |
+
if p_type == ParcelType.A: return BUILDING_ADDR[0]
|
| 71 |
+
if p_type == ParcelType.B: return BUILDING_ADDR[1]
|
| 72 |
+
if p_type == ParcelType.C: return BUILDING_ADDR[2]
|
| 73 |
+
if p_type == ParcelType.U: return BUILDING_ADDR[3]
|
| 74 |
+
|
| 75 |
+
# output args and loggers
|
| 76 |
+
WRITE_UNNECESSARY = False
|
| 77 |
+
WRITE_LOGS = True
|
| 78 |
+
def log_axis_finding_settings():
|
| 79 |
+
log(f'====== Axis Finding inputs ======')
|
| 80 |
+
log(f'PARCELS_COUNT : {PARCELS_COUNT}')
|
| 81 |
+
log(f'ARCH : {ARCH}')
|
| 82 |
+
log(f'ARCH_FIRST_INPUT : {ARCH_FIRST_INPUT}')
|
| 83 |
+
log(f'VALID_POINT_DISTANCE : {VALID_POINT_DISTANCE}')
|
| 84 |
+
log(f'ROAD_SIZE_MAX : {ROAD_SIZE_MAX}')
|
| 85 |
+
log(f'ROAD_SIZE_MIN : {ROAD_SIZE_MIN}')
|
| 86 |
+
log(f'ROAD_STEP : {ROAD_STEP}')
|
| 87 |
+
log(f'ACCESS_RATIO : {ACCESS_RATIO}')
|
| 88 |
+
log(f'AXIS_MIN_AREA : {AXIS_MIN_AREA}')
|
| 89 |
+
log(f'FACILITY_SAFE_DIST : {FACILITY_SAFE_DIST}')
|
| 90 |
+
log(f'TREE_SAFE_DIST : {TREE_SAFE_DIST}')
|
| 91 |
+
log(f'A_ACCESS_SPLIT_WEIGHT : {A_ACCESS_SPLIT_WEIGHT}')
|
| 92 |
+
log(f'A_AREA_SPLIT_WEIGHT : {A_AREA_SPLIT_WEIGHT}')
|
| 93 |
+
log(f'A_FIXED_FACILITIES_WEIGHT : {A_FIXED_FACILITIES_WEIGHT}')
|
| 94 |
+
log(f'A_CARBON_WEIGHT : {A_CARBON_WEIGHT}')
|
| 95 |
+
def log_partitioning_settings():
|
| 96 |
+
log(f'====== Partitioning inputs ======')
|
| 97 |
+
log(f'PARCELS_COUNT : {PARCELS_COUNT}')
|
| 98 |
+
log(f'PROCESSING_CORES : {PROCESSING_CORES}')
|
| 99 |
+
log(f'P_GA_LOSS_THOLD : {P_GA_LOSS_THOLD}')
|
| 100 |
+
log(f'TYPE_A_AREA : {TYPE_A_AREA}')
|
| 101 |
+
log(f'TYPE_B_AREA : {TYPE_B_AREA}')
|
| 102 |
+
log(f'TYPE_C_AREA : {TYPE_C_AREA}')
|
| 103 |
+
log(f'TYPE_AREA_STEP : {TYPE_AREA_STEP}')
|
| 104 |
+
log(f'P_FF_WEIGHT : {P_FF_WEIGHT}')
|
| 105 |
+
log(f'P_AREA_WEIGHT : {P_AREA_WEIGHT}')
|
| 106 |
+
log(f'P_TREE_WEIGHT : {P_TREE_WEIGHT}')
|
| 107 |
+
def log_location_finding_settings():
|
| 108 |
+
log(f'====== Location Finding inputs ======')
|
| 109 |
+
log(f'PARCELS_COUNT : {PARCELS_COUNT}')
|
| 110 |
+
log(f'BUILDING_ADDR : {BUILDING_ADDR}')
|
| 111 |
+
log(f'BUILDING_BORDER_GAP : {BUILDING_BORDER_GAP}')
|
| 112 |
+
log(f'TYPE_A_AREA : {TYPE_A_AREA}')
|
| 113 |
+
log(f'TYPE_B_AREA : {TYPE_B_AREA}')
|
| 114 |
+
log(f'TYPE_C_AREA : {TYPE_C_AREA}')
|
| 115 |
+
log(f'TYPE_AREA_STEP : {TYPE_AREA_STEP}')
|
| 116 |
+
log(f'L_DIST_WEIGHT : {L_DIST_WEIGHT}')
|
| 117 |
+
log(f'L_OUT_BORDER_WEIGHT : {L_OUT_BORDER_WEIGHT}')
|
| 118 |
+
log(f'L_CARBON_WEIGHT : {L_CARBON_WEIGHT}')
|
| 119 |
+
log(f'L_ON_ROAD_WEIGHT : {L_ON_ROAD_WEIGHT}')
|
| 120 |
+
def log(msg):
|
| 121 |
+
if WRITE_LOGS:
|
| 122 |
+
with open('./outputs/logs.txt', 'a') as f:
|
| 123 |
+
f.writelines(f'{datetime.datetime.now()} : {str(msg)}\n')
|
| 124 |
+
print(str(msg))
|
inputs/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
inputs/Sample_test120-70_FiFa_mask.bmp
ADDED
|
inputs/Sample_test120-70_FiFa_mask_fringe.bmp
ADDED
|
inputs/Sample_test120-70_boundry_mask.bmp
ADDED
|
inputs/Sample_test120-70_boundry_mask_fringe.bmp
ADDED
|
inputs/Sample_test120-70_total_map.bmp
ADDED
|
inputs/Sample_test120-70_total_map_fringe.bmp
ADDED
|
inputs/rectangle_6-15.bmp
ADDED
|
inputs/white.bmp
ADDED
|
outputs/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|