def do_fuse_with_icp(substack,C_firstview,C_secondview,max_distance,match_distance=None,num_iterations = 100, eps=1e-8, verbose=False): if match_distance is None: match_distance = max_distance if len(C_firstview)==0 or len(C_secondview)==0: if verbose: print('total=%d merged=%d only_firstview=%d only_secondview=%d'%(len(C_firstview+C_secondview),len([]),len(C_firstview),len(C_secondview))) return [],C_firstview,C_secondview,C_firstview+C_secondview C_secondview,good_firstview,good_secondview,_,_ = match_markers_with_icp(C_firstview,C_secondview, match_distance, num_iterations, eps) c_firstview_matched = [] c_secondview_matched = [] for gi,gj in zip(good_firstview,good_secondview): c1=C_firstview[gi] c2=C_secondview[gj] d = distance((c1.x,c1.y,c1.z),(c2.x,c2.y,c2.z)) if d < max_distance: c_firstview_matched.append(c1) c_secondview_matched.append(c2) true_positives_firstview = set(c_firstview_matched) true_positives_secondview = set(c_secondview_matched) C_merged = [] for c1,c2 in zip(c_firstview_matched,c_secondview_matched): c_merged = c1 c_merged.x = (c_merged.x + c2.x)/2 c_merged.y = (c_merged.y + c2.y)/2 c_merged.z = (c_merged.z + c2.z)/2 if c_merged.x<0 or c_merged.y<0 or c_merged.z<0 or c_merged.x>substack.info['Width'] or c_merged.y>substack.info['Height'] or c_merged.z>substack.info['Depth']: continue C_merged.append(c_merged) C_onlyfirstview=[] for i,c in enumerate(C_firstview): if c not in true_positives_firstview: cx,cy,cz = c.x,c.y,c.z if cx<0 or cy<0 or cz<0 or cx>substack.info['Width'] or cy>substack.info['Height'] or cz>substack.info['Depth']: continue else: C_onlyfirstview.append(c) C_onlysecondview=[] for i,c in enumerate(C_secondview): if c not in true_positives_secondview: cx,cy,cz = c.x,c.y,c.z if cx<0 or cy<0 or cz<0 or cx>substack.info['Width'] or cy>substack.info['Height'] or cz>substack.info['Depth']: continue else: C_onlysecondview.append(c) C_total=C_merged+C_onlyfirstview+C_onlysecondview if verbose: print('total=%d merged=%d only_firstview=%d only_secondview=%d'%(len(C_total),len(C_merged),len(C_onlyfirstview),len(C_onlysecondview))) return C_merged,C_onlyfirstview,C_onlysecondview,C_total
def do_fuse(substack,C_firstview,C_secondview,max_distance,verbose=False): # ============ max-cardinality bipartite matching if len(C_firstview)==0 or len(C_secondview)==0: if verbose: print('total=%d merged=%d only_firstview=%d only_secondview=%d'%(len(C_firstview+C_secondview),len([]),len(C_firstview),len(C_secondview))) return [],C_firstview,C_secondview,C_firstview+C_secondview true_positives_firstview = set() # subset of C_true that are true positives true_positives_secondview = set() # subset of C_pred that are true positives G,mate,node2center = match_markers(C_firstview,C_secondview,max_distance*2) C_merged = [] for k1,k2 in mate.iteritems(): if k1[0] == 'p': # mate is symmetric continue c1 = node2center[k1] c2 = node2center[k2] d = distance((c1.x,c1.y,c1.z),(c2.x,c2.y,c2.z)) if d < (max_distance): # a constant criterion is needed! true_positives_firstview.add(c1) true_positives_secondview.add(c2) c_merged = c1 c_merged.x = (c_merged.x + c2.x)/2 c_merged.y = (c_merged.y + c2.y)/2 c_merged.z = (c_merged.z + c2.z)/2 if c_merged.x<0 or c_merged.y<0 or c_merged.z<0 or c_merged.x>substack.info['Width'] or c_merged.y>substack.info['Height'] or c_merged.z>substack.info['Depth']: continue C_merged.append(c_merged) C_onlyfirstview=[] for i,c in enumerate(C_firstview): if c not in true_positives_firstview: cx,cy,cz = c.x,c.y,c.z if cx<0 or cy<0 or cz<0 or cx>substack.info['Width'] or cy>substack.info['Height'] or cz>substack.info['Depth']: continue else: C_onlyfirstview.append(c) C_onlysecondview=[] for i,c in enumerate(C_secondview): if c not in true_positives_secondview: cx,cy,cz = c.x,c.y,c.z if cx<0 or cy<0 or cz<0 or cx>substack.info['Width'] or cy>substack.info['Height'] or cz>substack.info['Depth']: continue else: C_onlysecondview.append(c) C_total=C_merged+C_onlyfirstview+C_onlysecondview if verbose: print('total=%d merged=%d only_firstview=%d only_secondview=%d'%(len(C_total),len(C_merged),len(C_onlyfirstview),len(C_onlysecondview))) return C_merged,C_onlyfirstview,C_onlysecondview,C_total
def eval_perf(substack,C_true,C_pred,verbose=True,errors_marker_file=None,rp_file=None, max_cell_diameter=None): # max-cardinality bipartite matching C_rejected = [c for c in C_pred if c.rejected] C_pred = [c for c in C_pred if not c.rejected] true_positives_true = set() # subset of C_true that are true positives true_positives_pred = set() # subset of C_pred that are true positives TP = 0 TP_inside = [] G,mate,node2center = match_markers(C_true,C_pred, 2*max_cell_diameter) kw = 0 tee.log(mate) #todo modificato #tee.log(type(mate)) #for k1,k2 in mate.iteritems(): for k1, k2 in mate: if k1[0] == 'p': # mate is symmetric continue c1 = node2center[k1] c2 = node2center[k2] d = distance((c1.x,c1.y,c1.z),(c2.x,c2.y,c2.z)) if d < max_cell_diameter/2: true_positives_pred.add(c2) true_positives_true.add(c1) TP += 1 if inside(c1,substack): if verbose: print(' TP:', k2, c2.name,c2.x,c2.y,c2.z,c2, k1, c1.name,c1.x,c1.y,c1.z,d) TP_inside.append(c2) kw += 1 else: if verbose: print('OTP:', k2, c2.name,c2.x,c2.y,c2.z,c2, k1, c1.name,c1.x,c1.y,c1.z,'d:',d) else: if verbose: print('---> too far', c2.name,c2.x,c2.y,c2.z,c2,c1.name,c1.x,c1.y,c1.z,d) FP_inside,FN_inside = [],[] if errors_marker_file is not None: ostream = open(errors_marker_file,'w') print('##x,y,z,radius,shape,name,comment, color_r,color_g,color_b',file=ostream) for i,c in enumerate(C_true): if c not in true_positives_true: if inside(c,substack): r,g,b = 255,0,255 name = 'FN_%03d (%s)' % (i+1,c.name) cx,cy,cz = int(round(c.x)),int(round(c.y)),int(round(c.z)) comment = ':'.join(map(str,[cx,cy,cz,c])) if errors_marker_file is not None: print(','.join(map(str,[cx,cy,cz,0,1,name,comment,r,g,b])), file=ostream) FN_inside.append(c) if verbose: print('FN: ', c.name,c.x,c.y,c.z,c) for i,c in enumerate(C_pred): c.is_false_positive = False if c not in true_positives_pred: if inside(c,substack): r,g,b = 255,0,0 name = 'FP_%03d (%s)' % (i+1,c.name) c.is_false_positive = True cx,cy,cz = int(round(c.x)),int(round(c.y)),int(round(c.z)) comment = ':'.join(map(str,[cx,cy,cz,c])) if errors_marker_file is not None: print(','.join(map(str,[1+cx,1+cy,1+cz,0,1,name,comment,r,g,b])), file=ostream) FP_inside.append(c) if verbose: print('FP: ', c.name,c.x,c.y,c.z,c) # Also print predicted TP in error marker file (helps debugging) for i,c in enumerate(C_pred): if c in true_positives_pred: if inside(c,substack): r,g,b = 0,255,0 name = 'TP_%03d (%s)' % (i+1,c.name) cx,cy,cz = int(round(c.x)),int(round(c.y)),int(round(c.z)) comment = ':'.join(map(str,[cx,cy,cz,c])) if errors_marker_file is not None: print(','.join(map(str,[1+cx,1+cy,1+cz,0,1,name,comment,r,g,b])), file=ostream) # Also print true TP in error marker file (helps debugging) for i,c in enumerate(C_true): if c in true_positives_true: if inside(c,substack): r,g,b = 0,255,255 name = 'TP_%03d (%s)' % (i+1,c.name) cx,cy,cz = int(round(c.x)),int(round(c.y)),int(round(c.z)) comment = ':'.join(map(str,[cx,cy,cz,c])) if errors_marker_file is not None: print(','.join(map(str,[1+cx,1+cy,1+cz,0,1,name,comment,r,g,b])), file=ostream) # Finally, print rejected predictions error marker file (to show the benefit of the filter) for i,c in enumerate(C_rejected): if inside(c,substack): r,g,b = 255,128,0 name = 'REJ_%03d (%s)' % (i+1,c.name) cx,cy,cz = int(round(c.x)),int(round(c.y)),int(round(c.z)) comment = ':'.join(map(str,[cx,cy,cz,c])) if errors_marker_file is not None: print(','.join(map(str,[1+cx,1+cy,1+cz,0,1,name,comment,r,g,b])), file=ostream) if errors_marker_file is not None: ostream.close() if len(C_pred): if hasattr(C_pred[0],'distance') and rp_file is not None: with open(rp_file, 'w') as ostream: for i,c in enumerate(C_pred): if inside(c,substack): if c in true_positives_pred: print(-c.distance, '1', file=ostream) else: print(-c.distance, '0', file=ostream) # Add also the false negatives with infinite distance so they will always be rejected for i,c in enumerate(C_true): if c not in true_positives_true: if inside(c,substack): print(-1000, '1', file=ostream) if len(TP_inside) > 0: precision = float(len(TP_inside))/float(len(TP_inside)+len(FP_inside)) recall = float(len(TP_inside))/float(len(TP_inside)+len(FN_inside)) else: precision = int(len(FP_inside) == 0) recall = int(len(FN_inside) == 0) if len(TP_inside)==0 and len(FP_inside)>0 and len(FN_inside)>0: F1 = 0.00 else: F1 = 2*precision*recall/(precision+recall) C_pred_inside = [c for c in C_pred if inside(c,substack)] C_true_inside = [c for c in C_true if inside(c,substack)] print('|pred|=%d |true|=%d P: %.2f / R: %.2f / F1: %.2f ==== TP: %d / FP: %d / FN: %d' % (len(C_pred_inside),len(C_true_inside),precision*100,recall*100,F1*100,len(TP_inside),len(FP_inside),len(FN_inside))) return precision,recall,F1,TP_inside,FP_inside,FN_inside
def eval_perf(substack,C_true,C_pred,verbose=True,errors_marker_file=None,rp_file=None, max_cell_diameter=None): # max-cardinality bipartite matching C_rejected = [c for c in C_pred if c.rejected] C_pred = [c for c in C_pred if not c.rejected] true_positives_true = set() # subset of C_true that are true positives true_positives_pred = set() # subset of C_pred that are true positives TP = 0 TP_inside = [] G,mate,node2center = match_markers(C_true,C_pred, 2*max_cell_diameter) kw = 0 for k1,k2 in mate.iteritems(): if k1[0] == 'p': # mate is symmetric continue c1 = node2center[k1] c2 = node2center[k2] d = distance((c1.x,c1.y,c1.z),(c2.x,c2.y,c2.z)) if d < max_cell_diameter/2: true_positives_pred.add(c2) true_positives_true.add(c1) TP += 1 if inside(c1,substack): if verbose: print(' TP:', k2, c2.name,c2.x,c2.y,c2.z,c2, k1, c1.name,c1.x,c1.y,c1.z,d) TP_inside.append(c2) kw += 1 else: if verbose: print('OTP:', k2, c2.name,c2.x,c2.y,c2.z,c2, k1, c1.name,c1.x,c1.y,c1.z,'d:',d) else: if verbose: print('---> too far', c2.name,c2.x,c2.y,c2.z,c2,c1.name,c1.x,c1.y,c1.z,d) FP_inside,FN_inside = [],[] if errors_marker_file is not None: ostream = open(errors_marker_file,'w') print('##x,y,z,radius,shape,name,comment, color_r,color_g,color_b',file=ostream) for i,c in enumerate(C_true): if c not in true_positives_true: if inside(c,substack): r,g,b = 255,0,255 name = 'FN_%03d (%s)' % (i+1,c.name) cx,cy,cz = int(round(c.x)),int(round(c.y)),int(round(c.z)) comment = ':'.join(map(str,[cx,cy,cz,c])) if errors_marker_file is not None: print(','.join(map(str,[cx,cy,cz,0,1,name,comment,r,g,b])), file=ostream) FN_inside.append(c) if verbose: print('FN: ', c.name,c.x,c.y,c.z,c) for i,c in enumerate(C_pred): c.is_false_positive = False if c not in true_positives_pred: if inside(c,substack): r,g,b = 255,0,0 name = 'FP_%03d (%s)' % (i+1,c.name) c.is_false_positive = True cx,cy,cz = int(round(c.x)),int(round(c.y)),int(round(c.z)) comment = ':'.join(map(str,[cx,cy,cz,c])) if errors_marker_file is not None: print(','.join(map(str,[1+cx,1+cy,1+cz,0,1,name,comment,r,g,b])), file=ostream) FP_inside.append(c) if verbose: print('FP: ', c.name,c.x,c.y,c.z,c) # Also print predicted TP in error marker file (helps debugging) for i,c in enumerate(C_pred): if c in true_positives_pred: if inside(c,substack): r,g,b = 0,255,0 name = 'TP_%03d (%s)' % (i+1,c.name) cx,cy,cz = int(round(c.x)),int(round(c.y)),int(round(c.z)) comment = ':'.join(map(str,[cx,cy,cz,c])) if errors_marker_file is not None: print(','.join(map(str,[1+cx,1+cy,1+cz,0,1,name,comment,r,g,b])), file=ostream) # Also print true TP in error marker file (helps debugging) for i,c in enumerate(C_true): if c in true_positives_true: if inside(c,substack): r,g,b = 0,255,255 name = 'TP_%03d (%s)' % (i+1,c.name) cx,cy,cz = int(round(c.x)),int(round(c.y)),int(round(c.z)) comment = ':'.join(map(str,[cx,cy,cz,c])) if errors_marker_file is not None: print(','.join(map(str,[1+cx,1+cy,1+cz,0,1,name,comment,r,g,b])), file=ostream) # Finally, print rejected predictions error marker file (to show the benefit of the filter) for i,c in enumerate(C_rejected): if inside(c,substack): r,g,b = 255,128,0 name = 'REJ_%03d (%s)' % (i+1,c.name) cx,cy,cz = int(round(c.x)),int(round(c.y)),int(round(c.z)) comment = ':'.join(map(str,[cx,cy,cz,c])) if errors_marker_file is not None: print(','.join(map(str,[1+cx,1+cy,1+cz,0,1,name,comment,r,g,b])), file=ostream) if errors_marker_file is not None: ostream.close() if len(C_pred): if hasattr(C_pred[0],'distance') and rp_file is not None: with open(rp_file, 'w') as ostream: for i,c in enumerate(C_pred): if inside(c,substack): if c in true_positives_pred: print(-c.distance, '1', file=ostream) else: print(-c.distance, '0', file=ostream) # Add also the false negatives with infinite distance so they will always be rejected for i,c in enumerate(C_true): if c not in true_positives_true: if inside(c,substack): print(-1000, '1', file=ostream) if len(TP_inside) > 0: precision = float(len(TP_inside))/float(len(TP_inside)+len(FP_inside)) recall = float(len(TP_inside))/float(len(TP_inside)+len(FN_inside)) else: precision = int(len(FP_inside) == 0) recall = int(len(FN_inside) == 0) if len(TP_inside)==0 and len(FP_inside)>0 and len(FN_inside)>0: F1 = 0.00 else: F1 = 2*precision*recall/(precision+recall) C_pred_inside = [c for c in C_pred if inside(c,substack)] C_true_inside = [c for c in C_true if inside(c,substack)] print('|pred|=%d |true|=%d P: %.2f / R: %.2f / F1: %.2f ==== TP: %d / FP: %d / FN: %d' % (len(C_pred_inside),len(C_true_inside),precision*100,recall*100,F1*100,len(TP_inside),len(FP_inside),len(FN_inside))) return precision,recall,F1,TP_inside,FP_inside,FN_inside