// // state_of_nodes() // boost::shared_ptr<std::vector< std::map<unsigned int, bool> > > state_of_nodes(const HypothesesGraph& g) { LOG(logDEBUG) << "detections(): entered"; shared_ptr<vector< map<unsigned int, bool> > > ret(new vector< map<unsigned int, bool> >); // required node properties: timestep, traxel, active typedef property_map<node_timestep, HypothesesGraph::base_graph>::type node_timestep_map_t; node_timestep_map_t& node_timestep_map = g.get(node_timestep()); typedef property_map<node_traxel, HypothesesGraph::base_graph>::type node_traxel_map_t; node_traxel_map_t& node_traxel_map = g.get(node_traxel()); typedef property_map<node_active, HypothesesGraph::base_graph>::type node_active_map_t; node_active_map_t& node_active_map = g.get(node_active()); // for every timestep for(int t = g.earliest_timestep(); t <= g.latest_timestep(); ++t) { ret->push_back(map<unsigned int, bool>()); for(node_timestep_map_t::ItemIt node_at(node_timestep_map, t); node_at!=lemon::INVALID; ++node_at) { assert(node_traxel_map[node_at].Timestep == t); unsigned int id = node_traxel_map[node_at].Id; bool active = node_active_map[node_at]; (*ret)[t-g.earliest_timestep()][id] = active; } } return ret; }
HypothesesGraph* SingleTimestepTraxel_HypothesesBuilder::add_edges_at(HypothesesGraph* graph, int timestep) const { const HypothesesGraph::node_timestep_map& timemap = graph->get( node_timestep()); typedef property_map<node_traxel, HypothesesGraph::base_graph>::type traxelmap_t; const traxelmap_t& traxelmap = graph->get(node_traxel()); const TraxelStoreByTimeid& traxels_by_timeid = ts_->get<by_timeid>(); const TraxelStoreByTimestep& traxels_by_timestep = ts_->get<by_timestep>(); //// find k nearest neighbors in next timestep // init nearest neighbor search pair<TraxelStoreByTimestep::const_iterator, TraxelStoreByTimestep::const_iterator> traxels_at = traxels_by_timestep.equal_range(timestep + 1); for (TraxelStoreByTimestep::const_iterator it = traxels_at.first; it != traxels_at.second; ++it) { assert(it->Timestep == (timestep+1)); } NearestNeighborSearch nns(traxels_at.first, traxels_at.second); // establish transition edges between a current node and appropriate nodes in next timestep for (HypothesesGraph::node_timestep_map::ItemIt curr_node(timemap, timestep); curr_node != lemon::INVALID; ++curr_node) { assert(timemap[curr_node] == timestep); assert(traxelmap[curr_node].Timestep == timestep); // search map<unsigned int, double> nearest_neighbors = nns.knn_in_range( traxelmap[curr_node], options_.distance_threshold, options_.max_nearest_neighbors); //// connect current node with k nearest neighbor nodes for (map<unsigned int, double>::const_iterator neighbor = nearest_neighbors.begin(); neighbor != nearest_neighbors.end(); ++neighbor) { // connect with one of the neighbor nodes TraxelStoreByTimeid::iterator neighbor_traxel = traxels_by_timeid.find( boost::make_tuple(timestep + 1, neighbor->first)); assert(neighbor_traxel->Timestep == (timestep + 1)); assert(neighbor_traxel->Timestep != traxelmap[curr_node].Timestep); traxelmap_t::ItemIt neighbor_node(traxelmap, *neighbor_traxel); assert(curr_node != neighbor_node); graph->addArc(curr_node, neighbor_node); } } return graph; }
boost::shared_ptr<std::vector< std::vector<Event> > > events(const HypothesesGraph& g) { LOG(logDEBUG) << "events(): entered"; shared_ptr<std::vector< std::vector<Event> > > ret(new vector< vector<Event> >); typedef property_map<node_timestep, HypothesesGraph::base_graph>::type node_timestep_map_t; node_timestep_map_t& node_timestep_map = g.get(node_timestep()); typedef property_map<node_traxel, HypothesesGraph::base_graph>::type node_traxel_map_t; node_traxel_map_t& node_traxel_map = g.get(node_traxel()); // for every timestep LOG(logDEBUG1) << "events(): earliest_timestep: " << g.earliest_timestep(); LOG(logDEBUG1) << "events(): latest_timestep: " << g.latest_timestep(); for(int t = g.earliest_timestep(); t < g.latest_timestep(); ++t) { LOG(logDEBUG2) << "events(): processing timestep: " << t; ret->push_back(vector<Event>()); // for every node: destiny LOG(logDEBUG2) << "events(): for every node: destiny"; for(node_timestep_map_t::ItemIt node_at(node_timestep_map, t); node_at!=lemon::INVALID; ++node_at) { assert(node_traxel_map[node_at].Timestep == t); // count ougoing arcs int count = 0; for(HypothesesGraph::base_graph::OutArcIt a(g, node_at); a!=lemon::INVALID; ++a) ++count; LOG(logDEBUG3) << "events(): counted outgoing arcs: " << count; // construct suitable Event object switch(count) { // Disappearance case 0: { Event e; e.type = Event::Disappearance; e.traxel_ids.push_back(node_traxel_map[node_at].Id); (*ret)[t-g.earliest_timestep()].push_back(e); LOG(logDEBUG3) << e; break; } // Move case 1: { Event e; e.type = Event::Move; e.traxel_ids.push_back(node_traxel_map[node_at].Id); HypothesesGraph::base_graph::OutArcIt a(g, node_at); e.traxel_ids.push_back(node_traxel_map[g.target(a)].Id); (*ret)[t-g.earliest_timestep()].push_back(e); LOG(logDEBUG3) << e; break; } // Division case 2: { Event e; e.type = Event::Division; e.traxel_ids.push_back(node_traxel_map[node_at].Id); HypothesesGraph::base_graph::OutArcIt a(g, node_at); e.traxel_ids.push_back(node_traxel_map[g.target(a)].Id); ++a; e.traxel_ids.push_back(node_traxel_map[g.target(a)].Id); (*ret)[t-g.earliest_timestep()].push_back(e); LOG(logDEBUG3) << e; break; } default: throw runtime_error("events(): encountered node dividing in three or more nodes in graph"); break; } } // appearances in next timestep LOG(logDEBUG2) << "events(): appearances in next timestep"; for(node_timestep_map_t::ItemIt node_at(node_timestep_map, t+1); node_at!=lemon::INVALID; ++node_at) { // count incoming arcs int count = 0; for(HypothesesGraph::base_graph::InArcIt a(g, node_at); a!=lemon::INVALID; ++a) ++count; LOG(logDEBUG3) << "events(): counted incoming arcs in next timestep: " << count; // no incoming arcs => appearance if(count == 0) { Event e; e.type = Event::Appearance; e.traxel_ids.push_back(node_traxel_map[node_at].Id); (*ret)[t-g.earliest_timestep()].push_back(e); LOG(logDEBUG3) << e; } } } return ret; }
HypothesesGraph* SingleTimestepTraxel_HypothesesBuilder::add_nodes(HypothesesGraph* graph) const { LOG(logDEBUG) << "SingleTimestepTraxel_HypothesesBuilder::add_nodes(): entered"; property_map<node_traxel, HypothesesGraph::base_graph>::type& traxel_m = graph->get(node_traxel()); for(TraxelStoreByTimestep::const_iterator it = ts_->begin(); it!= ts_->end(); ++it) { HypothesesGraph::Node node = graph->add_node(it->Timestep); traxel_m.set(node, *it); } return graph; }
//// //// class SingleTimestepTraxel_HypothesesBuilder //// HypothesesGraph* SingleTimestepTraxel_HypothesesBuilder::construct() const { HypothesesGraph* graph = new HypothesesGraph(); // store traxels inside the graph data structure graph->add(node_traxel()); return graph; }
//// //// class ConsTracking //// vector<vector<Event> > ConsTracking::operator()(TraxelStore& ts) { cout << "-> building energy functions " << endl; double detection_weight = 10; Traxels empty; boost::function<double(const Traxel&, const size_t)> detection, division; boost::function<double(const double)> transition; bool use_classifier_prior = false; Traxel trax = *(ts.begin()); FeatureMap::const_iterator it = trax.features.find("detProb"); if(it != trax.features.end()) { use_classifier_prior = true; } if (use_classifier_prior) { LOG(logINFO) << "Using classifier prior"; detection = NegLnDetection(detection_weight); } else if (use_size_dependent_detection_) { LOG(logINFO) << "Using size dependent prior"; vector<double> means; if (means_.size() == 0 ) { for(int i = 0; i<max_number_objects_+1; ++i) { means.push_back(i*avg_obj_size_); LOG(logINFO) << "mean[" << i << "] = " << means[i]; } } else { assert(sigmas_.size() != 0); for(int i = 0; i<max_number_objects_+1; ++i) { means.push_back(means_[i]); LOG(logINFO) << "mean[" << i << "] = " << means[i]; } } vector<double> sigma2; if (sigmas_.size() == 0) { double s2 = (avg_obj_size_*avg_obj_size_)/4.0; if (s2 < 0.0001) { s2 = 0.0001; } for(int i = 0; i<max_number_objects_+1; ++i) { sigma2.push_back(s2); LOG(logINFO) << "sigma2[" << i << "] = " << sigma2[i]; } } else { for (int i = 0; i<max_number_objects_+1; ++i) { sigma2.push_back(sigmas_[i]); LOG(logINFO) << "sigma2[" << i << "] = " << sigma2[i]; } } for(TraxelStore::iterator tr = ts.begin(); tr != ts.end(); ++tr) { Traxel trax = *tr; FeatureMap::const_iterator it = trax.features.find("count"); if(it == trax.features.end()) { throw runtime_error("get_detection_prob(): cellness feature not in traxel"); } double vol = it->second[0]; vector<double> detProb; detProb = computeDetProb(vol,means,sigma2); feature_array detProbFeat(feature_array::difference_type(max_number_objects_+1)); for(int i = 0; i<=max_number_objects_; ++i) { double d = detProb[i]; if (d < 0.01) { d = 0.01; } else if (d > 0.99) { d = 0.99; } LOG(logDEBUG2) << "detection probability for " << trax.Id << "[" << i << "] = " << d; detProbFeat[i] = d; } trax.features["detProb"] = detProbFeat; ts.replace(tr, trax); } detection = NegLnDetection(detection_weight); // weight 1 } else { LOG(logINFO) << "Using hard prior"; // assume a quasi geometric distribution vector<double> prob_vector; double p = 0.7; // e.g. for max_number_objects_=3, p=0.7: P(X=(0,1,2,3)) = (0.027, 0.7, 0.21, 0.063) double sum = 0; for(double state = 0; state < max_number_objects_; ++state) { double prob = p*pow(1-p,state); prob_vector.push_back(prob); sum += prob; } prob_vector.insert(prob_vector.begin(), 1-sum); detection = bind<double>(NegLnConstant(detection_weight,prob_vector), _2); } LOG(logDEBUG1) << "division_weight_ = " << division_weight_; LOG(logDEBUG1) << "transition_weight_ = " << transition_weight_; division = NegLnDivision(division_weight_); transition = NegLnTransition(transition_weight_); cout << "-> building hypotheses" << endl; SingleTimestepTraxel_HypothesesBuilder::Options builder_opts(1, // max_nearest_neighbors max_dist_, true, // forward_backward with_divisions_, // consider_divisions division_threshold_ ); SingleTimestepTraxel_HypothesesBuilder hyp_builder(&ts, builder_opts); HypothesesGraph* graph = hyp_builder.build(); LOG(logDEBUG1) << "ConsTracking(): adding distance property to edges"; HypothesesGraph& g = *graph; g.add(arc_distance()).add(tracklet_intern_dist()).add(node_tracklet()).add(tracklet_intern_arc_ids()).add(traxel_arc_id()); property_map<arc_distance, HypothesesGraph::base_graph>::type& arc_distances = g.get(arc_distance()); property_map<node_traxel, HypothesesGraph::base_graph>::type& traxel_map = g.get(node_traxel()); bool with_optical_correction = false; Traxel some_traxel = (*traxel_map.beginValue()); if (some_traxel.features.find("com_corrected") != some_traxel.features.end()) { LOG(logINFO) << "optical correction enabled"; with_optical_correction = true; } for(HypothesesGraph::ArcIt a(g); a!=lemon::INVALID; ++a) { HypothesesGraph::Node from = g.source(a); HypothesesGraph::Node to = g.target(a); Traxel from_tr = traxel_map[from]; Traxel to_tr = traxel_map[to]; if (with_optical_correction) { arc_distances.set(a, from_tr.distance_to_corr(to_tr)); } else { arc_distances.set(a, from_tr.distance_to(to_tr)); } } //border_width_ is given in normalized scale, 1 corresponds to a maximal distance of dim_range/2 boost::function<double(const Traxel&)> appearance_cost_fn, disappearance_cost_fn; LOG(logINFO) << "using border-aware appearance and disappearance costs, with absolute margin: " << border_width_; appearance_cost_fn = SpatialBorderAwareWeight(appearance_cost_, border_width_, false, // true if relative margin to border fov_); disappearance_cost_fn = SpatialBorderAwareWeight(disappearance_cost_, border_width_, false, // true if relative margin to border fov_); cout << "-> init ConservationTracking reasoner" << endl; ConservationTracking pgm( max_number_objects_, detection, division, transition, forbidden_cost_, ep_gap_, with_tracklets_, with_divisions_, disappearance_cost_fn, appearance_cost_fn, true, // with_misdetections_allowed true, // with_appearance true, // with_disappearance transition_parameter_, with_constraints_ ); cout << "-> formulate ConservationTracking model" << endl; pgm.formulate(*graph); cout << "-> infer" << endl; pgm.infer(); cout << "-> conclude" << endl; pgm.conclude(*graph); cout << "-> storing state of detection vars" << endl; last_detections_ = state_of_nodes(*graph); cout << "-> pruning inactive hypotheses" << endl; prune_inactive(*graph); cout << "-> constructing unresolved events" << endl; boost::shared_ptr<std::vector< std::vector<Event> > > ev = events(*graph); if (max_number_objects_ > 1 && with_merger_resolution_ && all_true(ev->begin(), ev->end(), has_data<Event>)) { cout << "-> resolving mergers" << endl; MergerResolver m(graph); FeatureExtractorMCOMsFromMCOMs extractor; DistanceFromCOMs distance; FeatureHandlerFromTraxels handler(extractor, distance); calculate_gmm_beforehand(*graph, 1, number_of_dimensions_); m.resolve_mergers(handler); HypothesesGraph g_res; resolve_graph(*graph, g_res, transition, ep_gap_, with_tracklets_, transition_parameter_, with_constraints_); prune_inactive(*graph); cout << "-> constructing resolved events" << endl; boost::shared_ptr<std::vector< std::vector<Event> > > multi_frame_moves = multi_frame_move_events(*graph); cout << "-> merging unresolved and resolved events" << endl; return *merge_event_vectors(*ev, *multi_frame_moves); } else { return *ev; } }