2020import sys
2121import numpy as np
2222import cv2 as cv
23+ import random
2324
2425
2526 # importing common Use modules
@@ -46,7 +47,8 @@ def __init__(self, detect_type = 'p'):
4647 # detector type
4748 self .matrix_inv = None # holds inverse params of the
4849 self .matrix_dir = None # direct u,v,1
49- self .matrix_xyz = None # direct u,v,1 multiplied by z
50+ self .matrix_xyz = None # direct u,v,1 multiplied by z
51+ self .matrix_index = None # index of the points in the original image
5052 self .plane_params = None # rvec not normalized
5153 self .plane_center = None # tvec
5254 #self.corner_ind = [0, 10, 40, 50] # corner of the rectnagle for the projection
@@ -56,6 +58,9 @@ def __init__(self, detect_type = 'p'):
5658 self .MIN_SPLIT_SIZE = 32
5759 self .MIN_STD_ERROR = 0.01
5860
61+ # color for the mask
62+ self .color_mask = (0 ,255 ,0 ) # green
63+
5964 # help variable
6065 self .ang_vec = np .zeros ((3 ,1 )) # help variable
6166
@@ -95,6 +100,10 @@ def preprocess(self, img = None):
95100
96101 if self .rect is None : # use entire image
97102 self .rect = self .init_roi (4 )
103+
104+ # init params of the inverse
105+ if self .matrix_dir is None :
106+ self .fit_plane_init ()
98107
99108 x0 , y0 , x1 , y1 = self .rect
100109 if len (img .shape ) > 2 :
@@ -223,6 +232,38 @@ def fit_plane_init(self):
223232 self .cam_matrix = np .array ([[650 ,0 ,self .frame_size [0 ]/ 2 ],[0 ,650 ,self .frame_size [1 ]/ 2 ],[0 ,0 ,1 ]], dtype = np .float32 )
224233 self .cam_distort = np .array ([0 ,0 ,0 ,0 ,0 ],dtype = np .float32 )
225234
235+ x0 ,y0 ,x1 ,y1 = 0 ,0 ,self .frame_size [1 ],self .frame_size [0 ] #self.rect
236+ h ,w = y1 - y0 , x1 - x0
237+ x_grid = np .arange (x0 , x1 , 1 )
238+ y_grid = np .arange (y0 , y1 , 1 )
239+ x , y = np .meshgrid (x_grid , y_grid )
240+
241+ # remember corner indexes for reprojection [0 .... h*(w-1))
242+ # . .
243+ # h ......h*w-1]
244+ #self.corner_ind = [0, h, h*w-1, h*(w-1), 0]
245+ #h2,w2 = h>>1, w>>1
246+ #self.rect_3d = [[-w,-h,0],[w,-h,0],[w,h,0],[-w,h,0],[-w,-h,0]]
247+
248+ # camera coordinates
249+ xy = np .hstack ((x .reshape (- 1 ,1 ),y .reshape (- 1 ,1 )))
250+ xy = np .expand_dims (xy , axis = 1 ).astype (np .float32 )
251+ xy_undistorted = cv .undistortPoints (xy , self .cam_matrix , self .cam_distort )
252+
253+ u = xy_undistorted [:,0 ,0 ].reshape ((h ,w )).reshape (- 1 ,1 )
254+ v = xy_undistorted [:,0 ,1 ].reshape ((h ,w )).reshape (- 1 ,1 )
255+
256+ # check
257+ #u, v = u*self.cam_matrix[0,0], v*self.cam_matrix[1,1]
258+
259+ self .matrix_dir = np .hstack ((u ,v ,u * 0 + 1 ))
260+ #self.matrix_inv = np.linalg.pinv(self.matrix_dir)
261+
262+ def fit_plane_init_old (self ):
263+ "prepares data for real time fit a*x+b*y+c = z"
264+ self .cam_matrix = np .array ([[650 ,0 ,self .frame_size [0 ]/ 2 ],[0 ,650 ,self .frame_size [1 ]/ 2 ],[0 ,0 ,1 ]], dtype = np .float32 )
265+ self .cam_distort = np .array ([0 ,0 ,0 ,0 ,0 ],dtype = np .float32 )
266+
226267 x0 ,y0 ,x1 ,y1 = self .rect
227268 h ,w = y1 - y0 , x1 - x0
228269 x_grid = np .arange (x0 , x1 , 1 )
@@ -250,7 +291,50 @@ def fit_plane_init(self):
250291 self .matrix_dir = np .hstack ((u ,v ,u * 0 + 1 ))
251292 self .matrix_inv = np .linalg .pinv (self .matrix_dir )
252293
253- def convert_roi_to_points (self , img_roi , point_num = 30 , step_size = 1 ):
294+ def convert_roi_to_points (self , img , point_num = 30 , step_size = 1 , roi_rect = None ):
295+ "converting roi to pts in XYZ - Nx3 array. point_num - is the target point number"
296+
297+ # init params of the inverse
298+ if self .matrix_dir is None :
299+ self .fit_plane_init ()
300+
301+ # deal iwth different rect options
302+ roi_rect = self .rect if roi_rect is None else roi_rect
303+
304+ # extract roi - must be compatible with image dimensions
305+ n ,m = img .shape [:2 ]
306+ img_roi_mask = np .zeros ((n ,m ), dtype = np .bool_ )
307+ x0 , y0 , x1 , y1 = roi_rect
308+ img_roi_mask [y0 :y1 ,x0 :x1 ] = 1
309+ valid_bool = img_roi_mask > 0
310+ valid_bool = valid_bool .flatten ()
311+ #log.info(f'Timing : 1')
312+
313+ # rect to show
314+ h ,w = y1 - y0 , x1 - x0
315+ self .rect_3d = [[- w ,- h ,0 ],[w ,- h ,0 ],[w ,h ,0 ],[- w ,h ,0 ],[- w ,- h ,0 ]]
316+
317+ # all non valid
318+ ii = np .where (valid_bool )[0 ]
319+ valid_point_num = len (ii )
320+ if valid_point_num < 5 :
321+ return None
322+ step_size = np .maximum (step_size , np .int32 (valid_point_num / point_num ))
323+ ii = ii [::step_size ]
324+
325+ # plane params - using only valid
326+ z = img .flat [ii ].reshape ((- 1 ,1 ))
327+ xyz_matrix = self .matrix_dir [ii ,:]
328+ xyz_matrix [:,:3 ] = xyz_matrix [:,:3 ]* z # keep 1 intact
329+
330+ #self.plane_center = xyz_center.flatten()
331+ self .matrix_xyz = xyz_matrix
332+ self .matrix_index = ii
333+
334+ return xyz_matrix
335+
336+
337+ def convert_roi_to_points_old (self , img_roi , point_num = 30 , step_size = 1 ):
254338 "converting roi to pts in XYZ - Nx3 array. point_num - is the target point number"
255339 # x1,y1 = self.img_xyz.shape[:2]
256340 # roi_area = x1*y1
@@ -267,8 +351,10 @@ def convert_roi_to_points(self, img_roi, point_num = 30, step_size = 1):
267351 #
268352
269353 # init params of the inverse
270- if self .matrix_inv is None :
271- self .fit_plane_init ()
354+ if self .matrix_dir is None :
355+ self .fit_plane_init_old ()
356+
357+ # extract roi
272358
273359 n ,m = img_roi .shape [:2 ]
274360 img_roi = img_roi .reshape ((- 1 ,1 ))
@@ -291,7 +377,10 @@ def convert_roi_to_points(self, img_roi, point_num = 30, step_size = 1):
291377
292378 # update corners of the rect in 3d
293379 #self.rect_3d = self.matrix_dir[self.corner_ind,:]*img_roi[self.corner_ind]
294-
380+ # rect to show
381+ x0 , y0 , x1 , y1 = self .rect
382+ h ,w = y1 - y0 , x1 - x0
383+ self .rect_3d = [[- w ,- h ,0 ],[w ,- h ,0 ],[w ,h ,0 ],[- w ,h ,0 ],[- w ,- h ,0 ]]
295384 # substract mean
296385 #xyz_center = xyz_matrix[:,:3].mean(axis=0)
297386 #xyz_matrix = xyz_matrix - xyz_center
@@ -332,7 +421,8 @@ def fit_plane_svd(self, img_roi):
332421 #self.rect_3d = self.matrix_dir[self.corner_ind,:]*img_roi[self.corner_ind]
333422
334423 # roi converted to points with step size on the grid
335- xyz_matrix = self .convert_roi_to_points (img_roi , point_num = 1e4 , step_size = 1 )
424+ #xyz_matrix = self.convert_roi_to_points(img_roi, point_num = 1e4, step_size = 1)
425+ xyz_matrix = self .convert_roi_to_points_old (img_roi , point_num = 1e4 , step_size = 1 )
336426
337427 # substract mean
338428 xyz_center = xyz_matrix [:,:3 ].mean (axis = 0 )
@@ -374,7 +464,7 @@ def fit_plane_with_outliers(self, img_roi):
374464 "computes normal for the specifric roi and evaluates error. Do it twice to reject outliers"
375465
376466 # roi converted to points with step size on the grid
377- xyz_matrix = self .convert_roi_to_points (img_roi , point_num = 250 , step_size = 0 )
467+ xyz_matrix = self .convert_roi_to_points_old (img_roi , point_num = 250 , step_size = 0 )
378468
379469 # substract mean
380470 xyz_center = xyz_matrix [:,:3 ].mean (axis = 0 )
@@ -439,12 +529,16 @@ def fit_plane_ransac(self, img_roi):
439529 """
440530 #log.info('Fit ransac: ...')
441531 # roi converted to points with step size on the grid
532+ #xyz_matrix = self.convert_roi_to_points_old(img_roi, point_num = 250, step_size = 1)
442533 xyz_matrix = self .convert_roi_to_points (img_roi , point_num = 250 , step_size = 1 )
534+ if xyz_matrix is None :
535+ log .error ('No points in the ROI' )
536+ return 0 , 0
443537
444- thresh = 0 .05
538+ thresh = 1 .05
445539 maxIteration = 100
446540
447- import random
541+
448542 n_points = xyz_matrix .shape [0 ]
449543 best_eq = []
450544 best_inliers = []
@@ -525,8 +619,12 @@ def fit_plane_ransac_and_grow(self, img_full):
525619 """
526620 Find the best equation for a plane of the predefined ROI and then grow the ROI
527621 """
528- img_roi = self .preprocess (img_full )
529- img_mean , img_std = self .fit_plane_ransac (img_roi )
622+ h ,w = img_full .shape [:2 ]
623+ # start from the original ROI
624+ if self .img_mask is None :
625+ isOk = self .init_image (img_full )
626+
627+ img_mean , img_std = self .fit_plane_ransac (img_full )
530628
531629 # make sure that mask is not empty
532630 x0 , y0 , x1 , y1 = self .rect
@@ -540,28 +638,44 @@ def fit_plane_ransac_and_grow(self, img_full):
540638 x_min , x_max = np .maximum (0 ,x_min - 1 ), np .minimum (self .img_mask .shape [1 ],x_max + 1 )
541639
542640 # extract ROI
543- img_roi = img_full [y_min :y_max ,x_min :x_max ].astype (np .float32 )
544- xyz_matrix = self .convert_roi_to_points (img_roi , point_num = 250 , step_size = 1 )
641+ roi_rect = [x_min , y_min , x_max , y_max ]
642+ #img_roi = img_full[y_min:y_max,x_min:x_max].astype(np.float32)
643+ xyz_matrix = self .convert_roi_to_points (img_full , point_num = 5000 , step_size = 1 , roi_rect = roi_rect )
545644
546- # check against the plane
645+ # check against the plane : do not substract plane.center from all the points
547646 vecC = self .plane_params [:3 ]
548- dist_pt = np .dot (xyz_matrix , vecC ) + self .plane_params [3 ]
647+ dist_offset = np .dot (self .plane_center , vecC )
648+ dist_pt = np .dot (xyz_matrix , vecC ) - dist_offset
549649
550650 # Select indexes where distance is biggers than the threshold
551- thresh = 0.05
651+ thresh = 1.5
552652 err = np .abs (dist_pt )
553- yi ,xi = np .where ( err <= thresh )
554- yi ,xi = yi + y_min , xi + x_min
653+ i2 = np .where ( err <= thresh )[0 ]
654+
655+
656+ # transfer xi,yi coordinates to the original image index
657+ ii = self .matrix_index [i2 ] # convert to 2D index
658+
659+ # # Convert 2D index to flat index:
660+ # row, col = 2, 1
661+ # flat_index = np.ravel_multi_index((row, col), arr.shape) # flat_index = 9
662+
663+ # # Convert flat index back to 2D index:
664+ # row, col = np.unravel_index(flat_index, arr.shape) # (2, 1)
665+
666+ self .img_mask .flat [ii ] = self .img_mask .flat [ii ] + 0.1 * (1 - self .img_mask .flat [ii ])
555667
556668
669+ # position in 2d array
670+ # unravel_index(a.argmax(), a.shape)
671+
557672 # output
558673 img_std = err .std ()
559- img_mean = xyz_matrix .mean (axis = 0 )[2 ]
674+ img_mean = xyz_matrix [ i2 ] .mean (axis = 0 )[2 ]
560675
561676
562677 return img_mean , img_std
563678
564-
565679 def fit_and_split_roi_recursively (self , roi , level = 0 ):
566680 # splits ROI on 4 regions and recursevly call
567681 x0 ,y0 ,x1 ,y1 = roi
@@ -615,11 +729,15 @@ def find_planes(self, img):
615729
616730 img_mean , img_std = 0 ,0
617731 if detect_type == 'P' :
618- img_mean , img_std = self .fit_plane_svd (img_roi )
732+ img_mean , img_std = self .fit_plane_svd (img )
619733 elif detect_type == 'O' :
620- img_mean , img_std = self .fit_plane_with_outliers (img_roi )
734+ img_mean , img_std = self .fit_plane_svd (img_roi )
735+ #img_mean, img_std = self.fit_plane_with_outliers(img_roi)
621736 elif detect_type == 'R' :
622- img_mean , img_std = self .fit_plane_ransac (img_roi )
737+ img_mean , img_std = self .fit_plane_ransac (img )
738+ elif detect_type == 'G' :
739+ img_mean , img_std = self .fit_plane_ransac_and_grow (img )
740+
623741
624742 #log.debug(f'camera noise - roi mean : {img_mean}')
625743 self .img_mean = img_mean # final measurements per frame
0 commit comments