You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
664 lines
24 KiB
664 lines
24 KiB
9 years ago
|
//------------------------------------------------------------------------------
|
||
|
//
|
||
|
// Project: Anonymizer
|
||
|
//
|
||
|
// Brno University of Technology
|
||
|
// Faculty of Information Technology
|
||
|
//
|
||
|
//------------------------------------------------------------------------------
|
||
|
//
|
||
|
// This project was financially supported by project VG20102015006 funds
|
||
|
// provided by Ministry of the Interior of the Czech republic.
|
||
|
//
|
||
|
//------------------------------------------------------------------------------
|
||
|
/*!
|
||
|
|
||
|
@file trackedobject.cpp
|
||
|
@brief Implementation of methods ...
|
||
|
@details Details
|
||
|
@authors Martin Borek (mborekcz@gmail.com)
|
||
|
@authors Filip Orsag (orsag@fit.vutbr.cz)
|
||
|
@date 2014-2015
|
||
|
@note This project was supported by MV CR project VG20102015006.
|
||
|
@copyright BUT OPEN SOURCE LICENCE (see License.txt)
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "trackedobject.h"
|
||
|
#include <QDebug>
|
||
|
#include "objectshape.h"
|
||
|
|
||
|
// Only currentSection can have initialized trackingAlgorithm so as memory can be correctly freed
|
||
|
|
||
|
TrackedObject::TrackedObject()
|
||
|
{ // CEREAL uses this constructor
|
||
|
endTimestampSet = false;
|
||
|
currentSection = nullptr;
|
||
|
nextSection = false;
|
||
|
allProcessed = false;
|
||
|
qDebug() << "new trackedObject";
|
||
|
}
|
||
|
|
||
|
TrackedObject::TrackedObject(const Characteristics &appearance, std::string objectName, int64_t initialTimestamp,
|
||
|
Selection initialPosition, unsigned long initialTimePosition, unsigned long initialFrameNumber,
|
||
|
bool endTimestampSet, int64_t endTimestamp, unsigned long endTimePosition,
|
||
|
unsigned long endFrameNumber) :
|
||
|
name(objectName),
|
||
|
appearance(appearance),
|
||
|
initialTimestamp(initialTimestamp),
|
||
|
//initialPosition(initialPosition),
|
||
|
endTimestampSet(endTimestampSet),
|
||
|
endTimestamp(endTimestamp),
|
||
|
endTimePosition(endTimePosition),
|
||
|
endFrameNumber(endFrameNumber)
|
||
|
{
|
||
|
add_section(initialTimestamp, initialPosition, initialTimePosition, initialFrameNumber);
|
||
|
|
||
|
currentSection = nullptr;
|
||
|
nextSection = false;
|
||
|
allProcessed = false;
|
||
|
//lastProcessedTimestamp = -1;
|
||
|
//lastProcessedTimestamp = VIDEOTRACKING_NOTHING_PROCESSED;
|
||
|
}
|
||
|
|
||
|
TrackedObject::~TrackedObject()
|
||
|
{
|
||
|
for (auto §ion: trajectorySections)
|
||
|
{
|
||
|
if (section.second.trackingAlgorithm)
|
||
|
{// if there is initialized trackingAlgorithm, free its memory
|
||
|
// this should occur only with currentSection
|
||
|
delete section.second.trackingAlgorithm;
|
||
|
section.second.trackingAlgorithm = nullptr;
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
if (trackingAlgorithm)
|
||
|
{ // was it already initialized (by initialize_section)?
|
||
|
delete trackingAlgorithm;
|
||
|
trackingAlgorithm = nullptr;
|
||
|
}
|
||
|
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
void TrackedObject::add_section(int64_t initialTimestamp, Selection const &initialPosition, unsigned long initialTimePosition, unsigned long initialFrameNumber)
|
||
|
{
|
||
|
|
||
|
TrajectorySection newSection(initialPosition, initialTimestamp, initialTimePosition, initialFrameNumber);
|
||
|
|
||
|
trajectorySections.insert({initialTimestamp, newSection});
|
||
|
|
||
|
}
|
||
|
|
||
|
// If oldTimeSet==true, oldTimestamp is valid and updating is done, otherwise adding is done
|
||
|
bool TrackedObject::set_trajectory_section(int64_t newTimestamp, Selection position, unsigned long timePosition, unsigned long frameNumber)
|
||
|
{
|
||
|
if (endTimestampSet && endTimestamp < newTimestamp)
|
||
|
return false; // Section cannot begin after the end of the tracking period
|
||
|
else if (trajectorySections.find(newTimestamp) != trajectorySections.end())
|
||
|
{ // Section with this timestamp already exists
|
||
|
// Change that section instead of creating a new one
|
||
|
qDebug() << "set_trajectory_section calls change_trajectory_section";
|
||
|
return change_trajectory_section(newTimestamp, newTimestamp, position, timePosition, frameNumber);
|
||
|
}
|
||
|
|
||
|
add_section(newTimestamp, position, timePosition, frameNumber);
|
||
|
|
||
|
allProcessed = false;
|
||
|
int64_t lastProcessedTimestamp;
|
||
|
bool lastProcessedTimestampSet = get_last_processed_timestamp(lastProcessedTimestamp);
|
||
|
|
||
|
if (newTimestamp < initialTimestamp)
|
||
|
{ // delete current and delete all trajectory => DONE
|
||
|
initialTimestamp = newTimestamp;
|
||
|
trajectory.clear();
|
||
|
}
|
||
|
else if ((newTimestamp < initialTimestamp) || // This section begins before the BEGINNING section. Therefore, set this section as beginning.
|
||
|
(lastProcessedTimestampSet && newTimestamp <= lastProcessedTimestamp))
|
||
|
{
|
||
|
|
||
|
if (currentSection)
|
||
|
{ // Unset it
|
||
|
if (currentSection->trackingAlgorithm)
|
||
|
{
|
||
|
delete currentSection->trackingAlgorithm;
|
||
|
currentSection->trackingAlgorithm = nullptr;
|
||
|
}
|
||
|
currentSection = nullptr;
|
||
|
nextSection = false;
|
||
|
}
|
||
|
|
||
|
if (newTimestamp < initialTimestamp)
|
||
|
{
|
||
|
initialTimestamp = newTimestamp;
|
||
|
trajectory.clear();
|
||
|
}
|
||
|
else // (lastProcessedTimestampSet && newTimestamp <= lastProcessedTimestamp)
|
||
|
{
|
||
|
// delete all >=newTimestamp
|
||
|
trajectory.erase(trajectory.find(newTimestamp), trajectory.end());
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{ // newTimestamp > LASTPROCESSEDTIMESTAMP
|
||
|
// No need to unset currentSection or delete anything from trajectory.
|
||
|
// The currently processed frame is before this section.
|
||
|
// Only nextSectionTimestamp may need to be updated if the newly added section is the next one.
|
||
|
|
||
|
// The newly added is already in trajectorySections, so let it find the appropriate one itself
|
||
|
auto nextSectionIterator = trajectorySections.upper_bound(currentSection->initialTimestamp);
|
||
|
if (nextSectionIterator != trajectorySections.end())
|
||
|
{
|
||
|
nextSection = true;
|
||
|
nextSectionTimestamp = nextSectionIterator->first;
|
||
|
}
|
||
|
else
|
||
|
nextSection = false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool TrackedObject::change_trajectory_section(int64_t oldTimestamp, int64_t newTimestamp, Selection position, unsigned long timePosition, unsigned long frameNumber)
|
||
|
{
|
||
|
// The oldTimestamp needs to exist
|
||
|
assert(trajectorySections.find(oldTimestamp) != trajectorySections.end());
|
||
|
|
||
|
if (endTimestampSet && endTimestamp < newTimestamp)
|
||
|
return false; // Section cannot begin after the end of the tracking period
|
||
|
|
||
|
// currentSection will be unset, therefore trackingAlgorithm deletion is needed
|
||
|
if (currentSection && currentSection->trackingAlgorithm)
|
||
|
{ // if currentSection is set and has initialized trackingAlgorithm, delete the trackingAlgorithm
|
||
|
// as it is not needed anymore; if needed, it would get initialized again
|
||
|
|
||
|
trajectory.erase(trajectory.find(currentSection->initialTimestamp), trajectory.end()); // Clear all the trajectory from Current section initial timestamp till the end
|
||
|
delete currentSection->trackingAlgorithm;
|
||
|
currentSection->trackingAlgorithm = nullptr;
|
||
|
}
|
||
|
|
||
|
currentSection = nullptr; // let track_next() to find correct currentSection and nextSection
|
||
|
nextSection = false;
|
||
|
allProcessed = false;
|
||
|
|
||
|
auto oldSection = trajectorySections.find(oldTimestamp);
|
||
|
|
||
|
if (oldSection == trajectorySections.begin())
|
||
|
{ // The Beginning section is being changed
|
||
|
|
||
|
assert(initialTimestamp == oldTimestamp);
|
||
|
|
||
|
trajectory.clear(); // All trajectory will be counted from the beginning
|
||
|
|
||
|
// Delete all trajectory changes (sections) that occur before this section as this is the beginning.
|
||
|
// This situation happens when user moves the Beginning forward while some Section was
|
||
|
// defined on some position between the old Beginning and the new one.
|
||
|
trajectorySections.erase(trajectorySections.begin(), trajectorySections.find(newTimestamp));
|
||
|
|
||
|
initialTimestamp = newTimestamp;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{ // Trajectory change section is being change, not Beginning
|
||
|
trajectory.erase(trajectory.find(newTimestamp), trajectory.end()); // Clear all the trajectory from the timestamp at which the section begins till the end
|
||
|
|
||
|
if (newTimestamp < initialTimestamp) // This section begins before the BEGINNING section. Therefore, set this section as beginning.
|
||
|
initialTimestamp = newTimestamp;
|
||
|
|
||
|
if (oldTimestamp < newTimestamp)
|
||
|
{ // Section is updated to begin later
|
||
|
|
||
|
// V tomhle pripade je treba, aby bylo z trajectory odstraneno vsechno pocinaje
|
||
|
// zacatku PREDCHOZI sekce od oldTimestamp. To z toho duvodu, ze od oldTimestamp
|
||
|
// je treba prepocitat novou trajektorii. Vzhledem k tomu, ze zadna sekce na snimku
|
||
|
// oldTimestamp nezacina (ta soucasna se meni ne currentTimestamp), tak je treba pozici
|
||
|
// objektu vypocitat pomoci trackingAlgorithm predchozi sekce. Ten vsak musi byt
|
||
|
// inicializovan a proto musi probehnout od zacatku. Z toho duvodu se maze vse od
|
||
|
// zacatku teto predchozi sekce.
|
||
|
|
||
|
// If oldSection was trajectorySections.begin(), decreasing the iterator would cause
|
||
|
// undefined behaviour. However, this branche secures that this cannot happen.
|
||
|
trajectory.erase(trajectory.find((--oldSection)->first), trajectory.end());
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
trajectorySections.erase(oldTimestamp);
|
||
|
|
||
|
if (trajectorySections.find(newTimestamp) != trajectorySections.end())
|
||
|
{ // Section with this timestamp already exists
|
||
|
// Call change_trajectory_section to replace the old section by this new one
|
||
|
qDebug() << "change_trajectory_section(): Section with given timestamp exists. Thus, the old one was deleted.";
|
||
|
return change_trajectory_section(newTimestamp, newTimestamp, position, timePosition, frameNumber);
|
||
|
}
|
||
|
|
||
|
add_section(newTimestamp, position, timePosition, frameNumber);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/* If false return: Beginning section cannot be deleted */
|
||
|
bool TrackedObject::delete_trajectory_section(int64_t timestamp)
|
||
|
{
|
||
|
if (timestamp == initialTimestamp) // Beginning section cannot be deleted
|
||
|
{
|
||
|
qDebug() << "Beginning section cannot be deleted";
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (currentSection && (currentSection->initialTimestamp >= timestamp))
|
||
|
{ // This trajectorySection will be erased below(==timestamp) or
|
||
|
// takes place after the section being deleted(>timestamp), therefore needs to be unset
|
||
|
if (currentSection->trackingAlgorithm)
|
||
|
{
|
||
|
delete currentSection->trackingAlgorithm;
|
||
|
currentSection->trackingAlgorithm = nullptr;
|
||
|
}
|
||
|
|
||
|
currentSection = nullptr;
|
||
|
nextSection = false;
|
||
|
}
|
||
|
else if (nextSection && nextSectionTimestamp == timestamp)
|
||
|
{ // The deleted section should have been the next section.
|
||
|
// Set the following section or false if no later section exists.
|
||
|
|
||
|
auto nextSectionIterator = trajectorySections.upper_bound(timestamp);
|
||
|
if (nextSectionIterator != trajectorySections.end())
|
||
|
{
|
||
|
nextSection = true;
|
||
|
nextSectionTimestamp = nextSectionIterator->first;
|
||
|
}
|
||
|
else
|
||
|
nextSection = false;
|
||
|
}
|
||
|
allProcessed = false;
|
||
|
|
||
|
// previousSection always exists as Beginning section cannot be deleted.
|
||
|
auto previousSection = --(trajectorySections.find(timestamp));
|
||
|
trajectorySections.erase(timestamp);
|
||
|
|
||
|
// Remove all entries that exist for frames at timestamps higher than the beginning
|
||
|
// of the PREVIOUS section. It is needed so the trackingAlgorithm from the previous section
|
||
|
// goes from its beginning to have the correct data. Thereby, the deleted trajectory will be recounted.
|
||
|
trajectory.erase(trajectory.find(previousSection->first), trajectory.end());
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/* If set==false, the end frame will be unset and the object will be tracked till the end of the video
|
||
|
* newTimestamp and timePosition are valid only if set==true
|
||
|
* Returns false when given timestamp is lower than the timestamp of Beginning
|
||
|
*/
|
||
|
bool TrackedObject::change_end_frame(bool set, int64_t timestamp, unsigned long timePosition, unsigned long frameNumber)
|
||
|
{
|
||
|
if (!set)
|
||
|
{ // Tracking till the end of the video
|
||
|
|
||
|
if (allProcessed)
|
||
|
{ // All frames were processed, but now the length is extended.
|
||
|
// Delete trajectory from the last section's initial timestamp till the end so the
|
||
|
// tracking algorithm has the right values.
|
||
|
|
||
|
trajectory.erase(trajectory.find(trajectorySections.rbegin()->first), trajectory.end());
|
||
|
|
||
|
}
|
||
|
|
||
|
endTimestampSet = false;
|
||
|
allProcessed = false;
|
||
|
}
|
||
|
else
|
||
|
{ // End timestamp is set
|
||
|
if (timestamp < initialTimestamp)// given timestamp is lower than the timestamp of Beginning -> Not valid
|
||
|
return false;
|
||
|
|
||
|
if (allProcessed && timestamp > endTimestamp)
|
||
|
{ // All frames were processed, but now the length is extended.
|
||
|
// Delete trajectory from the last section's initial timestamp till the end so the
|
||
|
// tracking algorithm has the right values.
|
||
|
|
||
|
trajectory.erase(trajectory.find(trajectorySections.rbegin()->first), trajectory.end());
|
||
|
|
||
|
}
|
||
|
|
||
|
allProcessed = false;
|
||
|
|
||
|
endTimestampSet = true;
|
||
|
endTimestamp = timestamp;
|
||
|
|
||
|
endTimePosition = timePosition;
|
||
|
endFrameNumber = frameNumber;
|
||
|
|
||
|
// Remove all entries that exist for frames at timestamps higher than the end timestamp
|
||
|
trajectory.erase(trajectory.upper_bound(timestamp), trajectory.end());
|
||
|
|
||
|
if (currentSection && (currentSection->initialTimestamp > timestamp) && currentSection->trackingAlgorithm)
|
||
|
{ // This trajectorySection will be erased below, therefore needs to be unset
|
||
|
delete currentSection->trackingAlgorithm;
|
||
|
currentSection->trackingAlgorithm = nullptr;
|
||
|
currentSection = nullptr;
|
||
|
nextSection = false;
|
||
|
}
|
||
|
|
||
|
if (nextSection && (nextSectionTimestamp > endTimestamp)) // If there is a next section that is later than the end timestamp
|
||
|
nextSection = false;
|
||
|
|
||
|
// Remove all sections (trajectory changes) that have timestamp higher than the end timestamp
|
||
|
trajectorySections.erase(trajectorySections.upper_bound(timestamp), trajectorySections.end());
|
||
|
|
||
|
|
||
|
if (trajectory.find(timestamp) != trajectory.end())
|
||
|
{ // "trajectory" contains positions throughout all the object live; thus, everything is processed
|
||
|
set_all_processed(true);
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void TrackedObject::change_appearance(Characteristics const &newAppearance)
|
||
|
{
|
||
|
appearance = newAppearance;
|
||
|
}
|
||
|
|
||
|
Characteristics TrackedObject::get_appearance() const
|
||
|
{
|
||
|
return appearance;
|
||
|
}
|
||
|
|
||
|
//Selection TrackedObject::track_next(cv::Mat const &frame, int64_t timestamp)
|
||
|
|
||
|
// All changes to trajectorySections make currentSection==nullptr and nextSection=false, so
|
||
|
// track_next() needs to find appropriate values
|
||
|
Selection TrackedObject::track_next(VideoFrame const *frame)
|
||
|
{
|
||
|
if (!currentSection || (nextSection && frame->get_timestamp() >= nextSectionTimestamp))
|
||
|
{ // Enters new section
|
||
|
// Close old section and initialize a new one.
|
||
|
|
||
|
int64_t currentSectionTimestamp;
|
||
|
if (!currentSection)
|
||
|
{ // First section or change to trajectorySections was made
|
||
|
if (trajectory.begin() == trajectory.end())
|
||
|
{ // Nothing is processed, set Beginning section
|
||
|
auto trajectoryIterator = trajectorySections.begin();
|
||
|
currentSection = &(trajectoryIterator->second);
|
||
|
|
||
|
currentSectionTimestamp = trajectoryIterator->first; // Is later used to count the nextSectionTimestamp
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int64_t lastProcessed = trajectory.rbegin()->first;
|
||
|
|
||
|
// Find section that begins after the last processed frame.
|
||
|
// That should be the next frame. If not - entries would be missing
|
||
|
// and that would cause an error.
|
||
|
auto trajectoryIterator = trajectorySections.upper_bound(lastProcessed);
|
||
|
currentSection = &(trajectoryIterator->second);
|
||
|
currentSectionTimestamp = trajectoryIterator->first;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ // currentSection was set
|
||
|
// Entering next section
|
||
|
if (currentSection->trackingAlgorithm)
|
||
|
{ // delete the trackingAlgorithm as it is not needed anymore;
|
||
|
// if needed, it would get initialized again
|
||
|
delete currentSection->trackingAlgorithm;
|
||
|
currentSection->trackingAlgorithm = nullptr;
|
||
|
}
|
||
|
currentSection = &(trajectorySections[nextSectionTimestamp]);
|
||
|
currentSectionTimestamp = nextSectionTimestamp;
|
||
|
}
|
||
|
|
||
|
auto nextSectionIterator = trajectorySections.upper_bound(currentSectionTimestamp);
|
||
|
if (nextSectionIterator != trajectorySections.end())
|
||
|
{
|
||
|
nextSection = true;
|
||
|
nextSectionTimestamp = nextSectionIterator->first;
|
||
|
}
|
||
|
else
|
||
|
nextSection = false;
|
||
|
|
||
|
// Now initialize the new section's tracking algorithm
|
||
|
Selection centerizedPosition;
|
||
|
|
||
|
|
||
|
currentSection->trackingAlgorithm = new TrackingAlgorithm(*(frame->get_mat_frame()),
|
||
|
currentSection->initialPosition, centerizedPosition);
|
||
|
|
||
|
trajectory[frame->get_timestamp()] = TrajectoryEntry(centerizedPosition, frame->get_time_position(), frame->get_frame_number());
|
||
|
|
||
|
return centerizedPosition;
|
||
|
}
|
||
|
|
||
|
Selection result = currentSection->trackingAlgorithm->track_next_frame(*(frame->get_mat_frame()));
|
||
|
|
||
|
trajectory[frame->get_timestamp()] = TrajectoryEntry(result, frame->get_time_position(), frame->get_frame_number());
|
||
|
|
||
|
|
||
|
int64_t lastProcessedTimestamp;
|
||
|
if (endTimestampSet && get_last_processed_timestamp(lastProcessedTimestamp) && lastProcessedTimestamp == endTimestamp)
|
||
|
{
|
||
|
set_all_processed(true);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool TrackedObject::get_position(int64_t timestamp, Selection &trackedPosition) const
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
trackedPosition = trajectory.at(timestamp).position; // Throws an exception, when trajectory with given timestamp does not exist
|
||
|
} catch (std::out_of_range) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool TrackedObject::draw_mark(cv::Mat &frame, cv::Mat const &originalFrame, int64_t timestamp) const
|
||
|
{
|
||
|
//qDebug()<< "Draw mark";
|
||
|
|
||
|
Selection position;
|
||
|
try
|
||
|
{
|
||
|
position = trajectory.at(timestamp).position; // Throws an exception, when trajectory with given timestamp does not exist
|
||
|
} catch (std::out_of_range) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (appearance.defocus)
|
||
|
{
|
||
|
assert(appearance.defocusSize > 0);
|
||
|
|
||
|
//cv::Mat3b roiMat = imgMat(cv::Rect(hSt,vSt,hEn,vEn));
|
||
|
unsigned long x = position.x - position.width/2;
|
||
|
unsigned long y = position.y - position.height/2;
|
||
|
unsigned long xMax = position.width + x;
|
||
|
unsigned long yMax = position.height + y;
|
||
|
|
||
|
// This secures valid values
|
||
|
unsigned long cols = frame.cols;
|
||
|
unsigned long rows = frame.rows;
|
||
|
if (xMax > cols)
|
||
|
xMax = cols;
|
||
|
if (yMax > rows)
|
||
|
yMax = rows;
|
||
|
|
||
|
unsigned long i, j;
|
||
|
unsigned long currentSquareWidth, currentSquareHeight;
|
||
|
cv::Rect roiRect;
|
||
|
cv::Mat roi;
|
||
|
cv::Scalar mean;
|
||
|
for (i=x; i < xMax; i+=appearance.defocusSize)
|
||
|
{
|
||
|
for (j=y; j < yMax; j+=appearance.defocusSize)
|
||
|
{
|
||
|
currentSquareWidth = appearance.defocusSize;
|
||
|
currentSquareHeight = appearance.defocusSize;
|
||
|
|
||
|
if (i+currentSquareWidth > xMax) // Do not cross the object's border
|
||
|
currentSquareWidth = xMax - i;
|
||
|
|
||
|
if (j+currentSquareHeight > yMax) // Do not cross the object's border
|
||
|
currentSquareHeight = yMax - j;
|
||
|
|
||
|
// Width and height must not be 0 for roi to be created
|
||
|
if (currentSquareWidth > 0 && currentSquareHeight > 0)
|
||
|
{
|
||
|
roiRect = cv::Rect(i, j, currentSquareWidth, currentSquareHeight);
|
||
|
roi = originalFrame(roiRect); // originalFrame is used so as it does not involve other tracked objects
|
||
|
mean = cv::mean(roi);
|
||
|
cv::rectangle(frame, roiRect, mean, CV_FILLED);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else // Fill and/or border; not defocus
|
||
|
{
|
||
|
cv::RotatedRect rectangle = cv::RotatedRect(cv::Point2f(position.x, position.y), cv::Size2f(position.width, position.height), position.angle);
|
||
|
|
||
|
// Important note: OpenCV uses BGR, not RGB
|
||
|
cv::Scalar borderColor(appearance.borderColor.b, appearance.borderColor.g, appearance.borderColor.r);
|
||
|
cv::Scalar color(appearance.color.b, appearance.color.g, appearance.color.r);
|
||
|
|
||
|
if (appearance.shape == ObjectShape::RECTANGLE)
|
||
|
{
|
||
|
cv::Point2f vertices2f[4];
|
||
|
cv::Point vertices[4];
|
||
|
rectangle.points(vertices2f);
|
||
|
for (int i = 0; i < 4; i++)
|
||
|
vertices[i] = vertices2f[i];
|
||
|
|
||
|
if (appearance.drawInside)
|
||
|
cv::fillConvexPoly(frame, vertices, 4, color);
|
||
|
|
||
|
|
||
|
if (appearance.drawBorder && appearance.borderThickness > 0)
|
||
|
{
|
||
|
for (int i = 0; i < 4; i++)
|
||
|
cv::line(frame, vertices2f[i], vertices2f[(i+1)%4], borderColor, appearance.borderThickness, CV_AA);
|
||
|
}
|
||
|
}
|
||
|
else if (appearance.shape == ObjectShape::ELLIPSE)
|
||
|
{
|
||
|
if (appearance.drawInside)
|
||
|
cv::ellipse(frame,rectangle, color, -1);
|
||
|
|
||
|
if (appearance.drawBorder && appearance.borderThickness > 0)
|
||
|
cv::ellipse(frame,rectangle, borderColor, appearance.borderThickness);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
std::map<int64_t, TrajectorySection> const &TrackedObject::get_trajectory_sections() const
|
||
|
{
|
||
|
return trajectorySections;
|
||
|
}
|
||
|
|
||
|
std::map<int64_t, TrajectoryEntry> const &TrackedObject::get_trajectory() const
|
||
|
{
|
||
|
return trajectory;
|
||
|
}
|
||
|
|
||
|
int64_t TrackedObject::get_initial_timestamp() const
|
||
|
{
|
||
|
return initialTimestamp;
|
||
|
}
|
||
|
|
||
|
int64_t TrackedObject::get_end_timestamp() const
|
||
|
{
|
||
|
return endTimestamp;
|
||
|
}
|
||
|
|
||
|
unsigned long TrackedObject::get_end_time_position() const
|
||
|
{
|
||
|
return endTimePosition;
|
||
|
}
|
||
|
|
||
|
unsigned long TrackedObject::get_end_frame_number() const
|
||
|
{
|
||
|
return endFrameNumber;
|
||
|
}
|
||
|
|
||
|
//int64_t TrackedObject::get_last_processed_timestamp() const
|
||
|
|
||
|
/* If false is returned, timestamp is not valid */
|
||
|
bool TrackedObject::get_last_processed_timestamp(int64_t ×tamp) const
|
||
|
{
|
||
|
if (trajectory.begin() == trajectory.end())
|
||
|
{
|
||
|
qDebug() << "Trajectory is empty";
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
timestamp = trajectory.rbegin()->first;
|
||
|
return true;
|
||
|
//return lastProcessedTimestamp;
|
||
|
}
|
||
|
|
||
|
void TrackedObject::set_all_processed(bool processed)
|
||
|
{
|
||
|
allProcessed = processed;
|
||
|
//qDebug() << "all processed set";
|
||
|
|
||
|
if (processed == true)
|
||
|
{
|
||
|
if (currentSection && currentSection->trackingAlgorithm)
|
||
|
{ // if currentSection is set and has initialized trackingAlgorithm, delete the trackingAlgorithm
|
||
|
// as it is not needed anymore; if needed, it would get initialized again
|
||
|
delete currentSection->trackingAlgorithm;
|
||
|
currentSection->trackingAlgorithm = nullptr;
|
||
|
}
|
||
|
currentSection = nullptr;
|
||
|
nextSection = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool TrackedObject::is_all_processed() const
|
||
|
{
|
||
|
return allProcessed;
|
||
|
}
|
||
|
|
||
|
bool TrackedObject::is_end_timestamp_set() const
|
||
|
{
|
||
|
return endTimestampSet;
|
||
|
}
|
||
|
|
||
|
std::string TrackedObject::get_name() const
|
||
|
{
|
||
|
return name;
|
||
|
}
|
||
|
|
||
|
bool TrackedObject::set_name(std::string newName)
|
||
|
{
|
||
|
name = newName;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void TrackedObject::erase_trajectory_to_comply()
|
||
|
{
|
||
|
if (allProcessed) // Everything is already processed, sections are not needed anymore
|
||
|
return;
|
||
|
|
||
|
int64_t lastProcessedTimestamp;
|
||
|
if (!get_last_processed_timestamp(lastProcessedTimestamp))
|
||
|
return; // Nothing processed -> nothing to be erased
|
||
|
|
||
|
auto section = --(trajectorySections.upper_bound(lastProcessedTimestamp));
|
||
|
|
||
|
trajectory.erase(trajectory.find(section->second.initialTimestamp), trajectory.end()); // Clear all the trajectory from Current section initial timestamp till the end
|
||
|
}
|