Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • ped-dyn-emp/petrack
1 result
Show changes
Commits on Source (26)
......@@ -376,6 +376,7 @@ target_sources(petrack_core PRIVATE
include/pMessageBox.h
include/moCapSelectionWidget.h
include/personStorage.h
include/autosave.h
)
target_sources(petrack_core PRIVATE
......@@ -435,6 +436,7 @@ target_sources(petrack_core PRIVATE
src/pMessageBox.cpp
src/moCapSelectionWidget.cpp
src/personStorage.cpp
src/autosave.cpp
ui/about.ui
ui/codeMarker.ui
ui/colorMarker.ui
......
/*
* PeTrack - Software for tracking pedestrians movement in videos
* Copyright (C) 2010-2022 Forschungszentrum Jülich GmbH,
* Maik Boltes, Juliane Adrian, Ricardo Martin Brualla, Arne Graf, Paul Häger, Daniel Hillebrand,
* Deniz Kilic, Paul Lieberenz, Daniel Salden, Tobias Schrödter, Ann Katrin Seemann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef AUTOSAVE_H
#define AUTOSAVE_H
#include <QObject>
#include <QStringList>
#include <memory>
class Petrack;
class QTimer;
class QFileInfo;
struct AutosaveFilenames
{
QString running;
QString final;
};
class Autosave : public QObject
{
Q_OBJECT
public:
explicit Autosave(Petrack &petrack);
Autosave() = delete;
Autosave(const Autosave &other) = delete;
Autosave(const Autosave &&other) = delete;
Autosave &operator=(const Autosave &other) = delete;
Autosave &operator=(Autosave &&other) = delete;
~Autosave() override = default;
void trackPersonModified();
void resetTrackPersonCounter();
static bool autosaveExists(const QString &filename);
void deleteAutosave();
void loadAutosave();
bool isAutosave(const QString &file);
private:
static QString buildAutosaveName(const QString &projectFileName, const QString &ending);
static AutosaveFilenames autosaveNamesTrc(const QString &projectFileName);
static AutosaveFilenames autosaveNamesPet(const QString &projectFileName);
void saveTrc();
QStringList getAutosave();
static QStringList getAutosave(const QFileInfo &projectPath);
private slots:
void savePet();
private:
static constexpr int petSaveInterval = 120 * 1000; // in ms -> 120s
static constexpr int changesTillAutosave = 10;
void startTimer();
void stopTimer();
Petrack &mPetrack;
QTimer *mTimer;
int mChangeCounter = 0;
};
#endif // AUTOSAVE_H
......@@ -26,6 +26,7 @@
#include <vector>
class Petrack;
class Autosave;
struct PersonFrame
{
......@@ -43,7 +44,7 @@ public:
Whole
};
explicit PersonStorage(Petrack &mainWindow) : mMainWindow(mainWindow) {}
explicit PersonStorage(Petrack &mainWindow, Autosave &autosave) : mMainWindow(mainWindow), mAutosave(autosave) {}
void splitPerson(size_t pers, int frame);
bool splitPersonAt(const Vec2F &p, int frame, const QSet<int> &onlyVisible);
......@@ -120,7 +121,7 @@ public:
// rueckgabewert false wenn keine hoeheninformationen in tracker datensatz vorliegt
bool printHeightDistribution();
void setMarkerHeights(const std::unordered_map<int, float> &heights);
void setMarkerID(int person, int markerIDs);
void setMarkerID(int person, int markerIDs, bool manual = false);
void setMarkerIDs(const std::unordered_map<int, int> &markerIDs);
void purge(int frame);
......@@ -129,6 +130,7 @@ public:
private:
std::vector<TrackPerson> mPersons;
Petrack &mMainWindow;
Autosave &mAutosave;
};
#endif // PERSONSTORAGE_H
......@@ -33,6 +33,7 @@
#include "stereoContext.h"
#endif
#include "autoCalib.h"
#include "autosave.h"
#include "backgroundFilter.h"
#include "borderFilter.h"
#include "brightContrastFilter.h"
......@@ -201,14 +202,7 @@ public:
inline pet::StereoContext *getStereoContext() { return mStereoContext; }
inline QString getProFileName() { return mProFileName; }
private:
inline void setProFileName(const QString &fileName)
{
// NOTE: Use only the global variant in future?
// global one in helper.h because it is needed to use getFileList and shouldn't depend on Petrack
proFileName = fileName;
mProFileName = fileName;
}
void setProFileName(const QString &fileName);
public:
inline QString getTrackFileName() { return mTrcFileName; }
......@@ -464,14 +458,15 @@ private:
reco::Recognizer mReco;
PersonStorage mPersonStorage{*this};
QDomDocument mDefaultSettings;
Autosave mAutosave{*this};
PersonStorage mPersonStorage{*this, mAutosave};
Tracker *mTracker;
TrackerReal *mTrackerReal;
double mHeadSize;
double mCmPerPixel;
QDomDocument mDefaultSettings;
double mShowFPS;
bool mAutoBackTrack;
......@@ -481,7 +476,6 @@ private:
MoCapStorage mStorage;
MoCapController mMoCapController{mStorage, mExtrCalibration};
QString mPetrackVersion{"Unknown"}; ///< Version of PeTrack used to compile
QString mGitCommitID{"Unknown"}; ///< Commit hash used to compile
QString mGitCommitDate{"Unknown"}; ///< Commit date used to compile
......
/*
* PeTrack - Software for tracking pedestrians movement in videos
* Copyright (C) 2010-2022 Forschungszentrum Jülich GmbH,
* Maik Boltes, Juliane Adrian, Ricardo Martin Brualla, Arne Graf, Paul Häger, Daniel Hillebrand,
* Deniz Kilic, Paul Lieberenz, Daniel Salden, Tobias Schrödter, Ann Katrin Seemann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "autosave.h"
#include "petrack.h"
#include <QTimer>
Autosave::Autosave(Petrack &petrack) : mPetrack(petrack)
{
mTimer = new QTimer{this};
connect(mTimer, &QTimer::timeout, this, &Autosave::savePet);
startTimer();
}
// Autosave::~Autosave() = default;
//{
// NOTE: Currently this would also delete on Keyboard Interrupt (Ctrl + C)
// Replaced by Method call in closeEvent in Petrack to circumvent this
// if Project-Object from Issue 88 gets implemented,
// Autosave should be a Member of the project, not Petrack
// then the destructor could maybe be used to delete the autosave
// deleteAutosave();
//}
/**
* @brief Occasioanlly triggers autosaving
*
* This method gets called everytime the user modifies a trajectory. After a certain number of modifications, an
* autosave for the .trc file is written to disk
*/
void Autosave::trackPersonModified()
{
mChangeCounter++;
if(mChangeCounter >= changesTillAutosave)
{
mChangeCounter = 0;
saveTrc();
}
}
void Autosave::resetTrackPersonCounter()
{
mChangeCounter = 0;
}
/**
* @brief Checks if autosave for project with given filename exists
* @param filename path to the project file
* @return true if autosave file exists, else false
*/
bool Autosave::autosaveExists(const QString &filename)
{
return !getAutosave(QFileInfo(filename)).empty();
}
/**
* @brief Delete all autosave files for currently loaded project (.pet and .trc)
*/
void Autosave::deleteAutosave()
{
const auto autosaves = getAutosave();
if(!autosaves.empty())
{
for(const auto &save : autosaves)
{
QFile saveFile{save};
saveFile.remove();
}
}
}
/**
* @brief Loads autosave files for currently loaded project
*/
void Autosave::loadAutosave()
{
const auto autosaveFiles = getAutosave();
if(autosaveFiles.empty())
{
return;
}
const auto petIndex = autosaveFiles.indexOf(QRegularExpression(R"(.*\.pet)"));
if(petIndex != -1)
{
const QString petAutosaveName = autosaveFiles[petIndex];
mPetrack.openProject(petAutosaveName);
}
else
{
mPetrack.openProject(mPetrack.getProFileName());
}
const auto trcIndex = autosaveFiles.indexOf(QRegularExpression(R"(.*\.trc)"));
if(trcIndex != -1)
{
const QString trcAutosaveName = autosaveFiles[trcIndex];
const auto trcFile = mPetrack.getTrackFileName();
mPetrack.deleteTrackPointAll(PersonStorage::Direction::Whole);
mPetrack.importTracker(trcAutosaveName);
mPetrack.setTrackFileName(trcFile);
}
}
/**
* @brief Returns whether a given filename would be autosave
*
* NOTE: File does not need to exist to be classified as autosave
*
* @param file file to test
* @return true when name of an autosave, else false;
*/
bool Autosave::isAutosave(const QString &file)
{
const auto &projectName = mPetrack.getProFileName();
const auto [petRunningAutosave, petAutosaveName] = [&projectName]
{
auto names = autosaveNamesPet(projectName);
names.running = QFileInfo(names.running).absoluteFilePath();
names.final = QFileInfo(names.final).absoluteFilePath();
return names;
}();
const auto [trcRunningAutosave, trcAutosaveName] = [&projectName]
{
auto names = autosaveNamesTrc(projectName);
names.running = QFileInfo(names.running).absoluteFilePath();
names.final = QFileInfo(names.final).absoluteFilePath();
return names;
}();
QFileInfo fileInfo{file};
const QString &filePath = fileInfo.absoluteFilePath();
return filePath == petAutosaveName || filePath == trcAutosaveName || filePath == petRunningAutosave ||
filePath == trcRunningAutosave;
}
/**
* @brief Starts timer for time-dependent autosave (pet-file)
*/
void Autosave::startTimer()
{
if(!mTimer->isActive())
{
mTimer->start(petSaveInterval);
}
}
/**
* @brief Stops timer for time-dependent autosave (pet-file)
*/
void Autosave::stopTimer()
{
if(mTimer->isActive())
{
mTimer->stop();
}
}
QString Autosave::buildAutosaveName(const QString &projectFileName, const QString &ending)
{
const QFileInfo projectFile{projectFileName};
return projectFile.dir().filePath("." + projectFile.baseName() + "_autosave" + ending);
}
AutosaveFilenames Autosave::autosaveNamesTrc(const QString &projectFileName)
{
return {buildAutosaveName(projectFileName, "_running.trc"), buildAutosaveName(projectFileName, ".trc")};
}
AutosaveFilenames Autosave::autosaveNamesPet(const QString &projectFileName)
{
return {buildAutosaveName(projectFileName, "_running.pet"), buildAutosaveName(projectFileName, ".pet")};
}
/**
* @brief Saves the .pet-file
*
* This method is called by the timeout signal of mTimer.
* It saves the pet-file to a hidden file with a name derived from
* the name of the currently loaded project
*/
void Autosave::savePet()
{
const auto projectName = mPetrack.getProFileName();
// only save if there is a project name; Means there needs to be an .pet file already for autosave to work. With our
// workflow usually the case
if(projectName.isEmpty() || QFileInfo(projectName).isDir())
{
return;
}
const auto &[autosaveName, finalAutosaveName] = autosaveNamesPet(projectName);
mPetrack.saveProject(autosaveName);
// first save to temp file, so crash during saving doesn't corrupt old autosave
QFile tempAutosave{autosaveName};
QFile autosave{finalAutosaveName};
if(tempAutosave.exists())
{
if(autosave.exists())
{
autosave.remove();
}
if(tempAutosave.copy(finalAutosaveName))
{
// we don't currently use it for loading, so we could remove it even if the copying fails...
tempAutosave.remove();
}
}
}
/**
* @brief Saves the .trc-file
*
* This method is called by trackPersonModified after a set number of modifications.
* It saves the trc-file to a hidden file with a name derived from
* the name of the currently loaded project
*/
void Autosave::saveTrc()
{
const auto projectName = mPetrack.getProFileName();
const auto &[autosaveName, finalAutosaveName] = autosaveNamesTrc(projectName);
const auto trackFileName = mPetrack.getTrackFileName();
const auto lastTrackerExport = mPetrack.getLastTrackerExport();
mPetrack.exportTracker(autosaveName);
mPetrack.setTrackFileName(trackFileName);
mPetrack.setLastTrackerExport(lastTrackerExport);
// first save to temp file, so crash during saving doesn't corrupt old autosave
QFile tempAutosave{autosaveName};
QFile autosave{finalAutosaveName};
if(tempAutosave.exists())
{
if(autosave.exists())
{
autosave.remove();
}
if(tempAutosave.copy(finalAutosaveName))
{
// we don't currently use it for loading, so we could remove it even if the copying fails...
tempAutosave.remove();
}
}
}
/**
* @brief Returns a list of autosave files for the current project
* @return list of autosaves; may be empty
*/
QStringList Autosave::getAutosave()
{
const auto projectPath = QFileInfo(mPetrack.getProFileName());
return Autosave::getAutosave(projectPath);
}
/**
* @brief Returns a list of autosave files for the project at projectPath
* @param projectPath filepath of .pet-file
* @return list of autosaves; may be empty
*/
QStringList Autosave::getAutosave(const QFileInfo &projectPath)
{
if(projectPath.isFile())
{
QStringList list;
const auto autosavePetName = autosaveNamesPet(projectPath.absoluteFilePath()).final;
const QFileInfo autosavePet{autosavePetName};
if(autosavePet.exists())
{
list.append(autosavePetName);
}
const auto autosaveTrcName = autosaveNamesTrc(projectPath.absoluteFilePath()).final;
const QFileInfo autosaveTrc{autosaveTrcName};
if(autosaveTrc.exists())
{
list.append(autosaveTrcName);
}
return list;
}
return QStringList{};
}
......@@ -21,6 +21,7 @@
#include "personStorage.h"
#include "animation.h"
#include "autosave.h"
#include "control.h"
#include "multiColorMarkerWidget.h"
#include "pMessageBox.h"
......@@ -34,6 +35,7 @@
*/
void PersonStorage::splitPerson(size_t pers, int frame)
{
mAutosave.trackPersonModified();
int j;
if(mPersons.at(pers).firstFrame() < frame)
......@@ -66,6 +68,7 @@ void PersonStorage::splitPerson(size_t pers, int frame)
*/
bool PersonStorage::splitPersonAt(const Vec2F &point, int frame, const QSet<int> &onlyVisible)
{
mAutosave.trackPersonModified();
for(size_t i = 0; i < mPersons.size(); ++i)
{ // ueber TrackPerson
if(((onlyVisible.empty()) || (onlyVisible.contains(i))) &&
......@@ -90,6 +93,7 @@ bool PersonStorage::splitPersonAt(const Vec2F &point, int frame, const QSet<int>
*/
bool PersonStorage::delPointOf(int pers, int direction, int frame)
{
mAutosave.trackPersonModified();
if(direction == -1)
{
for(int j = 0; j < frame - mPersons.at(pers).firstFrame(); ++j)
......@@ -125,6 +129,7 @@ bool PersonStorage::delPointOf(int pers, int direction, int frame)
*/
bool PersonStorage::delPoint(const Vec2F &point, int direction, int frame, const QSet<int> &onlyVisible)
{
mAutosave.trackPersonModified();
for(int i = 0; i < static_cast<int>(mPersons.size()); ++i)
{ // ueber TrackPerson
if(((onlyVisible.empty()) || (onlyVisible.contains(i))) &&
......@@ -146,6 +151,7 @@ bool PersonStorage::delPoint(const Vec2F &point, int direction, int frame, const
*/
void PersonStorage::delPointAll(Direction direction, int frame)
{
mAutosave.trackPersonModified();
for(size_t i = 0; i < mPersons.size(); ++i) // ueber TrackPerson
{
if(mPersons.at(i).trackPointExist(frame))
......@@ -190,6 +196,7 @@ void PersonStorage::delPointAll(Direction direction, int frame)
*/
void PersonStorage::delPointInsideROI()
{
mAutosave.trackPersonModified();
QRectF rect = mMainWindow.getRecoRoiItem()->rect();
bool inside;
......@@ -225,6 +232,7 @@ void PersonStorage::delPointInsideROI()
*/
void PersonStorage::delPointROI()
{
mAutosave.trackPersonModified();
int anz = 0;
QRectF rect = mMainWindow.getRecoRoiItem()->rect();
......@@ -258,6 +266,7 @@ void PersonStorage::delPointROI()
*/
bool PersonStorage::editTrackPersonComment(const Vec2F &point, int frame, const QSet<int> &onlyVisible)
{
mAutosave.trackPersonModified();
for(int i = 0; i < static_cast<int>(mPersons.size()); ++i) // ueber TrackPerson
{
if(((onlyVisible.empty()) || (onlyVisible.contains(i))) &&
......@@ -312,6 +321,7 @@ bool PersonStorage::editTrackPersonComment(const Vec2F &point, int frame, const
*/
bool PersonStorage::setTrackPersonHeight(const Vec2F &point, int frame, const QSet<int> &onlyVisible)
{
mAutosave.trackPersonModified();
for(int i = 0; i < static_cast<int>(mPersons.size()); ++i) // ueber TrackPerson
{
if(((onlyVisible.empty()) || (onlyVisible.contains(i))) &&
......@@ -379,6 +389,7 @@ bool PersonStorage::setTrackPersonHeight(const Vec2F &point, int frame, const QS
*/
bool PersonStorage::resetTrackPersonHeight(const Vec2F &point, int frame, QSet<int> onlyVisible)
{
mAutosave.trackPersonModified();
for(int i = 0; i < static_cast<int>(mPersons.size()); ++i) // ueber TrackPerson
{
if(((onlyVisible.empty()) || (onlyVisible.contains(i))) &&
......@@ -472,6 +483,11 @@ bool PersonStorage::addPoint(
reco::RecognitionMethod method,
int *pers)
{
if(point.qual() > 100)
{
// manually added point
mAutosave.trackPersonModified();
}
bool found = false;
int i, iNearest = 0.;
float scaleHead;
......@@ -737,6 +753,7 @@ PersonStorage::getProximalPersons(const QPointF &pos, int frame, QSet<int> selec
*/
void PersonStorage::recalcHeight(float altitude)
{
mAutosave.trackPersonModified();
for(auto &person : mPersons)
{
person.recalcHeight(altitude);
......@@ -949,6 +966,7 @@ void PersonStorage::checkPlausibility(
/// optimize color for all persons
void PersonStorage::optimizeColor()
{
mAutosave.trackPersonModified();
for(auto &person : mPersons)
{
if(person.color().isValid())
......@@ -961,6 +979,7 @@ void PersonStorage::optimizeColor()
/// reset the height of all persons, but not the pos of the trackpoints
void PersonStorage::resetHeight()
{
mAutosave.trackPersonModified();
for(auto &person : mPersons)
{
person.resetHeight();
......@@ -970,6 +989,7 @@ void PersonStorage::resetHeight()
/// reset the pos of the tzrackpoints, but not the heights
void PersonStorage::resetPos()
{
mAutosave.trackPersonModified();
for(auto &person : mPersons)
{
for(auto &point : person)
......@@ -1040,6 +1060,7 @@ bool PersonStorage::printHeightDistribution()
*/
void PersonStorage::setMarkerHeights(const std::unordered_map<int, float> &heights)
{
mAutosave.trackPersonModified();
for(auto &person : mPersons) // over TrackPerson
{
for(auto &point : person) // over TrackPoints
......@@ -1070,8 +1091,12 @@ void PersonStorage::setMarkerHeights(const std::unordered_map<int, float> &heigh
* @param personID internal id of persons (0 based)
* @param markerIDs new marker ID
*/
void PersonStorage::setMarkerID(int personID, int markerID)
void PersonStorage::setMarkerID(int personID, int markerID, bool manual)
{
if(manual)
{
mAutosave.trackPersonModified();
}
auto &person = mPersons.at(personID);
person.setMarkerID(markerID);
for(auto &trackPoint : person) // over TrackPoints
......@@ -1086,6 +1111,7 @@ void PersonStorage::setMarkerID(int personID, int markerID)
*/
void PersonStorage::setMarkerIDs(const std::unordered_map<int, int> &markerIDs)
{
mAutosave.trackPersonModified();
for(int i = 0; i < static_cast<int>(mPersons.size()); ++i) // over TrackPerson
{
// personID of current person
......@@ -1115,6 +1141,7 @@ void PersonStorage::setMarkerIDs(const std::unordered_map<int, int> &markerIDs)
*/
void PersonStorage::purge(int frame)
{
mAutosave.trackPersonModified();
int i, j;
float count; ///< number of trackpoints without recognition
......@@ -1242,6 +1269,7 @@ void PersonStorage::insertFeaturePoint(
*/
int PersonStorage::merge(int pers1, int pers2)
{
mAutosave.trackPersonModified();
auto &person = mPersons.at(pers1);
auto &other = mPersons.at(pers2);
const bool extrapolate = mMainWindow.getControlWidget()->trackExtrapolation->checkState() == Qt::Checked;
......
......@@ -605,6 +605,17 @@ void Petrack::openProject(QString fileName, bool openSeq) // default fileName=""
tr("PeTrack project file (*.pet);;All files (*.*)"));
}
if(Autosave::autosaveExists(fileName) && fileName != mProFileName)
{
auto ret = PQuestion(this, "Autosave detected", "An autosave was detected.\nDo you want to load the Autosave?");
if(ret == PMessageBox::StandardButton::Yes)
{
setProFileName(fileName);
mAutosave.loadAutosave();
return;
}
}
if(!fileName.isEmpty())
{
QFile file(fileName);
......@@ -2529,6 +2540,7 @@ void Petrack::closeEvent(QCloseEvent *event)
if(maybeSave())
{
writeSettings();
mAutosave.deleteAutosave();
event->accept();
}
else
......@@ -3045,6 +3057,7 @@ void Petrack::exportTracker(QString dest) // default = ""
progress.setValue(mPersonStorage.nbPersons() + 1);
std::cout << " finished " << std::endl;
mAutosave.resetTrackPersonCounter();
#ifdef TIME_MEASUREMENT
time1 += clock() - tstart;
......@@ -3974,6 +3987,23 @@ double Petrack::getHeadSize(QPointF *pos, int pers, int frame)
}
}
void Petrack::setProFileName(const QString &fileName)
{
// don't change project Name to an autosave
if(mAutosave.isAutosave(fileName) || fileName == mProFileName)
{
return;
}
// Change project => delete old autosave
mAutosave.deleteAutosave();
// NOTE: Use only the global variant in future?
// global one in helper.h because it is needed to use getFileList and shouldn't depend on Petrack
proFileName = fileName;
mProFileName = fileName;
updateWindowTitle();
}
/**
* @brief Return the user's selection of pedestrians/trajectories
*
......
......@@ -210,7 +210,7 @@ void TrackerItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
if(changeID)
{
int markerID = QInputDialog::getInt(mMainWindow, "Enter Marker ID", "Marker ID:");
mPersonStorage.setMarkerID(i, markerID);
mPersonStorage.setMarkerID(i, markerID, true);
}
}
else if(selectedAction == infoTrj)
......
......@@ -60,7 +60,8 @@ SCENARIO("I want to get the render data with one person loaded", "[ui]")
// default time offset 0
Petrack pet;
PersonStorage st{pet};
Autosave save{pet};
PersonStorage st{pet, save};
ExtrCalibMock extrCalib{st};
/*
......