Amirhosein commited on
Commit
ef6a23f
·
1 Parent(s): 0aa5112

added axis

Browse files
Files changed (3) hide show
  1. Axis.py +191 -0
  2. axis_finder.py +0 -9
  3. requirements.txt +0 -1
Axis.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+ from Map import MapIn, CVLineThickness
4
+ import random
5
+ import config
6
+
7
+ class AxisFinder:
8
+ clicked_points = []
9
+ def __init__(self,map:MapIn) -> None:
10
+ self.map = map
11
+ self.axis_res = []
12
+
13
+ """
14
+ opencv click callback for customized axis drawing
15
+ """
16
+ def click_callback(event, x, y, flags, params):
17
+ if event == cv2.EVENT_LBUTTONDOWN:
18
+ config.log(f"Clicked Y:{y}, X:{x}")
19
+ AxisFinder.clicked_points.append((y,x))
20
+
21
+ """
22
+ parts parcel number divider based on area of
23
+ parts. omits fixed facility areas
24
+ """
25
+ def cal_split_parcels(u_map:MapIn,d_map:MapIn,parcels_cnt:int):
26
+ u_ff_area = np.sum(u_map.facility_filled_mask)/255
27
+ u_block_area = np.sum(u_map.block_mask)/255
28
+ u_area = u_block_area - u_ff_area
29
+ d_ff_area = np.sum(d_map.facility_filled_mask)/255
30
+ d_block_area = np.sum(d_map.block_mask)/255
31
+ d_area = d_block_area - d_ff_area
32
+ t_area = u_area+d_area
33
+
34
+ precnt = u_area/t_area
35
+ u_parcels = int(parcels_cnt*precnt)
36
+ d_parcels = parcels_cnt - u_parcels
37
+ return (u_parcels,d_parcels)
38
+ """
39
+ sort results by best fitness
40
+ """
41
+ def sort_fitness(self,sub_li):
42
+ return sub_li.sort(key = lambda x: x[0])
43
+
44
+ """
45
+ calculates access balance ratio with the provided up&down masks
46
+ max value of fitness is 1
47
+ """
48
+ def cal_access_split_fitness(self,access_mask:np.ndarray,up_mask:np.ndarray,down_mask:np.ndarray):
49
+ img = access_mask
50
+ # calculate access ratio
51
+ up_sum_mask = up_mask & img
52
+ down_sum_mask = down_mask & img
53
+
54
+ sum_up_access = np.sum(up_sum_mask)/255
55
+ sum_down_access = np.sum(down_sum_mask)/255
56
+ return 1 - (abs(sum_up_access-sum_down_access)/(np.sum(img)/255))
57
+ """
58
+ calculates area balance ratio with provided up&down masks
59
+ max value of fitness is 1
60
+ """
61
+ def cal_area_split_fitness(self,block_mask:np.ndarray,up_mask:np.ndarray,down_mask:np.ndarray):
62
+ imgray = block_mask
63
+ up_area = up_mask & imgray
64
+ down_area = down_mask & imgray
65
+ sum_up_area = np.sum(up_area)/255
66
+ sum_down_area = np.sum(down_area)/255
67
+ return 1 - (abs(sum_up_area-sum_down_area)/(np.sum(imgray)/255))
68
+ """
69
+ calculates fixed facility hit
70
+ best answer is 1
71
+ """
72
+ def cal_fixed_facilities_fitness(self,facility_mask:np.ndarray,p0:tuple,p1:tuple):
73
+ imgray = facility_mask
74
+ plain = np.zeros((imgray.shape))
75
+ thickness = self.map.roud_thickness + self.map.facility_safe_dist
76
+ # input points are (y,x)->(x,y)
77
+ plain = cv2.line(plain,(p0[1],p0[0]),(p1[1],p1[0]),255,CVLineThickness.thickness_solver(thickness))
78
+ collision = plain.astype(np.uint8) & imgray
79
+ max_collision = np.sum(imgray)/255
80
+ if max_collision == 0: return 1
81
+ collision = np.sum(collision)/255
82
+ return 1 - (collision/max_collision)
83
+ """
84
+ calculates cut trees with given points
85
+ no cut tree = 1
86
+ """
87
+ def cal_carbon_fitness(self,tree_mask:np.ndarray,p0:tuple,p1:tuple):
88
+ mask = tree_mask
89
+ plain = np.zeros((mask.shape))
90
+ thickness = self.map.roud_thickness + self.map.tree_safe_dist
91
+ # input points are (y,x)->(x,y)
92
+ plain = cv2.line(plain,(p0[1],p0[0]),(p1[1],p1[0]),255,CVLineThickness.thickness_solver(thickness))
93
+ collision = plain.astype(np.uint8) & mask
94
+ # frame must be preprocessed
95
+ max_carbon = np.sum(mask)
96
+ if max_carbon == 0: return (1,0)
97
+ return (1-(np.sum(mask[collision>0])/max_carbon),len(mask[collision>0]))
98
+ """
99
+ axis finding fitness function
100
+ """
101
+ def fitness_axis(self,solution:tuple,mymap:MapIn,center:tuple):
102
+ # solution is y,x of one point
103
+ # other point is the center
104
+ y_max = mymap.frame_shape[0]-1
105
+ x_max = mymap.frame_shape[1]-1
106
+ # slope = inf, x=const
107
+ if solution[1]==center[1]:
108
+ point0 = (0,center[1])
109
+ point1 = (y_max,center[1])
110
+ # slope = zero, y=const
111
+ elif solution[0]==center[0]:
112
+ point0 = (center[0],0)
113
+ point1 = (center[0],x_max)
114
+ # normal line
115
+ else:
116
+ slope = (solution[0]-center[0])/(solution[1]-center[1])
117
+ intercept = center[0] - (slope*center[1])
118
+ point0 = (int(intercept),0)
119
+ point1 = (int((slope*x_max)+intercept),x_max)
120
+
121
+ # config.log(point1,point0)
122
+ up_mask,down_mask = mymap.line_split_mask_maker(point0,point1)
123
+ access_split_fitness = self.cal_access_split_fitness(mymap.access_mask,up_mask,down_mask)
124
+ area_split_fitness = self.cal_area_split_fitness(mymap.block_mask,up_mask,down_mask)
125
+ fixed_facilities_fitness = self.cal_fixed_facilities_fitness(mymap.fixed_f_mask,point0,point1)
126
+ carbon_fitness = self.cal_carbon_fitness(mymap.trees_mask,point0,point1)
127
+
128
+ # config.log(solution,slope,intercept,point0,point1)
129
+ weights = config.A_ACCESS_SPLIT_WEIGHT + config.A_AREA_SPLIT_WEIGHT + config.A_FIXED_FACILITIES_WEIGHT + config.A_CARBON_WEIGHT
130
+ score = (config.A_ACCESS_SPLIT_WEIGHT * access_split_fitness + config.A_AREA_SPLIT_WEIGHT * area_split_fitness +
131
+ config.A_FIXED_FACILITIES_WEIGHT * fixed_facilities_fitness + config.A_CARBON_WEIGHT * carbon_fitness[0])
132
+
133
+ # scale score between (0,1]
134
+ if fixed_facilities_fitness != 1:
135
+ return (-1,point0,point1)
136
+ return (score/weights,point0,point1,solution,center,[access_split_fitness,area_split_fitness,fixed_facilities_fitness,carbon_fitness])
137
+ """
138
+ iterate through all border pixels and
139
+ draw line on start_point to border
140
+ finding best line (for the first step of axis finding only)
141
+ """
142
+ def iterate_throughall(self,mymap:MapIn, start_point=None):
143
+ borders_access = []
144
+ if start_point != None:
145
+ borders_access = [start_point]
146
+ else:
147
+ borders_access = mymap.access_mask
148
+ borders_access = np.asarray(np.where(borders_access==255))
149
+ borders_access = list(zip(borders_access[0], borders_access[1]))
150
+
151
+ borders_random = mymap.boundry_mask
152
+ borders_random = np.asarray(np.where(borders_random==255))
153
+ borders_random = list(zip(borders_random[0], borders_random[1]))
154
+ borders_random = random.sample(borders_random, int(len(borders_random)*0.4))
155
+
156
+ res = []
157
+ for pixel in borders_access:
158
+ for second_point in borders_random:
159
+ if np.linalg.norm(np.asarray(pixel)-np.asarray(second_point)) > config.VALID_POINT_DISTANCE:
160
+ res.append(self.fitness_axis(pixel,mymap,second_point))
161
+ self.sort_fitness(res)
162
+ self.axis_res = res[-10:]
163
+ return res[-10:]
164
+
165
+ """
166
+ iterate over old boundries (without division line)
167
+ and find best line for New York design
168
+ """
169
+ def iterate_old_boundries_new_york(self):
170
+ res = []
171
+ last_axis_points = self.map.line_points
172
+ boundary = self.map.old_boundry_mask
173
+ boundary = np.asarray(np.where(boundary==255))
174
+ boundary = list(zip(boundary[0], boundary[1]))
175
+ # cal perpendicular center (pixelhit line)
176
+ for pixel in boundary:
177
+ y1, x1 = last_axis_points[0]
178
+ y2, x2 = last_axis_points[1]
179
+ y3, x3 = pixel
180
+ px, py = (x2-x1,y2-y1)
181
+ dAB = px*px + py*py
182
+ u = ((x3 - x1) * px + (y3 - y1) * py) / dAB
183
+ # (y,x)
184
+ ppcenter = (int(y1 + u * py),int(x1 + u * px))
185
+
186
+ if np.linalg.norm(np.asarray(pixel)-np.asarray(ppcenter)) > config.VALID_POINT_DISTANCE:
187
+ res.append(self.fitness_axis(pixel,self.map,ppcenter))
188
+
189
+ self.sort_fitness(res)
190
+ self.axis_res = res[-10:]
191
+ return res[-10:]
axis_finder.py CHANGED
@@ -1,7 +1,6 @@
1
  from Map import MapIn,MapOut
2
  from Axis import AxisFinder
3
  import cv2
4
- import pickle
5
  import config
6
  import time
7
 
@@ -110,11 +109,6 @@ def run_axis_finder(total_execution_time):
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------")
@@ -122,9 +116,6 @@ def run_axis_finder(total_execution_time):
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
 
1
  from Map import MapIn,MapOut
2
  from Axis import AxisFinder
3
  import cv2
 
4
  import config
5
  import time
6
 
 
109
  # sort maps by size
110
  maps_list.sort(key=lambda x: x.curr_size,reverse=True)
111
  cv2.destroyAllWindows()
 
 
 
 
 
112
 
113
  # export split result
114
  config.log(f"------Axis Result------")
 
116
  export_map.draw_axis()
117
  export_map.draw_collision()
118
  export_map.report()
 
 
 
119
 
120
  config.log("--- Axis Finder Finished In %s seconds ---" % (time.time() - start_time))
121
  total_execution_time += time.time() - start_time
requirements.txt CHANGED
@@ -1,6 +1,5 @@
1
  numpy
2
  pandas
3
  opencv-python
4
- pickle
5
  pygad
6
  sympy
 
1
  numpy
2
  pandas
3
  opencv-python
 
4
  pygad
5
  sympy