compare_statistics.py
Go to the documentation of this file.
00001 #!/usr/bin/python
00002 #################################
00003 # Plot the results from different experiments in one coherent plot.
00004 #
00005 # What you will usually do:
00006 #  rosrun shape_reconstruction compare_statistics.py  \
00007 #       <path/to/data>/results_centroid_and_neighbors' '<path/to/data>/results_centroid_and_neighbors_wo_tracker'  <path/to/data>/ochs_results
00008 # Where results_centroid_and_neighbors is the result of the pipeline
00009 # and results_centroid_and_neighbors_wo_tracker contains results with
00010 # the shape-tracker being off (optional), and ochs_results contains
00011 # results from the Ochs baseline (one subfolder per experiment, each
00012 # containing a folder "DenseSegmentation" with the *_dense.ppm result files.
00013 #
00014 # WARN: this does not actually *generate* the statistics! You have to
00015 # run "generate_statistics" script to do this first.
00016 
00017 import numpy as np
00018 import matplotlib.pylab as plt
00019 import matplotlib
00020 matplotlib.rcParams['ps.useafm'] = True
00021 matplotlib.rcParams['pdf.use14corefonts'] = True
00022 matplotlib.rcParams['text.usetex'] = True
00023 
00024 import sys
00025 import os
00026 import os.path
00027 
00028 import re
00029 import shutil
00030 
00031 ## Title and settings
00032 
00033 fscore_beta = 0.5
00034 
00035 full_pattern = '(segment_ext_d_and_c_rb)(([0-9]+))'
00036 wo_st_pattern= '(segment_no_st_ext_d_and_c_rb)(([0-9]+))'
00037 
00038 # used for name replacement
00039 wo_st_template = 'segment_no_st_ext_d_and_c_rb%d.txt'
00040 
00041 variant2labelAndStyle = {
00042           # (regex, plotting params, legend order)
00043           full_pattern: ({'label': "Full", 'lw': 3.0, 'ls': "-", 'color': 'k'}, 0),
00044           wo_st_pattern: ({'label': "Full w/o Shape Tracking", 'lw': 3.0, 'ls': "--", 'color': 'k', 'alpha': 0.5}, 1),
00045           '(segment_naive_depth_rb)([0-9]+)': ({'label': 'Shape-based (depth only)', 'lw': 1.0, 'ls': "--", 'color': 'b'}, 4),
00046           '(segment_naive_color_rb)([0-9]+)': ({'label': 'Shape-based (color only)', 'lw': 1.0, 'ls': "--", 'color': 'r'}, 5),
00047           '(segment_depth_rb)([0-9]+)': ({'label': 'Motion (depth only)', 'lw': 1.5, 'ls': "-", 'color': 'b'}, 2),
00048           '(segment_color_rb)([0-9]+)': ({'label': 'Motion (color only)', 'lw': 1.5, 'ls': "-", 'color': 'r'}, 3),
00049           '(ochs)': ({'label': 'Ochs et al.', 'lw': 3.0, 'ls': ":", 'color': 'g'}, 6), 
00050           #'segment_ext_c_rb([0-9]+)': (''),
00051           #'segment_ext_d_rb([0-9]+)': (''),
00052          }
00053 
00054 folderElems2Title = {
00055   ('box'): 'Box',
00056   ('globe'): 'Globe',
00057   ('metalcase'): '2 Bodies: Metal case',
00058   ('statue'): '2 Bodies: Statue',
00059   ('head1'): 'Head',
00060   ('robotDrawer'): 'Drawer',
00061   ('redthing'): 'Red shape',
00062   ('ks_drawer_full_gt_drawer'): 'Cabinet: Drawer',
00063   ('ks_drawer_full_gt_base'): 'Cabinet: Frame',
00064   ('ks_laptop_full_gt_lid'): 'Laptop: Lid',
00065   ('ks_laptop_full_gt_base'): 'Laptop: Base',
00066 }
00067 
00068 folderElems2Order = [
00069   ('robotDrawer'),
00070   ('box'),
00071   ('globe'),
00072   ('head1'),
00073   ('metalcase'),
00074   ('statue'),
00075   ('redthing'),
00076   ('ks_drawer_full_gt_base'),
00077   ('ks_drawer_full_gt_drawer'),
00078   ('ks_laptop_full_gt_base'),
00079   ('ks_laptop_full_gt_lid'),
00080 ]
00081 #########################
00082 
00083 def compare_statistics(folder, show_fscore=True, multiple_figures=True):
00084   stats_map = collect_stats(folder)
00085     
00086   no_exp = len(stats_map)
00087 
00088   figures = []
00089   if multiple_figures:
00090     for i in range(3*no_exp):
00091       figures.append(plt.figure(figsize=(2,2)))
00092   else:
00093     #adjust figure size to #experiments
00094     fig = plt.figure(figsize=(10,3*no_exp))
00095     figures.append(fig)
00096   
00097   #print stats_map.keys()
00098   #if no_exp == len(folderElems2Order):
00099   stats_map_sorted = []
00100   for i, name in enumerate(folderElems2Order):
00101     for k,v in stats_map.items():
00102       if name in k:
00103         stats_map_sorted.append ( (k,v) )
00104         break
00105   print [ k for k,v in stats_map_sorted ]
00106   #else:
00107     #stats_map_sorted = sorted(stats_map.items(), key=lambda x: x[0])
00108   
00109   cols = 2
00110   if show_fscore:
00111     cols = 3
00112   
00113   #print stats_map_sorted
00114   figure_names = []
00115   figure_rel_idx = []
00116   for i, (exp_name, variant_stats) in enumerate( stats_map_sorted ):
00117     if multiple_figures:
00118       fig = figures[cols*i]
00119       ax_prec = figures[cols*i].add_subplot(1,1,1)
00120       ax_rec =  figures[cols*i+1].add_subplot(1,1,1)
00121       ax_fscore = None
00122       if show_fscore:
00123         ax_fscore = figures[cols*i+2].add_subplot(1,1,1)
00124     else:
00125       ax_prec = plt.subplot(no_exp, cols, cols*i+1)
00126       ax_rec = plt.subplot(no_exp, cols, cols*i+2)
00127       ax_fscore = None
00128       if show_fscore:
00129         ax_fscore = plt.subplot(no_exp, cols, cols*i+3)
00130           
00131     plot_legend = i==0 and not multiple_figures
00132     plot_exp_name = not multiple_figures
00133     plot_stats_for_exp(exp_name, variant_stats, fig, ax_prec, ax_rec, ax_fscore, plot_legend, plot_exp_name)
00134 
00135     for c in range(cols):
00136       figure_names.append(exp_name)
00137       figure_rel_idx.append(c)
00138 
00139     if i == 0: # or multiple_figures:
00140       ax_prec.set_title("\\textrm{Precision}")
00141       ax_rec.set_title("\\textrm{Recall}")
00142       if show_fscore:
00143         ax_fscore.set_title("\\textrm{F$_{%.1f}$ score}" % fscore_beta)
00144 
00145     if i == len(stats_map_sorted)-1: # or multiple_figures:
00146       time_label = "\\textrm{time (sec)}"
00147       ax_prec.set_xlabel(time_label)
00148       ax_rec.set_xlabel(time_label)
00149       if show_fscore:
00150         ax_fscore.set_xlabel(time_label)
00151 
00152   for i, (fig, fig_idx) in enumerate(zip(figures, figure_rel_idx)):
00153     if multiple_figures:
00154       img_path = os.path.join(folder, "compare_results_%s_%d.pdf" % (figure_names[i], fig_idx)) 
00155     else:
00156       img_path = os.path.join(folder, "compare_results.pdf")
00157     print ("Saving image at %s" % img_path)
00158     fig.savefig(img_path, bbox_inches="tight")
00159       
00160 def collect_stats(folder):
00161   stats_map = {}
00162   
00163   for f in os.listdir(folder):
00164     fld = os.path.join(folder, f)
00165     real_fld = os.path.realpath(fld)
00166     print real_fld
00167     if not os.path.isdir(real_fld):
00168       #print "  skipping %s" % real_fld
00169       continue
00170     
00171     stats_map[f] = collect_stats_for_exp(real_fld)
00172   return stats_map
00173   
00174 def collect_stats_for_exp(folder):
00175   
00176   variant_map = {}
00177   
00178   for f in os.listdir(folder):
00179     if f[-3:] != "txt":
00180       continue
00181     filename = os.path.join(folder, f)
00182       
00183     data = np.genfromtxt(filename, dtype=float, delimiter=' ', names=True)
00184   
00185     precision = data['tp'] / (data['tp']+data['fp'])
00186     recall = data['tp'] / (data['tp']+data['fn'])
00187     seg_acc = data['tp'] / (data['tp']+data['fp']+data['fn'])
00188     #fscore = 2* (precision*recall) / (precision + recall)
00189     beta = fscore_beta
00190     fscore = (1+beta**2)* (precision*recall) / (beta**2 * precision + recall)
00191     time = data['time'] - data['time'][0]
00192     
00193     freq = np.mean(data['time'][1:] - data['time'][:-1])
00194     
00195     #rel_time = (time-data['time'][0]) / time[-1]
00196   
00197     # add t=0 -> 0
00198     precision = np.hstack( [ [0.], precision ]  )
00199     recall = np.hstack( [ [0.], recall ] )
00200     fscore = np.hstack( [ [0.], fscore ] )
00201     time = np.hstack( [ time, [time[-1] + freq] ]  )
00202     #rel_time = np.hstack( [ [0., rel_time] ] )
00203   
00204     # clean up
00205     precision[np.where(np.isnan(precision))] = 0.
00206     recall[np.where(np.isnan(recall))] = 0.
00207     seg_acc[np.where(np.isnan(seg_acc))] = 0.
00208     fscore[np.where(np.isnan(fscore))] = 0.
00209 
00210     filetitle = f.split(".")[-2]
00211     
00212     variant_map[filetitle] = {}
00213     variant_map[filetitle]['precision'] = precision
00214     variant_map[filetitle]['recall'] = recall
00215     variant_map[filetitle]['seg_acc'] = seg_acc
00216     variant_map[filetitle]['fscore'] = fscore
00217     variant_map[filetitle]['time'] = time
00218     #variant_map[filetitle]['rel_time'] = rel_time
00219     
00220   return variant_map
00221 
00222 def plot_stats_for_exp(exp_name, variant_stats, fig, ax_prec, ax_rec, ax_fscore=None, plot_legend=True, plot_exp_name=True):
00223   
00224   print exp_name
00225   
00226   processed_variants = []
00227   
00228   lines = []
00229   labels = []
00230   order = []
00231   
00232   for variant, stats in variant_stats.items():
00233     dct = None
00234     print " "+variant
00235     
00236     try:
00237       for var_re, (dct_, order_) in variant2labelAndStyle.items():
00238         res = re.match(var_re, variant)
00239         if res is not None:
00240           print res.group(1)
00241           if res.group(1) in processed_variants:
00242             print "ERROR: More than one rigid body ground truth found - currently not supported. Delete the _rb* files that do not correspond to the ground truth and re-run"
00243             print " experiment: %s" % exp_name
00244             print " variant: %s" % variant
00245             raise Exception()
00246           dct = dct_
00247           processed_variants.append (res.group(1) )
00248           order.append(order_)
00249     except Exception, e:
00250       #raise e
00251       pass
00252     
00253     if dct is None:
00254       print "   WARN: Variant unsupported %s " % variant
00255       continue
00256     
00257     for y in np.arange(0.0, 1.1, 0.2):  
00258       for ax in [ax_prec, ax_rec, ax_fscore]:
00259         if ax_fscore is None:
00260           continue
00261         ax.plot(stats['time'], [y] * len(stats['time']), "-.", lw=0.3, color="black", alpha=0.1)  
00262   
00263     #ax_segacc.plot(stats['rel_time'], seg_acc, "k", label="Segmentation Accuracy", lw=3.0)
00264     l1 = ax_prec.plot(stats['time'], stats['precision'], **dct)
00265     ax_rec.plot(stats['time'], stats['recall'], **dct)
00266     
00267     if ax_fscore is not None:
00268       ax_fscore.plot(stats['time'], stats['fscore'], **dct)
00269     
00270     #print l1
00271     lines.extend(l1)
00272     labels.append( "\\textrm{%s}" % dct['label'])
00273     
00274     if plot_exp_name:
00275       ax_prec.set_ylabel(exp_name[:15])
00276       for elem, title in folderElems2Title.items():
00277         if elem in exp_name:
00278           ax_prec.set_ylabel(title)
00279     
00280     for ax in [ax_prec, ax_rec, ax_fscore]:
00281       if ax is None:
00282         continue
00283       ax.set_xlim(0, stats['time'][-1])
00284       ax.set_ylim(-0.1, 1.1)
00285     
00286     # Put a legend to the right of the current axis
00287     
00288   if plot_legend:
00289     lines_sorted, labels_sorted, ordered = zip (* sorted( zip(lines, labels, order), key=lambda x: x[2]) )
00290     
00291     #box = ax.get_position()
00292     #ax_rec.set_position([box.x0, box.y0, box.width * 0.8, box.height])
00293     fig.legend(lines_sorted, labels_sorted, 'lower center', ncol=4,prop={'size':12}) #, bbox_to_anchor=(1, 0.5))
00294     #fig.legend(loc=4)
00295     
00296 def cherry_pick_full_wo_shape_tracker(wo_src, with_dst):
00297   print "Cherry-picking FULL result from %s" % wo_src
00298 
00299   exp2res = {}
00300 
00301   # collect result txts
00302   for d in os.listdir(wo_src):
00303     exp_dir = os.path.join(wo_src, d)
00304     if not os.path.isdir(exp_dir):
00305       continue
00306     for f in os.listdir(exp_dir):
00307       res = re.match(full_pattern, f)
00308       if res is not None:
00309         exp_name = None
00310         for elem, _ in folderElems2Title.items():
00311           if elem in d:
00312             exp_name = elem
00313         if exp_name is None:
00314           print "WARNING: source experiment unknown: %s" % d
00315         else:
00316           exp2res[exp_name] = (os.path.join(exp_dir, f), res.group(2))
00317         
00318   #print exp2res
00319   
00320   # copy to destination
00321   for d in os.listdir(with_dst):
00322     exp_dir = os.path.join(with_dst, d)
00323     if not os.path.isdir(exp_dir):
00324       continue
00325       
00326     for elem, _ in folderElems2Title.items():
00327       if elem in d:
00328         exp_name = elem
00329     if exp_name is None:
00330       print "WARNING: destination experiment unknown: %s" % d
00331       continue
00332       
00333     if exp_name not in exp2res:
00334       print "ERROR: source %s does not contain experiment %s" % (with_dst, d)
00335       continue
00336     
00337     fres, fres_rb = exp2res[exp_name]
00338     fdes = os.path.join(exp_dir, wo_st_template % int(fres_rb))
00339     print " Copying %s to %s" % (fres, fdes)
00340 
00341     if os.path.exists(fdes):
00342       try:
00343         os.remove(fdes)
00344       except:
00345         print "Cannot move %s because file exists and cannot be deleted" % fdes
00346         continue
00347     
00348     try:
00349       shutil.copyfile(fres, fdes)
00350     except Exception, e:
00351       print e
00352       print "Unknown error copying file %s" % fres
00353       continue      
00354       
00355   
00356 
00357 if __name__ == "__main__":
00358   if len(sys.argv) < 2:
00359     print "Usage: compare_statistics.py <experiment meta folder [contains ONLY folders that include statistics text files (and result bags)]> [<experiment meta folder w/o shape tracking]"
00360     sys.exit()
00361 
00362   if len(sys.argv) > 2:
00363     wst_folder = sys.argv[2]
00364     cherry_pick_full_wo_shape_tracker(sys.argv[2], sys.argv[1])
00365 
00366   print ("Starting compare statistics")
00367   multiple_figures=True
00368   compare_statistics(sys.argv[1],multiple_figures=multiple_figures)
00369 
00370   if not multiple_figures:
00371     plt.show()
00372 


shape_reconstruction
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:29:42