def animate_detection(imstack, fsets, fcsets, fosets=None, rc=0, side=15, verbose=False): from matplotlib.patches import Circle def advance(event): key = event.key if verbose: print 'pressed', key, 'next frame:', global f_display if key=='left': if f_display>=1: f_display -= 1 elif key=='right': f_display += 1 else: plt.close() f_display = -1 if verbose: print f_display sys.stdout.flush() plt_text = np.vectorize(plt.text) def draw_circles(ax, centers, r, *args, **kwargs): patches = [Circle(cent, r, *args, **kwargs) for cent in centers] map(ax.add_patch, patches) ax.figure.canvas.draw() return patches if side==1: side = 15 txtoff = max(rc, side, 10) fig = plt.figure(figsize=(12, 12)) p = plt.imshow(imstack[0], cmap='gray') h, w = imstack[0].shape ax = p.axes global f_display f_display = repeat = f_old = 0 lengths = map(len, [imstack, fsets, fcsets]) f_max = min(lengths) assert f_max, 'Lengths imstack: {}, fsets: {}, fcsets: {}'.format(*lengths) while 0 <= f_display < f_max: if repeat > 5: if verbose: print 'stuck on frame', f_display break f_display %= f_max if f_display==f_old: repeat += 1 else: repeat = 0 f_old = f_display if verbose: print 'starting loop with f_display =', f_display xyo = helpy.consecutive_fields_view(fsets[f_display], 'xyo', False) xyc = helpy.consecutive_fields_view(fcsets[f_display], 'xy', False) x, y, o = xyo.T omask = np.isfinite(o) xo, yo, oo = xyo[omask].T p.set_data(imstack[f_display]) remove = [] if rc > 0: patches = draw_circles(ax, xyo[:, 1::-1], rc, color='g', fill=False, zorder=.5) remove.extend(patches) q = plt.quiver(yo, xo, np.sin(oo), np.cos(oo), angles='xy', units='xy', width=side/8, scale_units='xy', scale=1/side) ps = plt.scatter(y, x, c='r')#c=np.where(omask, 'r', 'b')) cs = plt.scatter(xyc[:,1], xyc[:,0], c='g', s=8) if fosets is not None: oc = helpy.quick_field_view(fosets[f_display], 'corner').reshape(-1, 2) ocs = plt.scatter(oc[:,1], oc[:,0], c='orange', s=8) remove.append(ocs) remove.extend([q, ps, cs]) tstr = fsets[f_display]['t'].astype('S') txt = plt_text(y+txtoff, x+txtoff, tstr, color='r') remove.extend(txt) plt.xlim(0, w) plt.ylim(0, h) plt.title("frame {}\n{} orientations / {} particles detected".format( f_display, np.count_nonzero(omask), len(o))) fig.canvas.draw() plt.waitforbuttonpress() fig.canvas.mpl_connect('key_press_event', advance) for rem in remove: rem.remove() if verbose: print 'ending frame', f_display sys.stdout.flush() if verbose: print 'loop broken'
def get_angles(pdata, cdata, pfsets, cfsets, cftrees, nc, rc, drc=None, ang=None, dang=None, do_average=True, verbose=False): """find the orientations of particles given center and corner positions Parameters ---------- pdata: data array with 'x' and 'y' fields for particle centers cdata: data array wity 'x' and 'y' fields for corners pdata and cdata arrays need not have the same length, but both must have 'f' field for the image frame) pfsets: slices into pdata, by frame cfsets: slices into cdata, by frame cftrees: dict of KDTrees for corners, by frame the following arguments are passed to find_corner: nc: number of corner dots rc: expected distance between center and corner dot drc: tolerance for rc, defaults to sqrt(rc) ang: angular separation between corners (if nc > 1) dang: tolerance for ang (if None, ang is ignored if nfound == nc, but is uses to choose best nc of nfound if nfound > nc) do_average: whether to average the nc corners to one value for return Returns ------- odata: structured array, same shape as pdata, with fields: 'corner' for particle corner (with 'x' and 'y' sub-fields) 'orient' for orientation of particles 'cdisp' for the corner - center displacement """ dt = [('corner', float, (nc, 2)), ('orient', float), ('cdisp', float, (nc, ))] if nc > 1 and not do_average: dt[1] += ((nc, ), ) # give the 'orient' field a shape of (nc,) odata = np.full(len(pdata), np.nan, dtype=dt) if ang > pi: ang = np.radians(ang) if dang: dang = np.radians(dang) odata_corner = odata['corner'] odata_orient = odata['orient'] odata_cdisp = odata['cdisp'] full_ids = pdata['id'] id_ok = full_ids[0] == 0 and np.all(np.diff(full_ids) == 1) print_freq = len(pfsets) // (100 if verbose > 1 else 5) + 1 print 'seeking orientations' for f in pfsets: if verbose and not f % print_freq: print f, fpdata = pfsets[f] fcdata = cfsets[f] cftree = cftrees[f] positions = helpy.consecutive_fields_view(fpdata, 'xy') cpositions = helpy.consecutive_fields_view(fcdata, 'xy') fp_ids = helpy.quick_field_view(fpdata, 'id') for fp_id, posi in it.izip(fp_ids, positions): # TODO could probably be sped up by looping through the output of # ptree.query_ball_tree(ctree) corner, orient, disp = \ find_corner(posi, cpositions, nc=nc, rc=rc, drc=drc, ang=ang, dang=dang, tree=cftree, do_average=do_average) if orient is None: continue full_id = fp_id if id_ok else np.searchsorted(full_ids, fp_id) odata_corner[full_id] = corner odata_orient[full_id] = orient odata_cdisp[full_id] = disp if do_average or nc == 1: mask = np.isfinite(odata['orient']) elif nc > 1: mask = np.all(np.isfinite(odata['orient']), axis=1) return odata, mask
def get_angles_loop(pdata, cdata, pfsets, cfsets, cftrees, nc=3, rc=11, drc=0, do_average=True, verbose=False): """ get_angles(pdata, cdata, pfsets, cfsets, cftrees, nc=3, rc=11, drc=0, do_average=True) arguments: pdata - data array with 'x' and 'y' fields for particle centers cdata - data array wity 'x' and 'y' fields for corners (these arrays need not have the same length, but both must have 'f' field for the image frame) pfsets - slices into pdata, by frame cfsets - and for cdata cftrees - dict of KDTrees for corners, by frame nc - number of corner dots rc - distance between center and corner dot drc - tolerance for rc do_average - whether to average the nc corners to one value for return returns: odata - array with fields: 'orient' for orientation of particles 'corner' for particle corner (with 'x' and 'y' sub-fields) (odata has the same shape as data) """ import helpy if do_average or nc == 1: dt = [('corner',float,(nc,2)), ('orient',float), ('cdisp',float,(nc,))] elif nc > 1: dt = [('corner',float,(nc,2,)), ('orient',float,(nc,)), ('cdisp',float,(nc,))] odata = np.full(len(pdata), np.nan, dtype=dt) odata_corner = odata['corner'] odata_orient = odata['orient'] odata_cdisp = odata['cdisp'] full_ids = pdata['id'] id_ok = full_ids[0]==0 and np.all(np.diff(full_ids)==1) print_freq = len(pfsets)//(100 if verbose>1 else 5) + 1 if verbose: print 'seeking orientations' for f in pfsets: if verbose and not f % print_freq: print f, fpdata = pfsets[f] fcdata = cfsets[f] tree = cftrees[f] positions = helpy.consecutive_fields_view(fpdata, 'xy') cpositions = helpy.consecutive_fields_view(fcdata, 'xy') frame_ids = helpy.quick_field_view(fpdata, 'id') for frame_id, posi in izip(frame_ids, positions): #TODO could probably be sped up by looping through the output of # ptree.query_ball_tree(ctree) corner, orient, disp = \ find_corner(posi, cpositions, tree=tree, nc=nc, rc=rc, drc=drc, do_average=do_average) if orient is None: continue full_id = frame_id if id_ok else np.searchsorted(full_ids, frame_id) odata_corner[full_id] = corner odata_orient[full_id] = orient odata_cdisp[full_id] = disp if do_average or nc == 1: mask = np.isfinite(odata['orient']) elif nc > 1: mask = np.all(np.isfinite(odata['orient']), axis=1) return odata, mask
def get_angles(pdata, cdata, pfsets, cfsets, cftrees, nc, rc, drc=None, ang=None, dang=None, do_average=True, verbose=False): """find the orientations of particles given center and corner positions Parameters ---------- pdata: data array with 'x' and 'y' fields for particle centers cdata: data array wity 'x' and 'y' fields for corners pdata and cdata arrays need not have the same length, but both must have 'f' field for the image frame) pfsets: slices into pdata, by frame cfsets: slices into cdata, by frame cftrees: dict of KDTrees for corners, by frame the following arguments are passed to find_corner: nc: number of corner dots rc: expected distance between center and corner dot drc: tolerance for rc, defaults to sqrt(rc) ang: angular separation between corners (if nc > 1) dang: tolerance for ang (if None, ang is ignored if nfound == nc, but is uses to choose best nc of nfound if nfound > nc) do_average: whether to average the nc corners to one value for return Returns ------- odata: structured array, same shape as pdata, with fields: 'corner' for particle corner (with 'x' and 'y' sub-fields) 'orient' for orientation of particles 'cdisp' for the corner - center displacement """ dt = [('corner', float, (nc, 2)), ('orient', float), ('cdisp', float, (nc,))] if nc > 1 and not do_average: dt[1] += ((nc,),) # give the 'orient' field a shape of (nc,) odata = np.full(len(pdata), np.nan, dtype=dt) if ang > pi: ang = np.radians(ang) if dang: dang = np.radians(dang) odata_corner = odata['corner'] odata_orient = odata['orient'] odata_cdisp = odata['cdisp'] full_ids = pdata['id'] id_ok = full_ids[0] == 0 and np.all(np.diff(full_ids) == 1) print_freq = len(pfsets)//(100 if verbose > 1 else 5) + 1 print 'seeking orientations' for f in pfsets: if verbose and not f % print_freq: print f, fpdata = pfsets[f] fcdata = cfsets[f] cftree = cftrees[f] positions = helpy.consecutive_fields_view(fpdata, 'xy') cpositions = helpy.consecutive_fields_view(fcdata, 'xy') fp_ids = helpy.quick_field_view(fpdata, 'id') for fp_id, posi in it.izip(fp_ids, positions): # TODO could probably be sped up by looping through the output of # ptree.query_ball_tree(ctree) corner, orient, disp = \ find_corner(posi, cpositions, nc=nc, rc=rc, drc=drc, ang=ang, dang=dang, tree=cftree, do_average=do_average) if orient is None: continue full_id = fp_id if id_ok else np.searchsorted(full_ids, fp_id) odata_corner[full_id] = corner odata_orient[full_id] = orient odata_cdisp[full_id] = disp if do_average or nc == 1: mask = np.isfinite(odata['orient']) elif nc > 1: mask = np.all(np.isfinite(odata['orient']), axis=1) return odata, mask