def find_tracks(pdata, maxdist=20, giveup=10, n=0, cut=False, stub=0): """ Track dots from frame-to-frame, giving each particle a unique and persistent id, called the trackid. parameters ---------- pdata : the main positions data array maxdist : maximal separation in pixels between a particles current and previous position. i.e., the maximum distance a particle is allowed to travel to be considered part of the same track A good choice for this value is the size of one particle. giveup : maximal number of frames to recurse over seeking the parent n : the number of particles to track, useful if you wish to have one track per physical particle. Not useful if you want tracks to be cut when the particle hits the boundary cut : whether or not to cut tracks (assign a new trackid to the same physical particle) when the particle nears or hits the boundary if True, it requires either args.boundary or for user to click on an image to mark the center and boundary. Particle at the boundary (between two tracks) will have track id of -1 stub : minimal length of a track for it to be kept. trackids of any track with length less than `stub` will be set to -1 returns ------- trackids : an array of length `len(pdata)`, giving the track id number for each point in data. Any point not belonging to any track has a track id of -1 """ from sys import setrecursionlimit, getrecursionlimit setrecursionlimit(max(getrecursionlimit(), 2*giveup)) trackids = -np.ones(pdata.shape, dtype=int) if n is True: # use the mode of number of particles per frame # np.argmax(np.bincount(x)) == mode(x) n = np.argmax(np.bincount(np.bincount(pdata['f']))) print "Found {n} particles, will use {n} longest tracks".format(n=n) if cut: if args.boundary: print "cutting at supplied boundary" x0, y0, R = args.boundary elif 'track_cut_boundary' in meta: print "cutting at previously saved boundary" x0, y0, R = meta['track_cut_boundary'] else: not_found = ('Please give the path to a tiff image ' 'from this dataset to identify boundary\n') bgimage = helpy.find_first_frame([locdir, prefix], err=not_found) x0, y0, R = helpy.circle_click(bgimage) print "cutting at selected boundary (x0, y0, r):", x0, y0, R # assume 6mm particles if S not specified mm = R/101.6 # R = 4 in = 101.6 mm margin = S if S>1 else 6*mm meta['track_cut_boundary'] = (x0, y0, R) meta['track_cut_margin'] = margin print 'Cutting with margin {:.1f} pix = {:.1f} mm'.format(margin, margin/mm) rs = np.hypot(pdata['x'] - x0, pdata['y'] - y0) cut = rs > R - margin print "seeking tracks" for i in xrange(len(pdata)): # This must remain a simple loop because trackids gets modified and # passed into the function with each iteration trackids[i] = find_closest(pdata.item(i), trackids, maxdist=maxdist, giveup=giveup, cut=cut) if verbose: assert len(pdata) == len(trackids), "too few/many trackids" assert np.allclose(pdata['id'], np.arange(len(pdata))), "gap in particle id" if n or stub > 0: track_lens = np.bincount(trackids+1)[1:] if n: stubs = np.argsort(track_lens)[:-n] # all but the longest n elif stub > 0: stubs = np.where(track_lens < stub)[0] if verbose: print "removing {} stubs".format(len(stubs)) if n or stub > 0: stubs = np.in1d(trackids, stubs) trackids[stubs] = -1 return trackids
dt0 = 10 # here's assuming... dtau = 10 # should be true for all from before dt* was saved if args.save: helpy.save_meta(absprefix, meta) if __name__=='__main__': if args.plotmsd: if verbose: print 'plotting msd now!' plot_msd(msds, msdids, dtau, dt0, data['f'].max()+1, tnormalize=False, prefix=absprefix, show_tracks=args.showtracks, show=args.show, singletracks=args.singletracks, fps=fps, S=S, save=args.save, kill_flats=args.killflat, kill_jumps=args.killjump*S*S) if args.plottracks: if verbose: print 'plotting tracks now!' bgimage = helpy.find_first_frame([locdir, prefix]) if args.singletracks: mask = np.in1d(trackids, args.singletracks) else: mask = None plot_tracks(data, trackids, bgimage, mask=mask, save=args.save, show=args.show) if __name__=='__main__' and args.nn: # Calculate the <nn> correlation for all the tracks in a given dataset # TODO: fix this to combine multiple datasets (more than one prefix) if args.verbose: print 'calculating <nn> correlations for track' coscorrs = [] sincorrs = []