44
55@author: andrewcorbato
66"""
7- def icp (model ,data ,* args ):
7+ def icp (model ,data ,* arg ):
88# ICP Iterative Closest Point Algorithm. Takes use of
99# Delaunay tesselation of points in model.
1010#
@@ -110,66 +110,83 @@ def icp(model,data,*args):
110110# To clear old global tesselation variables run: "clear global Tes ir jc" (tes_flag=1)
111111# or run: "clear global Tes Tesind Tesver" (tes_flag=2) in Command Window.
112112#
113- # m-file can be downloaded for free at
113+ # based on an m-file can be downloaded for free at
114114# http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=12627&objectType=FILE
115115#
116- # icp version 1.4
117116#
118- # written by Per Bergstrm 2007-03-07
119117
120118 import numpy as np
121119 import scipy as sp
122120 from numpy import matlib as ml
123121 from numpy import matrix as mx
122+ import sys
124123
125- if model == False and data == False :
126- import sys
127- sys .exit ('ERROR: Only one input. There must be at least two inputs.' )
128- elif model == False :
129- import sys
130- sys .exit ('ERROR: Model cannot be an empty matrix.' )
124+ if model .any () == False and data .any () == False :
125+ raise ValueError ('ERROR: Only one input. There must be at least two inputs.' )
126+ elif model .any () == False :
127+ raise ValueError ('ERROR: Model cannot be an empty matrix.' )
131128 global MODEL , DATA , TR , TT , TS
132129
133130 dims_model = np .shape (model )
134131 if dims_model [1 ]< dims_model [0 ]:
135- global MODEL
136132 MODEL = np .transpose (model )
137133 else :
138- global MODEL
139134 MODEL = model
140135
141136 dims_data = np .shape (data )
142137 if dims_data [1 ]< dims_data [0 ]:
143138 data = np .transpose (data )
144139 dims_data = np .shape (data )
145- global DATA
146140 DATA = data
147141 else :
148- global DATA
149142 DATA = data
150143
151144 if dims_data [0 ] is not dims_model [0 ]:
152- import sys
153- sys .exit ('ERROR: DATA and MODEL cannot have different dimensions.' )
154- # default options
155- if len (args ) == 0 :
156- options = {'max_iter' : 104 , 'min_iter' : 4 ,'fitting' : 2 ,'thres' : 1e-05 , \
145+ raise ValueError ('ERROR: DATA and MODEL cannot have different dimensions.' )
146+ # default options
147+ if not len (arg )== 0 :
148+ opt = arg [0 ]
149+ else :
150+ opt = {'max_iter' : 104 , 'min_iter' : 4 ,'fitting' : [2 ],'thres' : 1e-05 , \
157151 'init_flag' : 1 ,'tes_flag' : 1 , 'delta' : 10 ,'mode' : 'rigid' , \
158152 'refpnt' : np .array ([]),}
159- elif len (args ) != 9 :
160- import sys
161- sys .exit ('ERROR: Options dictionary must have 9 entries.' )
153+
154+ print (opt )
155+
156+ if not isinstance (opt , dict ):
157+ raise ValueError ("opt must be dictionary of options" )
158+ if not 'max_iter' in opt :
159+ opt ['max_iter' ] = 104 ;
160+ if not 'min_iter' in opt :
161+ opt ['min_iter' ] = 4 ;
162+ if not 'fitting' in opt :
163+ opt ['fitting' ] = [2 ];
164+ if not 'thres' in opt :
165+ opt ['thres' ] = 1e-5 ;
166+ if not 'delta' in opt :
167+ opt ['delta' ] = 10 ;
168+ if not 'mode' in opt :
169+ opt ['mode' ] = 'rigid' ;
170+ if not 'refpnt' in opt :
171+ opt ['refpnt' ] = np .array ([]);
172+ if not 'init_flag' in opt :
173+ opt ['init_flag' ] = 1 ;
174+ if not 'tes_flag' in opt :
175+ opt ['tes_flag' ] = 1 ;
176+
177+
178+
162179
163180# move options out of dictionary for ease of use
164- max_iter = args ['max_iter' ]
165- min_iter = args ['min_iter' ]
166- fitting = args ['fitting' ]
167- thres = args ['thres' ]
168- init_flag = args ['init_flag' ]
169- tes_flag = args ['tes_flag' ]
170- delta = args ['delta' ]
171- mode = args ['mode' ]
172- refpnt = args ['refpnt' ]
181+ max_iter = opt ['max_iter' ]
182+ min_iter = opt ['min_iter' ]
183+ fitting = opt ['fitting' ]
184+ thres = opt ['thres' ]
185+ init_flag = opt ['init_flag' ]
186+ tes_flag = opt ['tes_flag' ]
187+ delta = opt ['delta' ]
188+ mode = opt ['mode' ]
189+ refpnt = opt ['refpnt' ]
173190
174191# input error checks
175192 if (tes_flag != 0 and tes_flag != 1 and tes_flag != 2 and tes_flag != 3 ):
@@ -178,7 +195,7 @@ def icp(model,data,*args):
178195 must be 0-3.' )
179196 if dims_model [1 ] == dims_model [0 ] and tes_flag is not 0 :
180197 import sys
181- sys . exit ('ERROR: This icp method requires the number of model points \
198+ raise ValueError ('ERROR: This icp method requires the number of model points \
182199 to be greater than the dimension' )
183200 if max_iter < min_iter :
184201 max_iter = min_iter
@@ -309,9 +326,10 @@ def icp_init(init_flag,fitting):
309326 DATA = DATA + ml .repmat (TT ,1 ,N ) # apply transformation
310327 else :
311328 import sys
312- sys . exit ('ERROR: Wrong init_flag' )
329+ raise ValueError ('ERROR: Wrong init_flag' )
313330###############################################################################
314331def icp_struct (tes_flag ):
332+ global Tes , ir , jc , Tesind , Tesver
315333 if tes_flag != 3 :
316334 if tes_flag == 0 :
317335 global ir
@@ -321,15 +339,15 @@ def icp_struct(tes_flag):
321339 dims_Tesind = np .shape (Tesind )
322340 if dims_Tesind [0 ] == 0 :
323341 import sys
324- sys . exit ('ERROR: No tesselation system exists' )
342+ raise ValueError ('ERROR: No tesselation system exists' )
325343 else :
326344 tes_flag = 2
327345 else :
328346 tes_flag = 1
329347 elif tes_flag == 3 :
330348 return tes_flag
331349 else :
332- global MODEL , Tes
350+
333351 [m ,n ] = np .shape (MODEL )
334352 if m == 1 :
335353 ind1 = np .argsort (MODEL )
@@ -364,7 +382,6 @@ def icp_struct(tes_flag):
364382 Tes = np .sort (np .sort (Tes ,axis = 1 ),axis = 1 )
365383 [mT ,nT ] = np .shape (Tes )
366384 if tes_flag == 1 :
367- global ir , jc
368385 num = np .zeros ((1 ,n ))
369386 for jj in range (0 ,mT ,1 ):
370387 for kk in range (0 ,nT ,1 ):
@@ -381,7 +398,6 @@ def icp_struct(tes_flag):
381398 ir [ind [Tes [i ,j ]]] = i
382399 ind [Tes [i ,j ]] = ind [Tes [i ,j ]]+ 1
383400 else : # tes_flag ==2
384- global Tesind , Tesver
385401 Tesind = np .zeros (mT ,nT )
386402 Tesver = np .zeros (mT ,nT )
387403 couvec = np .zeros (mT ,1 )
@@ -458,8 +474,8 @@ def icp_closest_start(tes_flag,fitting):
458474# ICP_CLOSEST_START finds indexes of closest MODEL points for each point in DATA.
459475# The _start version allocates memory for iclosest and finds the closest MODEL points
460476# to the DATA points
477+ global MODEL , DATA , Tes , ir , jc , iclosest
461478 if tes_flag == 3 :
462- global MODEL , DATA , iclosest
463479 dims_MODEL = np .shape (MODEL )
464480 dims_DATA = np .shape (DATA )
465481 mm = dims_MODEL [1 ]
@@ -477,25 +493,24 @@ def icp_closest_start(tes_flag,fitting):
477493 ERROR += err (dist ,fitting ,ID )
478494
479495 elif tes_flag == 1 :
480- global MODEL , DATA , Tes , ir , jc , iclosest
481496 dims_DATA = np .shape (DATA )
482497 md = dims_DATA [1 ]
483498 dims_MODEL = np .shape (MODEL )
484499 iclosest = np .zeros ((1 ,md ))
485500 mid = np .round (md / 2 )
486- iclosest ( mid ) = np .round ((dims_MODEL [1 ]/ 2 ))
501+ iclosest [ mid ] = np .round ((dims_MODEL [1 ]/ 2 ))
487502 bol = 1
488503 while bol :
489504 bol = np .logical_not (bol )
490- distc = np .linalg .norm ((DATA [:,mid ]- MODEL [:,iclosest ( mid ) ]))
505+ distc = np .linalg .norm ((DATA [:,mid ]- MODEL [:,iclosest [ mid ] ]))
491506 distcc = 2 * distc
492507 for i in range (ir [jc [iclosest [mid ]]],ir [jc [iclosest [mid ]+ 1 ]- 1 ],1 ):
493508 for ind in Tes [i ,:]:
494509 distcc = np .linalg .norm ((DATA [:,mid ]- MODEL [:,ind ]))
495510 if distcc < distc :
496511 distc = distcc
497512 bol = np .logical_not (bol )
498- iclosest ( mid ) = ind
513+ iclosest [ mid ] = ind
499514 break
500515 if bol :
501516 break
@@ -514,7 +529,7 @@ def icp_closest_start(tes_flag,fitting):
514529 if distcc < distc :
515530 distc = distcc
516531 bol = np .logical_not (bol )
517- iclosest ( mid ) = ind
532+ iclosest [ mid ] = ind
518533 break
519534 if bol :
520535 break
@@ -533,10 +548,9 @@ def icp_closest_start(tes_flag,fitting):
533548 if distcc < distc :
534549 distc = distcc
535550 bol = np .logical_not (bol )
536- iclosest ( mid ) = ind
551+ iclosest [ mid ] = ind
537552 break
538553 else : # tes_flag == 2
539- global MODEL , DATA , Tes , Tesind , Tesver , icTesind , iclosest
540554 dims_DATA = np .shape (DATA )
541555 md = dims_DATA [1 ]
542556 iclosest = np .zeros ((1 ,md ))
@@ -691,8 +705,8 @@ def icp_transformation(fitting,refpnt,delta,optmode):
691705 b = np .concatenate (0 ,DATA [0 ,n ],0 ,0 ,DATA [1 ,n ],0 ,0 ,DATA [2 ,n ],0 ,0 ,1 ,0 , axis = 1 )
692706 c = np .concatenate (0 ,0 ,DATA [0 ,n ],0 ,0 ,DATA [1 ,n ],0 ,0 ,DATA [2 ,n ],0 ,0 ,1 , axis = 1 )
693707 P [ind ,:] = np .concatenate (a ,b ,c , axis = 0 )
694- q [ind ] = MODEL [0 :2 ,iclosest [p_ind [n ]]
695- ind + = 3
708+ q [ind ] = MODEL [0 :2 ,iclosest [p_ind [n ]]]
709+ ind = 3
696710 if mode == 'affine' :
697711 theta = q / P
698712 a_r = np .concatenate (theta [0 ],theta [3 ],theta [6 ],axis = 0 )
@@ -734,7 +748,7 @@ def err(dist,fitting,ind):
734748 ERR = dist ** 2
735749 else :
736750 ERR = 0
737- print (WARNING : Unknown fitting value .)
751+ print (' WARNING: Unknown fitting value.' )
738752 return ERR
739753###############################################################################
740754def weightfcn (distances ):
@@ -745,4 +759,4 @@ def weightfcn(distances):
745759 else :
746760 weights = max_distances + min_distances - distances
747761 weights = weights / np .sum (weights )
748- return weights
762+ return weights
0 commit comments