Newer
Older
/*
* PeTrack - Software for tracking pedestrians movement in videos
* Copyright (C) 2023 Forschungszentrum Jülich GmbH, IAS-7
*
* 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 <QtOpenGL>
#include <QtWidgets>
#include "aboutDialog.h"
#include "animation.h"
#include "autoCalib.h"
#include "backgroundItem.h"
#include "calibFilter.h"
#include "codeMarkerWidget.h"
#include "helper.h"
#include "multiColorMarkerItem.h"
#include "multiColorMarkerWidget.h"
#include "openMoCapDialog.h"
#include "pMessageBox.h"
#include "petrack.h"
#include "player.h"
#include "roiItem.h"
#include "stereoItem.h"
#include "stereoWidget.h"
#include <QtPrintSupport/QPrintDialog>
#include <QtPrintSupport/QPrinter>
#include <cmath>
int Petrack::trcVersion = 0;
// Reihenfolge des anlegens der objekte ist sehr wichtig
Petrack::Petrack(QString petrackVersion) :
mExtrCalibration(mPersonStorage),
mPetrackVersion(std::move(petrackVersion)),
mAuthors(IO::readAuthors(QCoreApplication::applicationDirPath() + "/.zenodo.json"))
mHeadSize = -1;
mCmPerPixel = -1;
mScene = nullptr;
mTracker = nullptr;
mTrackerReal = nullptr; // damit beim zeichnen von control mit analysePlot nicht auf einen feheler laeuft
mStatusLabelFPS = nullptr;
mStatusLabelPosReal = nullptr;
mImageItem = nullptr;
mRecognitionChanged = true;
mTrackChanged = true;
mCoordItem = nullptr;
mImage = nullptr;
setLoading(true);
setAcceptDrops(true);
int space = 2;
mBrightContrastFilter.disable();
mBorderFilter.disable();
mSwapFilter.disable();
mBackgroundFilter.disable();
mCalibFilter = new CalibFilter; // schoener waere erst zu erzeugen, wenn video geladen wird, da sonst bei stereo
// erst normealer und dann stereo objekt erzeugt wird
mCalibFilter->disable(); // aber control widget greift schon bei erzeugung auf alle objekte zur einstellung zurueck
mTrackingRoiItem = new RoiItem(this, Qt::blue);
connect(mTrackingRoiItem, &RoiItem::changed, this, [=]() { this->setTrackChanged(true); });
mTrackingRoiItem->setZValue(4); // groesser heisst weiter oben
mRecognitionRoiItem = new RoiItem(this, Qt::green);
connect(mRecognitionRoiItem, &RoiItem::changed, this, [=]() { this->setRecognitionChanged(true); });
mRecognitionRoiItem->setZValue(5); // groesser heisst weiter oben
mControlWidget = new Control(*this, *mScene, mReco, *mTrackingRoiItem, *mRecognitionRoiItem, mMissingFrames);
mStereoWidget = new StereoWidget(this);
mStereoWidget->setWindowFlags(Qt::Window);
mStereoWidget->setWindowTitle("Stereo parameter");
mColorRangeWidget = new ColorRangeWidget(this);
mColorRangeWidget->setWindowFlags(Qt::Window);
mColorRangeWidget->setWindowTitle("Color range");
mColorMarkerWidget = new ColorMarkerWidget(this);
mColorMarkerWidget->setWindowFlags(Qt::Window);
mColorMarkerWidget->setWindowTitle("Color marker parameter");
mCodeMarkerWidget = new CodeMarkerWidget(this, mReco.getCodeMarkerOptions(), nullptr);
mCodeMarkerWidget->setWindowFlags(Qt::Window);
mCodeMarkerWidget->setWindowTitle("Code marker parameter");
mMultiColorMarkerWidget = new MultiColorMarkerWidget(this);
mMultiColorMarkerWidget->setWindowFlags(Qt::Window);
mMultiColorMarkerWidget->setWindowTitle("MultiColor marker parameter");
mImageItem = new ImageItem(this); // durch uebergabe von scene wird indirekt ein scene->addItem() aufgerufen
mAnimation = new Animation(this);
mLogoItem = new LogoItem(this); // durch uebergabe von scene wird indirekt ein scene->addItem() aufgerufen
mLogoItem->setZValue(6); // groesser heisst weiter oben
mExtrCalibration.setMainWindow(this);
mGridItem = new GridItem(this);
mGridItem->setZValue(2.5); // durch uebergabe von scene wird indirekt ein scene->addItem() aufgerufen
mCoordItem = new CoordItem(this);
mCoordItem->setZValue(3); // groesser heisst weiter oben
mImageItem->setCoordItem(mCoordItem);
mViewWidget = new ViewWidget(this);
connect(mView, &GraphicsView::mouseDoubleClick, this, [this]() { this->openSequence(); });
connect(mView, &GraphicsView::mouseShiftDoubleClick, this, &Petrack::addManualTrackPointOnlyVisible);
connect(mView, &GraphicsView::mouseShiftControlDoubleClick, this, &Petrack::splitTrackPerson);
connect(mView, &GraphicsView::mouseControlDoubleClick, this, &Petrack::addOrMoveManualTrackPoint);
connect(mView, &GraphicsView::mouseRightDoubleClick, this, &Petrack::deleteTrackPoint);
connect(mView, &GraphicsView::mouseMiddleDoubleClick, this, &Petrack::deleteTrackPointAll);
connect(mView, &GraphicsView::mouseShiftWheel, this, &Petrack::skipToFrameWheel);
connect(mView, &GraphicsView::mouseCtrlAltDoubleClick, this, &Petrack::skipToFrameFromTrajectory);
d.kilic
committed
connect(mView, &GraphicsView::mouseAltMoved, this, &Petrack::moveTrackPoint);
connect(mView, &GraphicsView::mouseAltPressed, this, &Petrack::selectPersonForMoveTrackPoint);
connect(mView, &GraphicsView::altReleased, this, &Petrack::releaseTrackPoint);
connect(mView, &GraphicsView::mouseAltReleased, this, &Petrack::releaseTrackPoint);
connect(mView, &GraphicsView::mouseCtrlWheel, this, &Petrack::scrollShowOnly);
mPlayerWidget = new Player(mAnimation, this);
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->setSpacing(space);
vLayout->addWidget(mViewWidget);
vLayout->addWidget(mPlayerWidget);
//---------------------------
mTracker = new Tracker(this, mPersonStorage);
mTrackerReal = new TrackerReal(this, mPersonStorage);
mTrackerItem = new TrackerItem(this, mPersonStorage);
mControlWidget->getColorPlot()->setPersonStorage(&mPersonStorage);
#ifdef QWT
mControlWidget->getAnalysePlot()->setTrackerReal(mTrackerReal);
#endif
//---------------------------
mStereoItem = new StereoItem(this);
mStereoItem->setZValue(2); // groesser heisst weiter oben
mStereoItem->setVisible(false);
//---------------------------
mColorMarkerItem = new ColorMarkerItem(this);
mColorMarkerItem->setZValue(2); // groesser heisst weiter oben
mColorMarkerItem->setVisible(false);
//---------------------------
mCodeMarkerItem = new CodeMarkerItem(this, mReco.getCodeMarkerOptions());
mCodeMarkerItem->setZValue(2); // groesser heisst weiter oben
mCodeMarkerItem->setVisible(false);
//---------------------------
mMultiColorMarkerItem = new MultiColorMarkerItem(this);
mMultiColorMarkerItem->setZValue(2); // groesser heisst weiter oben
mMultiColorMarkerItem->setVisible(false);
//---------------------------
mBackgroundItem = new BackgroundItem(this);
mBackgroundItem->setZValue(2.2); // um so groesser um so hoeher um so eher zu sehen
mBackgroundItem->setVisible(false);
//---------------------------
mMoCapItem = new MoCapItem(*this, *mAnimation, mMoCapController);
mMoCapItem->setZValue(3); // um so groesser um so hoeher um so eher zu sehen
/// Add Items
mScene->addItem(mImageItem);
mScene->addItem(mLogoItem);
mScene->addItem(mGridItem);
mScene->addItem(mCoordItem);
mScene->addItem(mTrackingRoiItem);
mScene->addItem(mRecognitionRoiItem);
mScene->addItem(mTrackerItem);
mScene->addItem(mStereoItem);
mScene->addItem(mColorMarkerItem);
mScene->addItem(mCodeMarkerItem);
mScene->addItem(mMultiColorMarkerItem);
mScene->addItem(mBackgroundItem);
//---------------------------
mCentralLayout = new QHBoxLayout;
mCentralLayout->setMargin(space);
mCentralWidget = new QFrame;
mCentralWidget->setFrameStyle(QFrame::Sunken | QFrame::StyledPanel);
mCentralWidget->setLayout(mCentralLayout);
setCentralWidget(mCentralWidget);
mSplitter = new QSplitter(this);
// create playAndView-Widget to wrap layout, since QSplitter only accepts widgets
QWidget *playAndView = new QWidget(this);
playAndView->setLayout(vLayout);
mSplitter->addWidget(playAndView);
mSplitter->addWidget(mControlWidget);
mSplitter->setStretchFactor(0, 1);
mSplitter->setStretchFactor(1, 0);
mCentralLayout->addWidget(mSplitter);
setWindowTitle(tr("PeTrack"));
//---------------------------
mAutoCalib.setMainWindow(this);
//---------------------------
createActions();
createMenus();
createStatusBar();
auto *exportShortCut = new QShortcut{QKeySequence("Ctrl+e"), this};
connect(exportShortCut, &QShortcut::activated, this, [=]() { exportTracker(); });
auto *toggleOnlineTracking = new QShortcut{QKeySequence("Shift+t"), this};
connect(toggleOnlineTracking, &QShortcut::activated, this, [=]() { mControlWidget->toggleOnlineTracking(); });
// TODO delete once we get Options to be value only (i.e. no Pointer/Ref anymore)
mReco.getCodeMarkerOptions().setControlWidget(mControlWidget);
mReco.getCodeMarkerOptions().setCodeMarkerItem(mCodeMarkerItem);
mSeqFileName = QDir::currentPath(); // fuer allerersten Aufruf des Programms
saveXml(mDefaultSettings); // noch nicht noetig, da eh noch nicht fkt
mShowFPS = 0;
mTrcFileName = "";
// initialer Aufruf, damit beim reinen Laden einer Videodatei die Defaultwerte in control genommen werden zum Setzen
setHeadSize();
// um im background subtraction filter das hoehenbild zu beruecksichtigen
mBackgroundFilter.setStereoContext(&mStereoContext);
mAutoBackTrack = true; // ist der default, dann wenn in XML-Datei nicht drin steht
mAutoTrackOptimizeColor = false; // ist der default, dann wenn in XML-Datei nicht drin steht
setLoading(false);
}
Petrack::~Petrack()
{
delete mImage;
// hier muessten weitere stehen insb die im konstruktor erzeugt werden
// aber da petrack nur vernichtet wird, wenn programm beendet wird, kann man sich das auch schenken
}
void Petrack::dragEnterEvent(QDragEnterEvent *event)
{
/**
* @brief Accepts dropped .pet, .trc and media files
*
* Opens the project for a .pet. Imports the trajectories for a .trc
* and tries to open the sequence for any other kind of file.
*
* @param event
*/
if(event->mimeData()->urls().first().toLocalFile().right(4) == ".pet")
else if(event->mimeData()->urls().first().toLocalFile().right(4) == ".trc")
event->acceptProposedAction();
}
}
void Petrack::updateSceneRect()
{
{
iW = mImage->width();
iH = mImage->height();
bS = getImageBorderSize();
}
if(mControlWidget->getCalibCoordShow())
double scale = mControlWidget->getCalibCoordScale() / 10.;
double tX = mControlWidget->getCalibCoordTransX() / 10.;
double tY = mControlWidget->getCalibCoordTransY() / 10.;
// setzen der bounding box der scene
// Faktor 1.1 dient dazu, dass auch Zahl "1" bei coord gut in sichtbaren Bereich passt
double xMin = (tX - 1.1 * scale < -bS) ? tX - 1.1 * scale : -bS;
double yMin = (tY - 1.1 * scale < -bS) ? tY - 1.1 * scale : -bS;
double xMax = (tX + 1.1 * scale > iW - bS) ? tX + 1.1 * scale : iW - bS;
double yMax = (tY + 1.1 * scale > iH - bS) ? tY + 1.1 * scale : iH - bS;
mScene->setSceneRect(xMin, yMin, xMax - xMin, yMax - yMin);
/**
* @brief Loads the content of a .pet file into petrack
*
* @param doc the DOM of the .pet file
* @param openSeq true, if sequence given in doc should be opened
*/
mMissingFrames.reset();
bool missingFramesExecuted = false;
std::vector<MissingFrame> missingFrames{};
QString seq;
int frame = -1, sourceFrameIn = -1, sourceFrameOut = -1;
double fps = DEFAULT_FPS;
int onlyPeopleNr = 1;
QString onlyPeopleNrList = "1";
int zoom = 250, rotate = 0, hScroll = 0, vScroll = 0;
enum Camera cam = cameraUnset;
setLoading(true);
for(QDomElement elem = root.firstChildElement(); !elem.isNull(); elem = elem.nextSiblingElement())
{
if(elem.hasAttribute("STATUS_HEIGHT"))
if(mStatusPosRealHeight) // null kann eigentlich nicht vorkommen, da im constructor von petrack erzeugt
// wird
mStatusPosRealHeight->setValue(elem.attribute("STATUS_HEIGHT").toDouble());
else if(elem.tagName() == "STEREO")
else if(elem.tagName() == "COLOR_MARKER")
else if(elem.tagName() == "CODE_MARKER")
else if(elem.tagName() == "MULTI_COLOR_MARKER")
else if(elem.tagName() == "MOCAP")
{
mMoCapController.getXml(elem);
}
else if(elem.tagName() == "CONTROL")
{
mControlWidget->getXml(elem);
QDomElement tmpElem = (elem.firstChildElement("TRACKING")).firstChildElement("PATH");
if(tmpElem.hasAttribute("ONLY_PEOPLE_NR"))
if(tmpElem.hasAttribute("ONLY_PEOPLE_NR_LIST"))
else if(elem.tagName() == "EXTR_CALIBRATION")
{
mExtrCalibration.getXml(elem);
}
else if(elem.tagName() == "PLAYER")
if(elem.hasAttribute("SOURCE_FRAME_IN"))
{
sourceFrameIn = elem.attribute("SOURCE_FRAME_IN").toInt();
}
if(elem.hasAttribute("SOURCE_FRAME_OUT"))
{
sourceFrameOut = elem.attribute("SOURCE_FRAME_OUT").toInt();
}
if(elem.hasAttribute("PLAYER_SPEED_FIXED"))
mPlayerWidget->setPlayerSpeedLimited(elem.attribute("PLAYER_SPEED_FIXED").toInt());
else if(elem.tagName() == "VIEW")
if(elem.hasAttribute("ANTIALIAS"))
mAntialiasAct->setChecked(elem.attribute("ANTIALIAS").toInt() == Qt::Checked);
mOpenGLAct->setChecked(elem.attribute("OPENGL").toInt() == Qt::Checked);
if(elem.hasAttribute("SAVE_TRANSFORMED"))
mCropZoomViewAct->setChecked(elem.attribute("SAVE_TRANSFORMED") == Qt::Checked);
if(elem.hasAttribute("TRANSFORMATION"))
QString matStr = elem.attribute("TRANSFORMATION");
QTextStream in(&matStr);
in >> zoom >> rotate >> hScroll >> vScroll;
}
{
cam = (enum Camera) elem.attribute("CAMERA").toInt();
}
if(elem.hasAttribute("HIDE_CONTROLS"))
mHideControlsAct->setChecked(elem.attribute("HIDE_CONTROLS").toInt() == Qt::Checked);
}
else if(elem.tagName() == "AUTO_TRACK")
if(elem.hasAttribute("BACK_TRACK"))
{
mAutoBackTrack = elem.attribute("BACK_TRACK").toInt();
}
if(elem.hasAttribute("OPTIMZE_COLOR"))
{
mAutoTrackOptimizeColor = elem.attribute("OPTIMZE_COLOR").toInt();
}
}
else if(elem.tagName() == "MISSING_FRAMES")
{
if((elem.hasAttribute("executed")) && (elem.attribute("executed").toInt() == 1))
{
missingFramesExecuted = true;
auto node = elem.firstChildElement("FRAME");
for(; !node.isNull(); node = node.nextSiblingElement("FRAME"))
{
size_t num = node.attribute("NUM_FRAME").toUInt();
int count = node.attribute("NUM_MISSING").toInt();
missingFrames.push_back(MissingFrame{num, count});
}
}
}
SPDLOG_ERROR("Unknown PETRACK tag {}", elem.tagName());
}
// open koennte am schluss passieren, dann wuerde nicht erst unveraendertes bild angezeigt,
// dafuer koennte es aber sein, dass werte zb bei fx nicht einstellbar sind!
mSeqFileName = seq;
openSequence(seq); // wenn leer, dann kommt abfrage hoch, welche datei; abbrechen, wenn aktuelle gewuenscht
mMissingFrames.setExecuted(missingFramesExecuted);
mMissingFrames.setMissingFrames(missingFrames);
mViewWidget->setZoomLevel(zoom);
mViewWidget->setRotateLevel(rotate);
mView->horizontalScrollBar()->setValue(hScroll);
mView->verticalScrollBar()->setValue(vScroll);
bool loaded = false;
if(!mBackgroundFilter.getFilename().isEmpty())
if(!(loaded = mBackgroundFilter.load(mBackgroundFilter.getFilename())))
SPDLOG_ERROR("Error: loading background file {}!", mBackgroundFilter.getFilename());
mPlayerWidget->setFrameInNum(sourceFrameIn == -1 ? mAnimation->getSourceInFrameNum() : sourceFrameIn);
mPlayerWidget->setFrameOutNum(sourceFrameOut == -1 ? mAnimation->getSourceOutFrameNum() : sourceFrameOut);
if(mControlWidget->isFilterBgChecked() &&
!loaded) // mit dem anfangs geladenen bild wurde bereits faelschlicherweise bg bestimmt
{
mBackgroundFilter.reset(); // erst nach dem springen zu einem frame background bestimmen
mPlayerWidget->skipToFrame(frame); // hier wird updateImage ausgefuehrt
}
// nicht schon in control, sonst loescht opensequence wieder tracker
{
// vorher loeschen aller trajektorien, da sonst nach start im ersten bild
// mgl zwei trackpoints
// beim haendischen importieren sind weiterhin parallele trajektorien moeglich (warnung wird ausgegeben)
frame = 0; // default
if((mPersonStorage.largestLastFrame() >= frame) && (getPersonStorage().smallestFirstFrame() <= frame))
mTracker->reset();
}
importTracker(mTrcFileName);
}
mControlWidget->setTrackShowOnlyNr(onlyPeopleNr);
mControlWidget->trackShowOnlyNrList()->setText(onlyPeopleNrList);
setCamera();
mPlayerWidget->setFPS(fps); // erst spaet setzen, damit Wert den des geladenen Videos ueberschreiben kann
setLoading(false);
}
void Petrack::openProject(QString fileName, bool openSeq) // default fileName="", openSequence = true
{
if(!QFileInfo(mProFileName).isDir()) // a project is already loaded
fileName = QFileDialog::getOpenFileName(
this,
tr("Select project file"),
QFileInfo(mProFileName).path(),
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(!file.open(QIODevice::ReadOnly))
PCritical(this, tr("PeTrack"), tr("Cannot open %1:\n%2.").arg(fileName, file.errorString()));
return;
}
resetSettings();
QDomDocument doc("PETRACK"); // eigentlich Pfad zu Beschreibungsdatei fuer Dateiaufbau
PCritical(this, tr("PeTrack"), tr("Cannot read content from %1.").arg(fileName));
if(root.attribute("VERSION") != mPetrackVersion)
PWarning(
this,
tr("PeTrack"),
tr("Reading %1:\nDifferent version numbers %2 (application) and %3 (file) may cause problems.")
.arg(fileName, mPetrackVersion, root.attribute("VERSION")));
mLastTrackerExport = mTrcFileName;
updateWindowTitle();
}
}
void Petrack::saveXml(QDomDocument &doc)
{
QDomElement elem;
QDomElement root = doc.createElement("PETRACK");
root.setAttribute("VERSION", mPetrackVersion);
doc.appendChild(root);
// main settings (window size, status hight)
elem = doc.createElement("MAIN");
QString seq = getFileList(mSeqFileName, mProFileName);
elem.setAttribute("SRC", seq);
elem.setAttribute("STATUS_HEIGHT", mStatusPosRealHeight->value());
root.appendChild(elem);
// control settings (right control widget)
elem = doc.createElement("CONTROL");
mControlWidget->setXml(elem);
root.appendChild(elem);
// Reprojection error extrinsic calib
elem = doc.createElement("EXTR_CALIBRATION");
mExtrCalibration.setXml(elem);
root.appendChild(elem);
// settings for stereo
elem = doc.createElement("STEREO");
mStereoWidget->setXml(elem);
root.appendChild(elem);
// settings for color marker
elem = doc.createElement("COLOR_MARKER");
mColorMarkerWidget->setXml(elem);
root.appendChild(elem);
// settings for code marker
elem = doc.createElement("CODE_MARKER");
mCodeMarkerWidget->setXml(elem);
root.appendChild(elem);
// settings for multicolor marker
elem = doc.createElement("MULTI_COLOR_MARKER");
mMultiColorMarkerWidget->setXml(elem);
root.appendChild(elem);
// settings for MoCap-Visualization
elem = doc.createElement("MOCAP");
mMoCapController.setXml(elem);
root.appendChild(elem);
// player settings (which frame, frame range)
elem = doc.createElement("PLAYER");
elem.setAttribute("FRAME", mPlayerWidget->getPos()); // == mAnimation->getCurrentFrameNum()
elem.setAttribute("FPS", mAnimation->getFPS());
elem.setAttribute("SOURCE_FRAME_IN", mPlayerWidget->getFrameInNum());
elem.setAttribute("SOURCE_FRAME_OUT", mPlayerWidget->getFrameOutNum());
elem.setAttribute("PLAYER_SPEED_FIXED", mPlayerWidget->getPlayerSpeedLimited());
root.appendChild(elem);
// view settings (zoom, rotate, alias, opengl)
elem = doc.createElement("VIEW");
elem.setAttribute("ANTIALIAS", mAntialiasAct->isChecked());
elem.setAttribute("OPENGL", mOpenGLAct->isChecked());
elem.setAttribute("SAVE_TRANSFORMED", mCropZoomViewAct->isChecked());
elem.setAttribute(
"TRANSFORMATION",
QString("%1 %2 %3 %4")
.arg(mViewWidget->getZoomLevel())
.arg(mViewWidget->getRotateLevel())
.arg(mView->horizontalScrollBar()->value())
.arg(mView->verticalScrollBar()->value()));
#ifndef STEREO_DISABLED
#else
elem.setAttribute("CAMERA", cameraUnset);
#endif
elem.setAttribute("HIDE_CONTROLS", mHideControlsAct->isChecked());
root.appendChild(elem);
// auto track settings
elem = doc.createElement("AUTO_TRACK");
elem.setAttribute("BACK_TRACK", mAutoBackTrack);
elem.setAttribute("OPTIMZE_COLOR", mAutoTrackOptimizeColor);
root.appendChild(elem);
elem = doc.createElement("MISSING_FRAMES");
elem.setAttribute("executed", mMissingFrames.isExecuted());
for(const auto &missingFrame : mMissingFrames.getMissingFrames())
{
auto frame = doc.createElement("FRAME");
frame.setAttribute("NUM_FRAME", static_cast<int>(missingFrame.mNumber));
frame.setAttribute("NUM_MISSING", missingFrame.mCount);
elem.appendChild(frame);
}
root.appendChild(elem);
/// rueckgabewert zeigt an, ob gesichert werden konnte
bool Petrack::saveSameProject()
{
return saveProject(mProFileName);
}
bool Petrack::saveProjectAs()
{
auto fileName = QFileDialog::getSaveFileName(
this, tr("Select project file"), mProFileName, tr("PeTrack project file (*.pet);;All files (*.*)"));
return saveProject(fileName);
}
/// rueckgabewert zeigt an, ob gesichert werden konnte
bool Petrack::saveProject(QString fileName) // default fileName=""
{
// if no destination file or folder is given
if(fileName.isEmpty() && QFileInfo(mProFileName).isDir())
fileName = QFileDialog::getSaveFileName(
this, tr("Select project file"), mProFileName, tr("PeTrack project file (*.pet);;All files (*.*)"));
QDomDocument doc("PETRACK"); // eigentlich Pfad zu Beschreibungsdatei fuer Dateiaufbau
saveXml(doc);
// file output
QByteArray byteArray;
QXmlStreamWriter xmlStream(&byteArray);
xmlStream.setAutoFormatting(true);
xmlStream.setAutoFormattingIndent(4);
xmlStream.writeStartDocument();
xmlStream.writeDTD("<!DOCTYPE PETRACK>");
QDomElement element = doc.documentElement();
writeXmlElement(xmlStream, element);
xmlStream.writeEndDocument();
QFile file(fileName);
if(!file.open(QFile::WriteOnly | QFile::Truncate | QFile::Text))
PCritical(this, tr("PeTrack"), tr("Cannot save %1:\n%2.").arg(fileName, file.errorString()));
file.close();
return false;
}
file.write(byteArray);
file.close(); // also flushes the file
statusBar()->showMessage(tr("Saved project to %1.").arg(fileName), 5000);
SPDLOG_INFO("save project to {}", fileName);
void Petrack::writeXmlElement(QXmlStreamWriter &xmlStream, QDomElement element)
QVector<QString> attribute_names;
for(int i = 0; i < attributes.size(); ++i)
{
attribute_names.push_back(attributes.item(i).toAttr().name());
}
// TODO: check if sorting of elements fits our needs
std::stable_sort(attribute_names.begin(), attribute_names.end()); // for a canonical XML
// Wants this macro instead of range-based for loop
foreach(QString name, attribute_names)
{
QDomAttr attr = element.attributeNode(name);
xmlStream.writeAttribute(attr.name(), attr.value());
}
// order of child nodes is defined at creation
if(element.hasChildNodes())
{
for(int i = 0; i < children.size(); ++i)
{
writeXmlElement(xmlStream, children.at(i).toElement());
}
}
xmlStream.writeEndElement();
}
/**
* @brief Opens camera livestream from cam with camID
* @param camID id of camera to use (defaults to 0)
*/
void Petrack::openCameraLiveStream(int camID /* =-1*/)
SPDLOG_INFO("No camera ID delivered: Set CameraID to 0 (default Camera)");
if(!mAnimation->openCameraStream(camID))
PCritical(this, tr("PeTrack"), tr("Cannot start Camera Livestream."));
SPDLOG_INFO(
"open {} ({} frames; {} fps; {} x {} pixel)",
mSeqFileName,
mAnimation->getNumFrames(),
mAnimation->getFPS(),
mAnimation->getSize().width(),
mAnimation->getSize().height());
updateSequence();
updateWindowTitle();
mPlayerWidget->setFPS(mAnimation->getFPS());
}
void Petrack::openSequence(QString fileName) // default fileName = ""
{
fileName = QFileDialog::getOpenFileName(
this,
tr("Open video or image sequence"),
QFileInfo(mSeqFileName).path(),
tr("All supported types (*.avi *.mpg *.mts *.m2t *.m2ts *.wmv *.mp4 *.mov *.mxf *.bmp *.dib *.jpeg *.jpg "
"*.jpe *.png *.pbm *.pgm *.ppm *.sr *.ras *.tiff *.tif *.exr *.jp2);;Video (*.avi *.mpg *.mts *.m2ts "
"*.m2t *.wmv *.mov *.mp4 *.mxf);;Images (*.bmp *.dib *.jpeg *.jpg *.jpe *.png *.pbm *.pgm *.ppm *.sr "
"*.ras *.tiff *.tif *.exr *.jp2);;Windows bitmaps (*.bmp *.dib);;JPEG (*.jpeg *.jpg *.jpe);;Portable "
"network graphics (*.png);;Portable image format (*.pbm *.pgm *.ppm);;Sun rasters (*.sr *.ras);;TIFF "
"(*.tiff *.tif);;OpenEXR HDR (*.exr);;JPEG 2000 (*.jp2);;All files (*.*)"));
if(!mAnimation->openAnimation(fileName))
PCritical(this, tr("PeTrack"), tr("Cannot load %1.").arg(fileName));
return;
}
mCameraGroupView->setEnabled(mAnimation->isStereoVideo());
mCameraMenu->setEnabled(mAnimation->isStereoVideo());
#ifdef STEREO
delete mStereoContext;
mStereoContext = new pet::StereoContext(this);
}
bool lastIsStereoVideo = mAnimation->isStereoVideo();
if(mCalibFilter == NULL || (mAnimation->isStereoVideo() != lastIsStereoVideo))
{
lastCalibFilterEnabled = mCalibFilter->getEnabled();
delete mCalibFilter;
}
{
mCalibFilter = new CalibStereoFilter;
((CalibStereoFilter *) mCalibFilter)->setStereoContext(mStereoContext);
}
else
mCalibFilter = new CalibFilter;
mCalibFilter->setEnabled(lastCalibFilterEnabled);
}
#endif
mSeqFileName = fileName;
SPDLOG_INFO(
"open {} ({} frames; {} fps; {} x {} pixel)",
mSeqFileName,
mAnimation->getNumFrames(),
mAnimation->getFPS(),
mAnimation->getSize().width(),
mAnimation->getSize().height());
updateSequence();
updateWindowTitle();
mPlayerWidget->setFPS(mAnimation->getFPS());
void Petrack::openMoCapFile()
{
OpenMoCapDialog dialog(this, mMoCapController);
dialog.exec();
}