def find_flies(old0, old1, obs): """All arguments are EllipseLists. Returns an EllipseList.""" # possibly matchidentities should be smart enough to deal with this case # instead of handling it specially here if len(obs) == 0: flies = ell.TargetList() #for e in old1: # flies.append( Ellipse() ) # no obs for any target return flies # make predicted targets targ = m_id.cvpred(old0, old1) # make a cost matrix containing the distance from each target to each obs ids = [] for i in targ.iterkeys(): ids.append(i) vals = [] for i in targ.itervalues(): vals.append(i) cost = num.zeros((len(obs), len(targ))) for i, observation in enumerate(obs): for j, target in enumerate(vals): if target.isDummy(): cost[i, j] = params.max_jump + eps # will be ignored else: cost[i, j] = observation.dist(target) # find optimal matching between targ and observations obs_for_target, unass_obs = m_id.matchidentities(cost) # make a new list containing the best matches to each prediction flies = ell.TargetList() for tt in range(len(targ)): if obs_for_target[tt] >= 0: obs[obs_for_target[tt]].identity = ids[tt] flies.append(obs[obs_for_target[tt]]) #else: # flies.append( Ellipse() ) # empty ellipse as a placeholder # append the targets that didn't match any observation for oo in range(len(obs)): if unass_obs[oo]: obs[oo].identity = params.nids params.nids += 1 flies.append(obs[oo]) return (flies, obs_for_target, unass_obs)
def cvpred(X1, X2): """Make prediction (target) based on two observations. Expects two EllipseLists, returns a single EllipseList.""" X3 = ell.TargetList() # set position and size as an extrapolation for ee in X2.iterkeys(): if X1.hasItem(ee): # only use the cv prediction if not jumping dx = X2[ee].center.x - X1[ee].center.x dy = X2[ee].center.y - X1[ee].center.y centerd = num.sqrt((dx**2. + dy**2.)) if centerd >= params.min_jump: new_x = X2[ee].center.x new_y = X2[ee].center.y dangle = X2[ee].angle else: new_x = X2[ee].center.x + (1. - params.dampen) * dx new_y = X2[ee].center.y + (1. - params.dampen) * dy dangle = ((X2[ee].angle - X1[ee].angle + num.pi/2.) \ % (num.pi)) - (num.pi/2.) new_w = X2[ee].size.width new_h = X2[ee].size.height new_angle = X2[ee].angle + (1. - params.angle_dampen) * dangle X3.append( ell.Ellipse(new_x, new_y, new_w, new_h, new_angle, X2[ee].identity)) else: X3.append(X2[ee].copy()) return X3
def GetTargetMotion(self): # get current positions obs_curr = self.GetObsFiltered() # get previous positions obs_prev = self.GetObsPrev() # give identities to previous positions target_prev = ell.TargetList() for i, obs in enumerate(obs_prev): obs.identity = i target_prev.append(obs) # match previous and current targets, no velocity oldnids = params.params.nids target_curr = ell.find_flies(target_prev, target_prev, obs_curr) # don't actually assign new identities params.params.nids = oldnids # delete targets that aren't in both frames keyscurr = set(target_curr.keys()) keysprev = set(target_prev.keys()) keysremove = keyscurr - keysprev for i in keysremove: tmp = target_curr.pop(i) keysremove = keysprev - keyscurr for i in keysremove: tmp = target_prev.pop(i) # compute predicted positions target_pred = cvpred(target_prev, target_curr) # store targetmotion = (target_prev, target_curr, target_pred) # return return targetmotion
Y += ellipse.center.y h = mpl.plot(X, Y, format, **params) return h try: os.remove('tmp.ann') except: pass tracks = ann.AnnotationFile('tmp.ann', None, True, False, False) tracks.InitializeData(0, -1) tracks.InitializeBufferForTracking(0) # tracks = [] # frame 0 tracks.append(ell.TargetList()) # just one ellipse with id = 0 tracks[0][0] = ell.Ellipse(10., 10., 1., 2., num.pi / 3, 0., 0) tracks[0][0].compute_area() # frame 1 # just one ellipse with id = 0 tracks.append(ell.TargetList()) tracks[1][0] = tracks[0][0].copy() tracks[1][0].x += 10. tracks[1][0].y += 10. # frame 2 # detection missed at pred # new ellipse at another location tracks.append(ell.TargetList()) #tracks[2][1] = ell.Ellipse(20.,20.,1.,2.,num.pi/3,0.,1) prev = tracks[0].copy()
def Track(self): """Run the m-tracker.""" ## initialization ## if DEBUG: print "Tracking from frame %d..." % self.start_frame if DEBUG: print "Last frame tracked = %d" % self.ann_file.lastframetracked print "YL:" print " bg_type", self.bg_imgs.bg_type print " norm_type", self.bg_imgs.norm_type print " thresh", params.n_bg_std_thresh, params.n_bg_std_thresh_low print " area", params.maxshape.area, params.minshape.area print " max_jump", params.max_jump, params.max_jump_split print " use_shadow_detector", params.use_shadow_detector print " recalc_bg_minutes", params.recalc_bg_minutes print " recalc_n_frames", self.movie.recalc_n_frames() print " fps %.1f" % self.movie.get_fps() strt = time.clock() if params.use_shadow_detector: fx, fy = self.matchTemplate() print " fx, fy", fx, fy bx = (fx[0] + fx[1]) / 2 # maximum number of frames we will look back to fix errors self.maxlookback = max(params.lostdetection_length, params.spuriousdetection_length, params.mergeddetection_length, params.splitdetection_length) if params.interactive: wx.Yield() # initialize hindsight data structures self.hindsight = hindsight.Hindsight(self.ann_file, self.bg_imgs) self.break_flag = False if DEBUG: print "Initializing buffer for tracking" self.ann_file.InitializeBufferForTracking(self.start_frame) # initialize dfore and connected component buffer self.bg_imgs.set_buffer_maxnframes() rc, rnf, bgs, nf = 0, self.movie.recalc_n_frames( ), [], self.movie.get_n_frames() def appendBg(): bgRw = self.bg_imgs.centers if self.bg_imgs.varying_bg else [ self.bg_imgs.center ] bgs.append( dict(bgs=[bg.astype(num.float32) for bg in bgRw], varying_bg=self.bg_imgs.varying_bg, mean_separator=self.bg_imgs.mean_separator)) appendBg() for self.start_frame in range(self.start_frame, nf): # KB 20120109 added last_frame command-line option if self.start_frame >= self.last_frame: break if DEBUG_LEVEL > 0: print "Tracking frame %d / %d" % (self.start_frame, nf - 1) #if DEBUG: # break if self.break_flag: break last_time = time.time() # recalculate background? rc += 1 if rnf > 0 and rc > rnf: if nf - self.start_frame > rnf / 2: assert self.start_frame % rnf == 0 # note: makes it easy to calculate which background was used; # not required for tracking self.bg_imgs.bg_firstframe = self.start_frame self.bg_imgs.bg_lastframe = self.start_frame + rnf - 1 self.OnComputeBg() appendBg() rc = 1 # perform background subtraction #try: (self.dfore,self.isfore,self.cc,self.ncc) = \ self.bg_imgs.sub_bg( self.start_frame, dobuffer=True ) #except: # # catch all error types here, and just break out of loop # break # write to sbfmf if self.dowritesbfmf: self.movie.writesbfmf_writeframe(self.isfore, self.bg_imgs.curr_im, self.bg_imgs.curr_stamp, self.start_frame) # process gui events if params.interactive: wx.Yield() if self.break_flag: break # find observations self.ellipses = ell.find_ellipses(self.dfore, self.cc, self.ncc) # shadow detector if params.use_shadow_detector: ne = 2 * [0] # idx: left, right (chamber) bei, bdist, bgood = 2 * [-1], 2 * [1000], 2 * [None] # best for ei, e in enumerate(self.ellipses): if e.area < params.minshape.area: continue good = e.area >= params.shadow_detector_minarea and ( not e.merged_areas or any(a >= params.minshape.area for a in e.merged_areas)) i = e.center.x > bx ne[i] += 1 dist = num.sqrt((e.center.x - fx[i])**2 + (e.center.y - fy[i])**2) if bei[i] < 0 or good and not bgood[ i] or dist < bdist[i] and good == bgood[i]: bei[i], bdist[i], bgood[i] = ei, dist, good #print "l:%d r:%d" %(ne) # keep only non-shadow ellipses numEll = len(self.ellipses) self.ellipses = [self.ellipses[i] for i in bei if i >= 0] if len(self.ellipses) < numEll: print ">>> kept only", bei #if params.DOBREAK: # print 'Exiting at frame %d'%self.start_frame # sys.exit(1) # process gui events if params.interactive: wx.Yield() if self.break_flag: break # match target identities to observations if len(self.ann_file) > 1: flies = ell.find_flies(self.ann_file[-2], self.ann_file[-1], self.ellipses, self.ann_file) elif len(self.ann_file) == 1: flies = ell.find_flies(self.ann_file[-1], self.ann_file[-1], self.ellipses, self.ann_file) else: flies = ell.TargetList() for i, obs in enumerate(self.ellipses): if obs.isEmpty(): if DEBUG: print 'empty observation' else: newid = self.ann_file.GetNewId() obs.identity = newid flies.append(obs) if DEBUG_LEVEL > 0: print "Done with frame %d, appending to ann_file" % self.start_frame # save to ann_data self.ann_file.append(flies) if DEBUG_LEVEL > 0: print "Added to ann_file, now running fixerrors" # fix any errors using hindsight self.hindsight.fixerrors() #print 'time to fix errors: '+str(time.time() - last_time) # draw? if self.request_refresh or (self.do_refresh and ( (self.start_frame % self.framesbetweenrefresh) == 0)): if params.interactive: if self.start_frame: self.ShowCurrentFrame() else: on = ("on " if self.bg_imgs.on else "off ") if self.bg_imgs.varying_bg else "" print " Frame %d / %d %s[%ds]" \ %(self.start_frame, nf, on, time.clock()-strt) self.request_refresh = False # process gui events if params.interactive: wx.Yield() if self.break_flag: break if (self.start_frame % 100) == 0 and self.has('diagnostics_filename'): self.write_diagnostics() # save ongoing self.saveBackgrounds(bgs) self.Finish()
def run_movie(moviefile, comms): """Run new-style tracking for a test movie.""" quit_val = comms['quit_val'] cmp_list = comms['cmp_list'] shape_dict = comms['shape_dict'] movie, bg_model, ann_file, hindsight = setup_tracking(moviefile, False) if quit_val.value > 0: return try: test_shape_bounds() except: print "**aborting with invalid shape bounds" print "minshape", params.minshape print "maxshape", params.maxshape print_vals() quit_val.value = 1 raise shape_dict['minshape'] = params.minshape shape_dict['meanshape'] = params.meanshape shape_dict['maxshape'] = params.maxshape fst = time.time() params.start_frame = 0 if MAX_FRAMES is None: max_frames = movie.get_n_frames() else: max_frames = min(movie.get_n_frames(), MAX_FRAMES) for frame in range(max_frames): if cmp_list is not None: counts = [] # perform background subtraction (dfore, isfore, cc, ncc) = bg_model.sub_bg(frame) # find observations if PRINT_COUNTS and (frame == PRINT_FRAME or PRINT_FRAME is None): print frame, "ncc", ncc if cmp_list is not None: counts.append(ncc) ellipses = ell.find_ellipses(dfore, cc, ncc) if PRINT_COUNTS and (frame == PRINT_FRAME or PRINT_FRAME is None): print frame, "found ellipses", len(ellipses) if cmp_list is not None: counts.append(len(ellipses)) try: test_ellipses(ellipses) except AssertionError: print "**find_ellipses output error in frame", frame print_vals() quit_val.value = 1 raise # match target identities to observations if len(ann_file) > 1: flies = ell.find_flies(ann_file[-2], ann_file[-1], ellipses, ann_file) elif len(ann_file) == 1: flies = ell.find_flies(ann_file[-1], ann_file[-1], ellipses, ann_file) else: flies = ell.TargetList() for i, obs in enumerate(ellipses): newid = ann_file.GetNewId() obs.identity = newid flies.append(obs) try: test_ellipses(flies) except AssertionError: print "**find_flies output error in frame", frame print_vals() quit_val.value = 1 raise if PRINT_COUNTS and (frame == PRINT_FRAME or PRINT_FRAME is None): print frame, "found flies", len(flies) if cmp_list is not None: counts.append(len(flies)) ann_file.append(flies) # fix any errors using hindsight if PRINT_COUNTS and (frame == PRINT_FRAME or PRINT_FRAME is None): print frame, "pre-hindsight", len(ann_file[-1]) if cmp_list is not None: counts.append(len(ann_file[-1])) hindsight.fixerrors() if PRINT_COUNTS and (frame == PRINT_FRAME or PRINT_FRAME is None): print frame, "post-hindsight", len(ann_file[-1]) if cmp_list is not None: counts.append(len(ann_file[-1])) try: test_ellipses(ann_file[-1]) except AssertionError: print "**hindsight output error in frame", frame print_vals() quit_val.value = 1 raise if frame % 500 == 0: print "__tracking", frame, "/", movie.get_n_frames() if quit_val.value > 0: return if cmp_list is not None: cmp_list.append((counts, ann_file[-1])) ann_file.close() at = (time.time() - fst) / max_frames print "avg. per frame: %.3f s" % (at)
def run_movie_pre4(moviefile, comms): """Run old-style tracking for a test movie.""" quit_val = comms['quit_val'] cmp_list = comms['cmp_list'] shape_dict = comms['shape_dict'] movie, bg_model, ann_file, hindsight = setup_tracking(moviefile, True) params.movie = movie if quit_val.value > 0: return try: test_shape_bounds() except: print "**aborting pre4 with invalid shape bounds" print "minshape", params.minshape print "maxshape", params.maxshape print_vals() quit_val.value = 1 raise if shape_dict is not None: while not shape_dict.has_key('maxshape'): time.sleep(0.5) if quit_val.value > 0: return try: assert (shape_dict['minshape'] == params.minshape) assert (shape_dict['meanshape'] == params.meanshape) assert (shape_dict['maxshape'] == params.maxshape) except AssertionError: print "**aborting after shape mismatch" print "minshape", shape_dict['minshape'] print "pre4 minshape", params.minshape print "meanshape", shape_dict['meanshape'] print "pre4 meanshape", params.meanshape print "maxshape", shape_dict['maxshape'] print "pre4 maxshape", params.maxshape print_vals() quit_val.value = 1 raise fst = time.time() params.start_frame = 0 if MAX_FRAMES is None: max_frames = movie.get_n_frames() else: max_frames = min(movie.get_n_frames(), MAX_FRAMES) for frame in range(max_frames): # perform background subtraction (dfore, isfore, cc, ncc) = bg_model.sub_bg(frame, dobuffer=True) # find observations if PRINT_COUNTS: print "pre4", frame, "ncc", ncc ellipses = ell_pre4.find_ellipses(dfore, cc, ncc) if PRINT_COUNTS: print "pre4", frame, "found ellipses", len(ellipses) try: test_ellipses(ellipses) except AssertionError: print "**find_ellipse output error in pre4 frame", frame print_vals() quit_val.value = 1 raise # match target identities to observations if len(ann_file) > 1: flies = ell.find_flies(ann_file[-2], ann_file[-1], ellipses, ann_file) elif len(ann_file) == 1: flies = ell.find_flies(ann_file[-1], ann_file[-1], ellipses, ann_file) else: flies = ell.TargetList() for i, obs in enumerate(ellipses): newid = ann_file.GetNewId() obs.identity = newid flies.append(obs) try: test_ellipses(flies) except AssertionError: print "**find_flies output error in pre4 frame", frame print_vals() quit_val.value = 1 raise if PRINT_COUNTS: print "pre4", frame, "found flies", len(flies) ann_file.append(flies) # fix any errors using hindsight if PRINT_COUNTS: print "pre4", frame, "pre-hindsight", len(ann_file[-1]) hindsight.fixerrors() if PRINT_COUNTS: print "pre4", frame, "post-hindsight", len(ann_file[-1]) try: test_ellipses(ann_file[-1]) except AssertionError: print "**hindsight output error in pre4 frame", frame print_vals() quit_val.value = 1 raise if frame % 100 == 0: print "__pre4 tracking", frame, "/", movie.get_n_frames() # compare with newly tracked values if cmp_list is not None: while len(cmp_list) <= frame: time.sleep(0.5) if quit_val.value > 0: return old = ann_file[-1] counts, new = cmp_list[frame] if PRINT_COUNTS: print "new counts", counts try: assert (len(new) == len(old)) except AssertionError: print "**aborting after data length error in frame", frame, "new", len( new), "old", len(old) print moviefile print_vals() quit_val.value = 1 raise try: compare_frames(new, old) except AssertionError: print "**data comparison error in frame", frame print "new", new print "old", old print moviefile print_vals() quit_val.value = 1 raise if quit_val.value > 0: return ann_file.close() at = (time.time() - fst) / max_frames print "pre4 avg. per frame: %.3f s" % (at) #bt = num.mean( num.array( bgsub_times ) ) #print "pre4 bg. sub: %.3f (%.1f%%); ellipses: %.3f (%.1f%%); flies: %.3f (%.1f%%); hindsight: %.3f (%.1f%%)" % (bt, 100.*bt/at, et, 100.*et/at, ft, 100.*ft/at, ht, 100.*ht/at) params.movie = None
def add_fly(annfile, x, y, theta): flies = ell.TargetList() flies.append(ell.Ellipse(x, y, 5., 10., theta, 25., 0)) annfile.append(flies)
def Track(self): """Run the tracker.""" ## initialization ## if DEBUG: print "Tracking from frame %d..." % self.start_frame if DEBUG: print "Last frame tracked = %d" % self.ann_file.lastframetracked # maximum number of frames we will look back to fix errors self.maxlookback = max(params.lostdetection_length, params.spuriousdetection_length, params.mergeddetection_length, params.splitdetection_length) if params.interactive: wx.Yield() # initialize hindsight data structures self.hindsight = hindsight.Hindsight(self.ann_file, self.bg_imgs) # initialize dfore and connected component buffer self.bg_imgs.set_buffer_maxnframes() self.track_timer_start_time = time.time() self.update_track_time() self.break_flag = False for self.start_frame in range(self.start_frame, self.movie.get_n_frames()): if DEBUG or DEBUG_TRACKINGSETTINGS: print "frame", self.start_frame # KB 20120109 added last_frame command-line option if self.start_frame >= self.last_frame: break if DEBUG_LEVEL > 0: print "Tracking frame %d / %d" % ( self.start_frame, self.movie.get_n_frames() - 1) if self.break_flag: break last_time = time.time() # perform background subtraction try: (dfore, isfore, cc, ncc) = self.bg_imgs.sub_bg(self.start_frame) except IOError: if self.movie.type == 'cavi' and self.start_frame >= self.movie.get_n_frames( ) - 2: # last frame or so wasn't present, no problem print "ignoring compressed AVI IOError reading last frame" else: traceback.print_exc() break except: # catch all error types here, and just break out of the loop traceback.print_exc() break if DEBUG_LEVEL > 1: print ncc, "connected components" # write to sbfmf if self.dowritesbfmf: self.movie.writesbfmf_writeframe(isfore, self.bg_imgs.curr_im, self.bg_imgs.curr_stamp, self.start_frame) # process gui events if params.interactive: wx.Yield() if self.break_flag: break # find observations ellipses = ell.find_ellipses(dfore, cc, ncc) if DEBUG_LEVEL > 1: print len(ellipses), "ellipses" # process gui events if params.interactive: wx.Yield() if self.break_flag: break # match target identities to observations if DEBUG_LEVEL > 0: print "matching identities" if len(self.ann_file) > 1: flies = ell.find_flies(self.ann_file[-2], self.ann_file[-1], ellipses, self.ann_file) elif len(self.ann_file) == 1: flies = ell.find_flies(self.ann_file[-1], self.ann_file[-1], ellipses, self.ann_file) else: flies = ell.TargetList() for i, obs in enumerate(ellipses): if obs.isEmpty(): if DEBUG: print 'empty observation' else: newid = self.ann_file.GetNewId() obs.identity = newid flies.append(obs) if DEBUG_LEVEL > 1: print len(flies), "flies" if DEBUG_LEVEL > 0: print "Done with frame %d, appending to ann_file" % self.start_frame # save to ann_data self.ann_file.append(flies) # fix any errors using hindsight if DEBUG_LEVEL > 0: print "Added to ann_file, now running fixerrors" self.hindsight.fixerrors() # draw? if self.request_refresh or (self.do_refresh and ( (self.start_frame % self.framesbetweenrefresh) == 0)): if params.interactive: if self.start_frame: self.ShowCurrentFrame() else: print " Frame %d / %d" % (self.start_frame, self.movie.get_n_frames() - 1) self.request_refresh = False if DEBUG_LEVEL > 1: print len(self.ann_file[-1]), "flies in last frame" # process gui events if params.interactive: wx.Yield() if self.break_flag: break if (self.start_frame % 100) == 0 and self.has('diagnostics_filename'): self.write_diagnostics() # save ongoing if hasattr(self, 'timer'): # timer.cancel() should work, but in case it doesn't, set a flag too self.timer.cancel() self.track_timer_cancel = True self.Finish()