00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 import numpy as np
00037 import scipy
00038 import scipy.linalg
00039
00040
00041
00042
00043
00044
00045
00046 TEST_FOLDER ='/home/jokerman/svn/robot1_data/usr/martin/laser_camera_segmentation/labeling'
00047
00048 def ransac(data,model,n,k,t,d,debug=False,return_all=False):
00049 print 'INFO: running RANSAC for k=',k,'iterations'
00050 """fit model parameters to data using the RANSAC algorithm
00051
00052 This implementation written from pseudocode found at
00053 http://en.wikipedia.org/w/index.php?title=RANSAC&oldid=116358182
00054
00055 {{{
00056 Given:
00057 data - a set of observed data points
00058 model - a model that can be fitted to data points
00059 n - the minimum number of data values required to fit the model
00060 k - the maximum number of iterations allowed in the algorithm
00061 t - a threshold value for determining when a data point fits a model
00062 d - the number of close data values required to assert that a model fits well to data
00063 Return:
00064 bestfit - model parameters which best fit the data (or nil if no good model is found)
00065 iterations = 0
00066 bestfit = nil
00067 besterr = something really large
00068 while iterations < k {
00069 maybeinliers = n randomly selected values from data
00070 maybemodel = model parameters fitted to maybeinliers
00071 alsoinliers = empty set
00072 for every point in data not in maybeinliers {
00073 if point fits maybemodel with an error smaller than t
00074 add point to alsoinliers
00075 }
00076 if the number of elements in alsoinliers is > d {
00077 % this implies that we may have found a good model
00078 % now test how good it is
00079 bettermodel = model parameters fitted to all points in maybeinliers and alsoinliers
00080 thiserr = a measure of how well model fits these points
00081 if thiserr < besterr {
00082 bestfit = bettermodel
00083 besterr = thiserr
00084 }
00085 }
00086 increment iterations
00087 }
00088 return bestfit
00089 }}}
00090 """
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 iterations = 0
00130 bestfit = None
00131 besterr = np.inf
00132 best_inlier_idxs = None
00133 while iterations < k:
00134
00135 maybe_idxs, test_idxs = random_partition(n,data.shape[0])
00136 maybeinliers = data[maybe_idxs,:]
00137 test_points = data[test_idxs]
00138 maybemodel = model.fit(maybeinliers)
00139 test_err = model.get_error( test_points, maybemodel)
00140 also_idxs = test_idxs[test_err < t]
00141 alsoinliers = data[also_idxs,:]
00142 if debug:
00143 print 'test_err.min()',test_err.min()
00144 print 'test_err.max()',test_err.max()
00145 print 'np.mean(test_err)',np.mean(test_err)
00146 print 'iteration %d:len(alsoinliers) = %d'%(
00147 iterations,len(alsoinliers))
00148 if len(alsoinliers) > d:
00149 betterdata = np.concatenate( (maybeinliers, alsoinliers) )
00150 bettermodel = model.fit(betterdata)
00151 better_errs = model.get_error( betterdata, bettermodel)
00152 thiserr = np.mean( better_errs )
00153 if thiserr < besterr:
00154 bestfit = bettermodel
00155 besterr = thiserr
00156 best_inlier_idxs = np.concatenate( (maybe_idxs, also_idxs) )
00157 iterations+=1
00158 if bestfit is None:
00159 print "\n\n[ransac.py - line 152]"
00160 print "Ransac plane fitting did not meet fit accaptance criteria at current settings."
00161 print "Consider editing Ransac Parameters to be more generous or trying scan again."
00162 print "This error often happens when no table is present in front of the robot.\n\n"
00163 import sys;
00164 sys.exit()
00165
00166 if return_all:
00167 return bestfit, {'inliers':best_inlier_idxs}
00168 else:
00169 return bestfit
00170
00171
00172 def random_partition(n,n_data):
00173 """return n random rows of data (and also the other len(data)-n rows)"""
00174 all_idxs = np.arange( n_data )
00175 np.random.shuffle(all_idxs)
00176 idxs1 = all_idxs[:n]
00177 idxs2 = all_idxs[n:]
00178 return idxs1, idxs2
00179
00180 class LinearLeastSquaresModel:
00181 """linear system solved using linear least squares
00182
00183 This class serves as an example that fulfills the model interface
00184 needed by the ransac() function.
00185
00186 """
00187 def __init__(self,input_columns,output_columns,debug=False):
00188 self.input_columns = input_columns
00189 self.output_columns = output_columns
00190 self.debug = debug
00191 def fit(self, data):
00192 A = np.vstack([data[:,i] for i in self.input_columns]).T
00193 B = np.vstack([data[:,i] for i in self.output_columns]).T
00194 x,resids,rank,s = scipy.linalg.lstsq(A,B)
00195 return x
00196 def get_error( self, data, model):
00197 A = np.vstack([data[:,i] for i in self.input_columns]).T
00198 B = np.vstack([data[:,i] for i in self.output_columns]).T
00199 B_fit = scipy.dot(A,model)
00200 err_per_point = np.sum((B-B_fit)**2,axis=1)
00201 print err_per_point
00202 return err_per_point
00203
00204 class PlaneLeastSquaresModel:
00205
00206 def __init__(self, debug=False):
00207 self.debug = debug
00208 def fit(self, data):
00209
00210 model = [data[0],np.cross(data[1] - data[0], data[2] - data[1])]
00211 model[1] = model[1] / np.linalg.norm(model[1])
00212 return model
00213 def get_error( self, data, model):
00214
00215
00216 max_angle = 30.0 * np.pi / 180.0
00217 angle = np.arccos(scipy.dot(np.array([0,0,1]),model[1].T))
00218
00219
00220 if abs(angle) > max_angle:
00221 return np.ones(np.shape(data)[0]) * 999999999999999999999999999999
00222
00223
00224 d = scipy.dot(model[0],model[1].T)
00225
00226 s = scipy.dot(data, model[1].T) - d
00227
00228
00229
00230 return abs(s)
00231
00232 def test():
00233
00234
00235 n_samples = 500
00236 n_inputs = 1
00237 n_outputs = 1
00238 A_exact = 20*np.random.random((n_samples,n_inputs) )
00239 perfect_fit = 60*np.random.normal(size=(n_inputs,n_outputs) )
00240 B_exact = scipy.dot(A_exact,perfect_fit)
00241 assert B_exact.shape == (n_samples,n_outputs)
00242
00243
00244 A_noisy = A_exact + np.random.normal(size=A_exact.shape )
00245 B_noisy = B_exact + np.random.normal(size=B_exact.shape )
00246
00247 if 1:
00248
00249 n_outliers = 100
00250 all_idxs = np.arange( A_noisy.shape[0] )
00251 np.random.shuffle(all_idxs)
00252 outlier_idxs = all_idxs[:n_outliers]
00253 non_outlier_idxs = all_idxs[n_outliers:]
00254 A_noisy[outlier_idxs] = 20*np.random.random((n_outliers,n_inputs) )
00255 B_noisy[outlier_idxs] = 50*np.random.normal(size=(n_outliers,n_outputs) )
00256
00257
00258
00259 all_data = np.hstack( (A_noisy,B_noisy) )
00260 input_columns = range(n_inputs)
00261 output_columns = [n_inputs+i for i in range(n_outputs)]
00262 debug = False
00263 model = LinearLeastSquaresModel(input_columns,output_columns,debug=debug)
00264
00265 linear_fit,resids,rank,s = scipy.linalg.lstsq(all_data[:,input_columns],
00266 all_data[:,output_columns])
00267
00268
00269 ransac_fit, ransac_data = ransac(all_data,model,
00270 50, 1000, 7e3, 300,
00271 debug=debug,return_all=True)
00272 if 1:
00273 import pylab
00274
00275 sort_idxs = np.argsort(A_exact[:,0])
00276 A_col0_sorted = A_exact[sort_idxs]
00277
00278 if 1:
00279 pylab.plot( A_noisy[:,0], B_noisy[:,0], 'k.', label='data' )
00280 pylab.plot( A_noisy[ransac_data['inliers'],0], B_noisy[ransac_data['inliers'],0], 'bx', label='RANSAC data' )
00281 else:
00282 pylab.plot( A_noisy[non_outlier_idxs,0], B_noisy[non_outlier_idxs,0], 'k.', label='noisy data' )
00283 pylab.plot( A_noisy[outlier_idxs,0], B_noisy[outlier_idxs,0], 'r.', label='outlier data' )
00284 pylab.plot( A_col0_sorted[:,0],
00285 np.dot(A_col0_sorted,ransac_fit)[:,0],
00286 label='RANSAC fit' )
00287 pylab.plot( A_col0_sorted[:,0],
00288 np.dot(A_col0_sorted,perfect_fit)[:,0],
00289 label='exact system' )
00290 pylab.plot( A_col0_sorted[:,0],
00291 np.dot(A_col0_sorted,linear_fit)[:,0],
00292 label='linear fit' )
00293 pylab.legend()
00294 pylab.show()
00295
00296
00297 def testPlane():
00298
00299
00300
00301 debug = True
00302 model = PlaneLeastSquaresModel(debug)
00303 data = np.array([[0,0,0],[0,1,0],[0.1,12,0.1],[0,0,12],[1,0,0],[1,2,13]])
00304
00305 ransac_fit, ransac_data = ransac(data,model,
00306 3, 1000, 1, 2,
00307 debug=debug,return_all=True)
00308 print ransac_fit
00309 print ransac_data
00310
00311 def testPlanePointcloud():
00312 import processor
00313 import configuration
00314
00315 cfg = configuration.configuration(TEST_FOLDER)
00316
00317 pc = processor.processor(cfg)
00318
00319 pc.load_data('2009Nov04_141226')
00320 pc.process_raw_data()
00321
00322
00323 debug = False
00324 model = PlaneLeastSquaresModel(debug)
00325 data = np.asarray(pc.pts3d_bound).T
00326
00327 ransac_fit, ransac_data = ransac(data,model,
00328 3, 1000, 0.02, 300,
00329 debug=debug,return_all=True)
00330 print ransac_fit
00331 print ransac_data
00332 print 'len inlier',len(ransac_data['inliers']),'shape pts',np.shape(pc.pts3d_bound)
00333 pc.pts3d_bound = pc.pts3d_bound[:,ransac_data['inliers']]
00334 pc.display_3d('height')
00335
00336 if __name__=='__main__':
00337
00338 testPlanePointcloud()