コード例 #1
0
ファイル: CTracker.cpp プロジェクト: sshhj89/InhaDriverless
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
void CTracker::Update(vector<Point2f>& detections)
{
    // -----------------------------------
    // If there is no tracks yet, then every point begins its own track.
    // -----------------------------------
    if(tracks.size()==0)
    {
        // If no tracks yet
        for(int i=0;i<detections.size();i++)
        {
            CTrack* tr=new CTrack(detections[i],dt,Accel_noise_mag);
            tracks.push_back(tr);
        }
    }
    
    // -----------------------------------
    // «десь треки уже есть в любом случае
    // -----------------------------------
    int N=tracks.size();		// треки
    int M=detections.size();	// детекты
    
    // ћатрица рассто¤ний от N-ного трека до M-ного детекта.
    vector< vector<double> > Cost(N,vector<double>(M));
    vector<int> assignment; // назначени¤
    
    // -----------------------------------
    // “реки уже есть, составим матрицу рассто¤ний
    // -----------------------------------
    double dist;
    for(int i=0;i<tracks.size();i++)
    {
         Point2d prediction=tracks[i]->prediction;
        for(int j=0;j<detections.size();j++)
        {
            //cal prediction and detection
            Point2d diff=(tracks[i]->prediction-detections[j]);
            dist=sqrtf(diff.x*diff.x+diff.y*diff.y);
            Cost[i][j]=dist;
        }
    }
    // -----------------------------------
    // Solving assignment problem (tracks and predictions of Kalman filter)
    // -----------------------------------
    AssignmentProblemSolver APS;
    APS.Solve(Cost,assignment,AssignmentProblemSolver::optimal);
    
    // -----------------------------------
    // clean assignment from pairs with large distance
    // -----------------------------------
    // Not assigned tracks
    vector<int> not_assigned_tracks;
    
    for(int i=0;i<assignment.size();i++)
    {
        if(assignment[i]!=-1)
        {
            if(Cost[i][assignment[i]]>dist_thres)
            {
                assignment[i]=-1;
                // Mark unassigned tracks, and increment skipped frames counter,
                // when skipped frames counter will be larger than threshold, track will be deleted.
                not_assigned_tracks.push_back(i);
            }
        }
        else
        {
            // If track have no assigned detect, then increment skipped frames counter.
            tracks[i]->skipped_frames++;
        }
        
    }
    
    // -----------------------------------
    // If track didn't get detects long time, remove it.
    // -----------------------------------
    for(int i=0;i<tracks.size();i++)
    {
        if(tracks[i]->skipped_frames>maximum_allowed_skipped_frames)
        {
            delete tracks[i];
            tracks.erase(tracks.begin()+i);
            assignment.erase(assignment.begin()+i);
            i--;
        }
    }
    // -----------------------------------
    // Search for unassigned detects
    // -----------------------------------
    vector<int> not_assigned_detections;
    vector<int>::iterator it;
    for(int i=0;i<detections.size();i++)
    {
        it=find(assignment.begin(), assignment.end(), i);
        if(it==assignment.end())
        {
            not_assigned_detections.push_back(i);
        }
    }
    
    // -----------------------------------
    // and start new tracks for them.
    // -----------------------------------
    if(not_assigned_detections.size()!=0)
    {
        for(int i=0;i<not_assigned_detections.size();i++)
        {
            CTrack* tr=new CTrack(detections[not_assigned_detections[i]],dt,Accel_noise_mag);
            tracks.push_back(tr);
        }
    }
    
    // Update Kalman Filters state
    
    for(int i=0;i<assignment.size();i++)
    {
        // If track updated less than one time, than filter state is not correct.
        
        tracks[i]->KF->GetPrediction();
        
        if(assignment[i]!=-1) // If we have assigned detect, then update using its coordinates,
        {
            tracks[i]->skipped_frames=0;
            tracks[i]->prediction=tracks[i]->KF->Update(detections[assignment[i]],1);
        }else				  // if not continue using predictions
        {
            tracks[i]->prediction=tracks[i]->KF->Update(Point2f(0,0),0);	
        }
        
        if(tracks[i]->trace.size()>max_trace_length)
        {
            tracks[i]->trace.erase(tracks[i]->trace.begin(),tracks[i]->trace.end()-max_trace_length);
        }
        
        tracks[i]->trace.push_back(tracks[i]->prediction);
        tracks[i]->KF->LastResult=tracks[i]->prediction;
    }
    
}
コード例 #2
0
ファイル: track3d.cpp プロジェクト: FRC900/2016VisionCode
// Process a set of detected rectangles
// Each will either match a previously detected object or
// if not, be added as new object to the list
void TrackedObjectList::processDetect(const vector<Rect> &detectedRects,
									  const vector<float> &depths,
									  const vector<ObjectType> &types)
{
	vector<Point3f> detectedPositions;
#ifdef VERBOSE_TRACK
	if (detectedRects.size() || list_.size())
		cout << "---------- Start of process detect --------------" << endl;
	print();
	if (detectedRects.size() > 0)
		cout << detectedRects.size() << " detected objects" << endl;
#endif
	for (size_t i = 0; i < detectedRects.size(); i++)
	{
		detectedPositions.push_back(
				screenToWorldCoords(detectedRects[i], depths[i], fovSize_, imageSize_, cameraElevation_));
#ifdef VERBOSE_TRACK
		cout << "Detected rect [" << i << "] = " << detectedRects[i] << " positions[" << detectedPositions.size() - 1 << "]:" << detectedPositions[detectedPositions.size()-1] << endl;
#endif
	}
	// TODO :: Combine overlapping detections into one?

	// Maps tracks to the closest new detected object.
	// assignment[track] = index of closest detection
	vector<int> assignment;
	if (list_.size())
	{
		size_t tracks = list_.size();		          // number of tracked objects from prev frames
		size_t detections = detectedPositions.size(); // number of detections this frame

		//Cost[t][d] is the distance between old tracked location t
		//and newly detected object d's position 
		vector< vector<double> > Cost(tracks,vector<double>(detections));

		// Calculate cost for each track->pair combo
		// The cost here is just the distance between them
		// Also check to see if the types are the same, if they are not then set the cost extremely high so that it's never matched
		auto it = list_.cbegin();
		for(size_t t = 0; t < tracks;  ++t, ++it)
		{
			// Point3f prediction=tracks[t]->prediction;
			// cout << prediction << endl;
			for(size_t d = 0; d < detections; d++)
			{
				const ObjectType it_type = it->getType();
				if(types[d] == it_type) {
					Point3f diff = it->getPosition() - detectedPositions[d];
					Cost[t][d] = sqrtf(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z);
				} else {
					Cost[t][d] = numeric_limits<double>::max();
				}
			}
		}

		// Solving assignment problem (find minimum-cost assignment
		// between tracks and previously-predicted positions)
		AssignmentProblemSolver APS;
		APS.Solve(Cost, assignment, AssignmentProblemSolver::optimal);

#ifdef VERBOSE_TRACK
		// assignment[i] holds the index of the detection assigned
		// to track i.  assignment[i] is -1 if no detection was
		// matchedto that particular track
		cout << "After APS : "<<endl;
		for(size_t i = 0; i < assignment.size(); i++)
			cout << i << ":" << assignment[i] << endl;
#endif
		// clear assignment from pairs with large distance
		for(size_t i = 0; i < assignment.size(); i++)
			if ((assignment[i] != -1) && (Cost[i][assignment[i]] > dist_thresh_))
				assignment[i] = -1;
	}

	// Search for unassigned detects and start new tracks for them.
	// This will also handle the case where no tracks are present,
	// since assignment will be empty in that case - everything gets added
	for(size_t i = 0; i < detectedPositions.size(); i++)
	{
		if (find(assignment.begin(), assignment.end(), i) == assignment.end())
		{
#ifdef VERBOSE_TRACK
			cout << "New assignment created " << i << endl;
#endif
			list_.push_back(TrackedObject(detectCount_++, types[i], detectedRects[i], depths[i], fovSize_, imageSize_, cameraElevation_));

#ifdef VERBOSE_TRACK
			cout << "New assignment finished" << endl;
#endif
		}
	}

	auto tr = list_.begin();
	auto as = assignment.begin();
	while ((tr != list_.end()) && (as != assignment.end()))
	{
		// If track updated less than one time, than filter state is not correct.
#ifdef VERBOSE_TRACK
		cout << "Predict: " << endl;
#endif
		Point3f prediction = tr->predictKF();
#ifdef VERBOSE_TRACK
		cout << "prediction:" << prediction << endl;
#endif

		if(*as != -1) // If we have assigned detect, then update using its coordinates
		{
#ifdef VERBOSE_TRACK
			cout << "Update match: " << endl;
#endif
			tr->setPosition(tr->updateKF(detectedPositions[*as]));
#ifdef VERBOSE_TRACK
			cout << tr->getScreenPosition(fovSize_, imageSize_) << endl;
#endif
			tr->setDetected();
		}
		else          // if not continue using predictions
		{
#ifdef VERBOSE_TRACK
			cout << "Update no match: " << endl;
#endif
			tr->setPosition(tr->updateKF(prediction));
#ifdef VERBOSE_TRACK
			cout << tr->getScreenPosition(fovSize_, imageSize_) << endl;
#endif
			tr->clearDetected();
		}

		++tr;
		++as;
	}

	// Remove tracks which haven't been seen in a while
	for (auto it = list_.begin(); it != list_.end(); )
	{
		if (it->tooManyMissedFrames()) // For now just remove ones for
		{                              // which detectList is empty
#ifdef VERBOSE_TRACK
			cout << "Dropping " << it->getId() << endl;
#endif
			it = list_.erase(it);
		}
		else
		{
			++it;
		}
	}
#ifdef VERBOSE_TRACK
	print();
	if (detectedRects.size() || list_.size())
		cout << "---------- End of process detect --------------" << endl;
#endif
}
コード例 #3
0
 void MultiObjectTracker::update(const std::vector<cv::Point2f>& massCenters,
                                 const std::vector<cv::Rect>& boundingRects,
                                 std::vector<OT::TrackingOutput>& trackingOutputs) {
     trackingOutputs.clear();
     
     // If we haven't found any mass centers, just update all the Kalman filters and return their predictions.
     if (massCenters.empty()) {
         for (int i = 0; i < this->kalmanTrackers.size(); i++) {
             // Indicate that the tracker didn't get an update this frame.
             this->kalmanTrackers[i].noUpdateThisFrame();
             
             // Remove the tracker if it is dead.
             if (this->kalmanTrackers[i].getNumFramesWithoutUpdate() > this->missedFramesThreshold) {
                 this->kalmanTrackers.erase(this->kalmanTrackers.begin() + i);
                 i--;
             }
         }
         // Update the remaining trackers.
         for (size_t i = 0; i < this->kalmanTrackers.size(); i++) {
             if (this->kalmanTrackers[i].getLifetime() > lifetimeThreshold) {
                 this->kalmanTrackers[i].predict();
                 trackingOutputs.push_back(this->kalmanTrackers[i].latestTrackingOutput());
             }
         }
         return;
     }
     
     // If there are no Kalman trackers, make one for each detection.
     if (this->kalmanTrackers.empty()) {
         for (auto massCenter : massCenters) {
             this->kalmanTrackers.push_back(OT::KalmanTracker(massCenter,
                                                              this->dt,
                                                              this->magnitudeOfAccelerationNoise));
         }
     }
     
     // Create our cost matrix.
     size_t numKalmans = this->kalmanTrackers.size();
     size_t numCenters = massCenters.size();
     
     std::vector<std::vector<double>> costMatrix(numKalmans, std::vector<double>(numCenters));
 
     std::vector<int> assignment;
     
     
     // Get the latest prediction for the Kalman filters.
     std::vector<cv::Point2f> predictions(this->kalmanTrackers.size());
     for (size_t i = 0; i < this->kalmanTrackers.size(); i++) {
         predictions[i] = this->kalmanTrackers[i].latestPrediction();
     }
     
     // We need to associate each of the mass centers to their corresponding Kalman filter. First,
     // let's find the pairwise distances. However, we first divide this distance by the diagonal size
     // of the frame to ensure that it is between 0 and 1.
     cv::Point framePoint = cv::Point(this->frameSize.width, this->frameSize.height);
     double frameDiagonal = std::sqrt(framePoint.dot(framePoint));
     for (size_t i = 0; i < predictions.size(); i++) {
         for (size_t j = 0; j < massCenters.size(); j++) {
             costMatrix[i][j] = cv::norm(predictions[i] - massCenters[j]) / frameDiagonal;
         }
     }
     
     // Assign Kalman trackers to mass centers with the Hungarian algorithm.
     AssignmentProblemSolver solver;
     solver.Solve(costMatrix, assignment, AssignmentProblemSolver::optimal);
     
     // Unassign any Kalman trackers whose distance to their assignment is too large.
     std::vector<int> kalmansWithoutCenters;
     for (size_t i = 0; i < assignment.size(); i++) {
         if (assignment[i] != -1) {
             if (costMatrix[i][assignment[i]] > this->distanceThreshold) {
                 assignment[i] = -1;
                 kalmansWithoutCenters.push_back(i);
             }
         } else {
             this->kalmanTrackers[i].noUpdateThisFrame();
         }
     }
     
     // If a Kalman tracker is contained in a bounding box and shares its
     // bounding box with another tracker, remove its assignment and mark it
     // as updated.
     for (size_t i = 0; i < assignment.size(); i++) {
         for (size_t j = 0; j < boundingRects.size(); j++) {
             if (boundingRects[j].contains(this->kalmanTrackers[i].latestPrediction())
                 && this->sharesBoundingRect(i, boundingRects[j])) {
                 this->kalmanTrackers[i].gotUpdate();
                 break;
             }
         }
     }
     
     // Remove any trackers that haven't been updated in a while.
     for (int i = 0; i < this->kalmanTrackers.size(); i++) {
         if (this->kalmanTrackers[i].getNumFramesWithoutUpdate() > this->missedFramesThreshold) {
             this->kalmanTrackers.erase(this->kalmanTrackers.begin() + i);
             assignment.erase(assignment.begin() + i);
             i--;
         }
     }
     
     // Find unassigned mass centers.
     std::vector<int> centersWithoutKalman;
     std::vector<int>::iterator it;
     for (size_t i = 0; i < massCenters.size(); i++) {
         it = std::find(assignment.begin(), assignment.end(), i);
         if (it == assignment.end()) {
             centersWithoutKalman.push_back(i);
         }
     }
     
     // Create new trackers for the unassigned mass centers.
     for (size_t i = 0; i < centersWithoutKalman.size(); i++) {
         this->kalmanTrackers.push_back(OT::KalmanTracker(massCenters[centersWithoutKalman[i]]));
     }
     
     // Update the Kalman filters.
     for (size_t i = 0; i < assignment.size(); i++) {
         this->kalmanTrackers[i].predict();
         if (assignment[i] != -1) {
             this->kalmanTrackers[i].correct(massCenters[assignment[i]]);
             this->kalmanTrackers[i].gotUpdate();
         }
     }
     
     // Remove any suppressed filters.
     for (size_t i = 0; i < this->kalmanTrackers.size(); i++) {
         if (this->hasSuppressor(i)) {
             this->kalmanTrackers.erase(this->kalmanTrackers.begin() + i);
             i--;
         }
     }
     
     // Now update the predictions.
     for (size_t i = 0; i < this->kalmanTrackers.size(); i++) {
         if (this->kalmanTrackers[i].getLifetime() > this->lifetimeThreshold) {
             trackingOutputs.push_back(this->kalmanTrackers[i].latestTrackingOutput());
         }
     }
 }
コード例 #4
0
ファイル: Ctracker.cpp プロジェクト: g0mb4/ProjectEdison
void CTracker::Update(vector<Point2d>& detections, float starttime)
{
	// -----------------------------------
	// Если треков еще нет, то начнем для каждой точки по треку
	// -----------------------------------
	if(tracks.size()==0)
	{
		// Если еще нет ни одного трека
		for(int i=0;i<detections.size();i++)
		{
			CTrack* tr=new CTrack(detections[i],dt,Accel_noise_mag, _statfileid, _trackfileid, starttime);
			tracks.push_back(tr);
		}	
	}

	// -----------------------------------
	// Здесь треки уже есть в любом случае
	// -----------------------------------
	int N=tracks.size();		// треки
	int M=detections.size();	// детекты

	// Матрица расстояний от N-ного трека до M-ного детекта.
	vector< vector<double> > Cost(N,vector<double>(M));
	vector<int> assignment; // назначения

	// -----------------------------------
	// Треки уже есть, составим матрицу расстояний
	// -----------------------------------
	double dist;
	for(int i=0;i<tracks.size();i++)
	{	
		// Point2d prediction=tracks[i]->prediction;
		// cout << prediction << endl;
		for(int j=0;j<detections.size();j++)
		{
			Point2d diff=(tracks[i]->prediction-detections[j]);
			dist=sqrtf(diff.x*diff.x+diff.y*diff.y);
			Cost[i][j]=dist;
		}
	}
	// -----------------------------------
	// Решаем задачу о назначениях (треки и прогнозы фильтра)
	// -----------------------------------
	AssignmentProblemSolver APS;
	APS.Solve(Cost,assignment,AssignmentProblemSolver::optimal);

	// -----------------------------------
	// почистим assignment от пар с большим расстоянием
	// -----------------------------------
	// Не назначенные треки
	vector<int> not_assigned_tracks;

	for(int i=0;i<assignment.size();i++)
	{
		if(assignment[i]!=-1)
		{
			if(Cost[i][assignment[i]]>dist_thres)
			{
				assignment[i]=-1;
				// Отмечаем неназначенные треки, и увеличиваем счетчик пропущеных кадров,
				// когда количество пропущенных кадров превысит пороговое значение, трек стирается.
				not_assigned_tracks.push_back(i);
			}
		}
		else
		{			
			// Если треку не назначен детект, то увеличиваем счетчик пропущеных кадров.
			tracks[i]->skipped_frames++;
		}

	}


	// -----------------------------------
	// Если трек долго не получает детектов, удаляем
	// -----------------------------------
	for(int i=0;i<tracks.size();i++)
	{
		if(tracks[i]->skipped_frames>maximum_allowed_skipped_frames)
		{
			delete tracks[i];
			tracks.erase(tracks.begin()+i);
			assignment.erase(assignment.begin()+i);
			i--;
		}
	}
	// -----------------------------------
	// Выявляем неназначенные детекты
	// -----------------------------------
	vector<int> not_assigned_detections;
	vector<int>::iterator it;
	for(int i=0;i<detections.size();i++)
	{
		it=find(assignment.begin(), assignment.end(), i);
		if(it==assignment.end())
		{
			not_assigned_detections.push_back(i);
		}
	}

	// -----------------------------------
	// и начинаем для них новые треки
	// -----------------------------------
	if(not_assigned_detections.size()!=0)
	{
		for(int i=0;i<not_assigned_detections.size();i++)
		{
			CTrack* tr=new CTrack(detections[not_assigned_detections[i]],dt,Accel_noise_mag, _statfileid,  _trackfileid, starttime);
			tracks.push_back(tr);
		}	
	}

	// Апдейтим состояние фильтров

	for(int i=0;i<assignment.size();i++)
	{
		// Если трек апдейтился меньше одного раза, то состояние фильтра некорректно.
		tracks[i]->KF->GetPrediction();

		if(assignment[i]!=-1) // Если назначение есть то апдейтим по нему
		{
			tracks[i]->skipped_frames=0;
			tracks[i]->prediction=tracks[i]->KF->Update(detections[assignment[i]],1);
		}
		else				  // Если нет, то продолжаем прогнозировать
		{
			tracks[i]->prediction=tracks[i]->KF->Update(Point2f(0,0),0);	
		}

		/*
		if(tracks[i]->trace.size()>max_trace_length)
		{
			tracks[i]->trace.erase(tracks[i]->trace.begin(),tracks[i]->trace.end()-max_trace_length);
		}
		*/
		
		tracks[i]->trace.push_back(tracks[i]->prediction);

		// store real path or the prediction if missed position
		if(assignment[i]!=-1)
		{
			tracks[i]->realtrace.push_back(detections[assignment[i]]);
		}
		else
		{
			tracks[i]->realtrace.push_back(tracks[i]->prediction);
		}

		tracks[i]->KF->LastResult=tracks[i]->prediction;
	}

}
コード例 #5
0
void CTracker::Update(vector<Point2f>& detections)
{
	// If there is no tracks yet, then every point begins its own track.
	if (tracks.size() == 0)
	{
		// If no tracks yet
		for (int i = 0; i < detections.size(); ++i)
		{
			CTrack* tr = new CTrack(detections[i], dt, Accel_noise_mag);
			tracks.push_back(tr);
		}	
	}

	int N = tracks.size();
	int M = detections.size();
	vector<vector<float>> Cost(N, vector<float>(M));
	vector<int> assignment;

	float dist;
	for (int i = 0; i < tracks.size(); ++i)
	{	
		// Point2f prediction=tracks[i]->prediction;
		// console_log(to_string(prediction.x) + to_string(prediction.y));
		for (int j = 0; j < detections.size(); ++j)
		{
			Point2f diff = (tracks[i]->prediction - detections[j]);
			dist = sqrtf(diff.x * diff.x + diff.y * diff.y);
			Cost[i][j] = dist;
		}
	}

	// Solving assignment problem (tracks and predictions of Kalman filter)
	AssignmentProblemSolver APS;
	APS.Solve(Cost, assignment, AssignmentProblemSolver::optimal);

	// clean assignment from pairs with large distance
	// Not assigned tracks
	vector<int> not_assigned_tracks;

	for (int i = 0; i < assignment.size(); ++i)
	{
		if (assignment[i] != -1)
		{
			if (Cost[i][assignment[i]] > dist_thres)
			{
				assignment[i] = -1;
				// Mark unassigned tracks, and increment skipped frames counter,
				// when skipped frames counter will be larger than threshold, track will be deleted.
				not_assigned_tracks.push_back(i);
			}
		}
		else
		{			
			// If track have no assigned detect, then increment skipped frames counter.
			tracks[i]->skipped_frames++;
		}

	}

	// If track didn't get detects long time, remove it.
	for (int i = 0; i < tracks.size(); ++i)
	{
		if (tracks[i]->skipped_frames > maximum_allowed_skipped_frames)
		{
			delete tracks[i];
			tracks.erase(tracks.begin() + i);
			assignment.erase(assignment.begin() + i);
			--i;
		}
	}

	// Search for unassigned detects
	vector<int> not_assigned_detections;
	vector<int>::iterator it;
	for (int i = 0; i < detections.size(); ++i)
	{
		it = find(assignment.begin(), assignment.end(), i);
		if (it == assignment.end())
		{
			not_assigned_detections.push_back(i);
		}
	}

	// and start new tracks for them.
	if (not_assigned_detections.size() != 0)
	{
		for (int i = 0; i < not_assigned_detections.size(); ++i)
		{
			CTrack* tr = new CTrack(detections[not_assigned_detections[i]], dt,Accel_noise_mag);
			tracks.push_back(tr);
		}	
	}

	// Update Kalman Filters state
	for (int i = 0; i < assignment.size(); ++i)
	{
		// If track updated less than one time, than filter state is not correct.
		tracks[i]->KF->GetPrediction();

		if (assignment[i] != -1) // If we have assigned detect, then update using its coordinates,
		{
			tracks[i]->skipped_frames = 0;
			tracks[i]->prediction = tracks[i]->KF->Update(detections[assignment[i]], 1);
			tracks[i]->raw = detections[assignment[i]];
		}
		else				  // if not continue using predictions
		{
			tracks[i]->prediction = tracks[i]->KF->Update(Point2f(0, 0), 0);
			tracks[i]->raw = Point2f(0, 0);
		}
		
		if(tracks[i]->trace.size() > max_trace_length)
		{
			tracks[i]->trace.erase(tracks[i]->trace.begin(), tracks[i]->trace.end() - max_trace_length);
		}

		tracks[i]->trace.push_back(tracks[i]->prediction);
		tracks[i]->KF->LastResult = tracks[i]->prediction;
	}

}
コード例 #6
0
ファイル: Ctracker.cpp プロジェクト: Nsteel/Apollo_13
// ---------------------------------------------------------------------------
//param rects input/output bounding boxes
// ---------------------------------------------------------------------------
void CTracker::Update(
	const std::vector<Point_t>& detections,
  const std::vector<cv::Rect>& rects,
	DistType distType
	)
{
	assert(detections.size() == rects.size());
	SWRI_PROFILE("Tracking");

	// -----------------------------------
	// If there is no tracks yet, then every cv::Point begins its own track.
	// -----------------------------------
	if (tracks.size() == 0)
	{
		// If no tracks yet
		for (size_t i = 0; i < detections.size(); ++i)
		{
			tracks.push_back(std::make_shared<CTrack>(detections[i], rects[i], dt, Accel_noise_mag, NextTrackID++));
		}
	}

	size_t N = tracks.size();		// треки
	size_t M = detections.size();	// детекты

	assignments_t assignment; // назначения

	if (!tracks.empty())
	{
		// Матрица расстояний от N-ного трека до M-ного детекта.
		distMatrix_t Cost(N * M);

		// -----------------------------------
		// Треки уже есть, составим матрицу расстояний
		// -----------------------------------
		switch (distType)
		{
		case CentersDist:
			for (size_t i = 0; i < tracks.size(); i++)
			{
				for (size_t j = 0; j < detections.size(); j++)
				{
					Cost[i + j * N] = tracks[i]->CalcDist(detections[j]);
				}
			}
			break;

		case RectsDist:
			for (size_t i = 0; i < tracks.size(); i++)
			{
				for (size_t j = 0; j < detections.size(); j++)
				{
					Cost[i + j * N] = tracks[i]->CalcDist(rects[j]);
				}
			}
			break;
		}

		// -----------------------------------
		// Solving assignment problem (tracks and predictions of Kalman filter)
		// -----------------------------------
		AssignmentProblemSolver APS;
		APS.Solve(Cost, N, M, assignment, AssignmentProblemSolver::optimal);

		// -----------------------------------
		// clean assignment from pairs with large distance
		// -----------------------------------
		for (size_t i = 0; i < assignment.size(); i++)
		{
			if (assignment[i] != -1)
			{
				//std::cout << "Kalman cost: " << Cost[i + assignment[i] * N] << std::endl;
				if (Cost[i + assignment[i] * N] > dist_thres)
				{
					assignment[i] = -1;
					tracks[i]->skipped_frames++;
				}
			}
			else
			{
				// If track have no assigned detect, then increment skipped frames counter.
				tracks[i]->skipped_frames++;
			}
		}

		// -----------------------------------
		// If track didn't get detects long time, remove it.
		// -----------------------------------
		for (int i = 0; i < static_cast<int>(tracks.size()); i++)
		{
			if (tracks[i]->skipped_frames > maximum_allowed_skipped_frames)
			{
				tracks.erase(tracks.begin() + i);
				assignment.erase(assignment.begin() + i);
				i--;
			}
		}
	}

	// -----------------------------------
    // Search for unassigned detects and start new tracks for them.
	// -----------------------------------
    for (size_t i = 0; i < detections.size(); ++i)
	{
        if (find(assignment.begin(), assignment.end(), i) == assignment.end())
		{
			tracks.push_back(std::make_shared<CTrack>(detections[i], rects[i], dt, Accel_noise_mag, NextTrackID++));
		}
	}

	// Update Kalman Filters state

    for (size_t i = 0; i<assignment.size(); i++)
	{
		// If track updated less than one time, than filter state is not correct.

		if (assignment[i] != -1) // If we have assigned detect, then update using its coordinates,
		{
			tracks[i]->skipped_frames = 0;
      tracks[i]->seen_frames++;
			tracks[i]->Update(detections[assignment[i]], rects[assignment[i]], true, max_trace_length);
		}
		else				     // if not continue using predictions
		{
			tracks[i]->Update(Point_t(), cv::Rect(), false, max_trace_length);
		}
	}

}