Newer
Older
/*
* PeTrack - Software for tracking pedestrians movement in videos
* Copyright (C) 2022 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() :
mExtrCalibration(mPersonStorage),
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;
if(newerThanVersion(QString("0.9.0"), root.attribute("VERSION")))
{
PWarning(
this,
tr("PeTrack"),
tr("You are using a project version lower than 0.9: Therefore, the extended intrinsic calibration "
"model is disabled."));
mControlWidget->setExtModelChecked(false);
}
else if(newerThanVersion(QString("0.9.2"), root.attribute("VERSION")))
{
// only checking one parameter because if the ext. model is used all parameters are not equal to zero
if(mControlWidget->getCalibS1() == 0.)
{
mControlWidget->setExtModelChecked(false);
}
else
{
mControlWidget->setExtModelChecked(true);
}
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();
}
QSize size = mAnimation->getSize();
if(QFileInfo(mProFileName).isDir())
title = tr("PeTrack (v") + mPetrackVersion + tr("): ");
title = tr("PeTrack (v") + mPetrackVersion + tr("): ") + QFileInfo(mProFileName).fileName();
if(mAnimation->isVideo() || mAnimation->isImageSequence())
title += "sequence: " + mAnimation->getCurrentFileName() + tr(" (%1").arg(mAnimation->getNumFrames()) +
tr(" frames; %1x%2").arg(size.width()).arg(size.height()) + " pixel)";
else if(mAnimation->isImageSequence())
title += "sequence: " + mAnimation->getCurrentFileName() + tr(" ... (%1").arg(mAnimation->getNumFrames()) +
tr(" frames; %1x%2").arg(size.width()).arg(size.height()) + " pixel)";
setWindowTitle(title);
}
void Petrack::saveVideo()
{
saveSequence(true, false);
}
void Petrack::saveVideoView()
{
saveSequence(true, true);
}
void Petrack::saveImageSequence()
{
saveSequence(false, false);
}
void Petrack::saveViewSequence()
{
saveSequence(false, true);
}
/**
* @brief Saves current sequence as avi-file or image sequence
*
* Saves the loaded image sequence or video from current frame on till the end.
* One can save the sequence as is or one can save the view shown in PeTrack.
*
* @param saveVideo true, if wanting to save a video. Ignored when dest isn't empty
* @param saveView true, if sequence should be saved as shown in PeTrack (with trajectories etc.)
* @param dest destination file; if empty, the user chooses via a dialog
*/
void Petrack::saveSequence(bool saveVideo, bool saveView, QString dest) // default saveView= false, dest=""
{
static QString lastDir;
// if no destination file or folder is given
if(lastDir.isEmpty() && !mSeqFileName.isEmpty())
dest = QFileDialog::getSaveFileName(
this,
tr("Select video file"),
lastDir,
tr("Video (*.mp4 *.avi);;All files (*.*)")); //? *.mpg *.mpeg
dest = QFileDialog::getExistingDirectory(
this,
tr("Select directory to save view sequence"),
lastDir,
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
dest = QFileDialog::getExistingDirectory(
this,
tr("Select directory to save image sequence"),
lastDir,
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
auto extension = dest.right(4);
int fourcc = -1;
if(extension == ".mp4")
fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v');
saveVideo = true;
}
else if(extension == ".avi")
{
fourcc = cv::VideoWriter::fourcc('M', 'J', 'P', 'G');
saveVideo = true;
}
else
{
saveVideo = false;
int rest = mAnimation->getNumFrames() - 1;
int numLength = 1;
int memPos = mPlayerWidget->getPos();
QString fileName = "";
bool formatIsSaveAble = false;
bool saveRet;
QPainter *painter = nullptr;
int progEnd = mAnimation->getSourceOutFrameNum() -
mPlayerWidget->getPos(); // nur wenn nicht an anfang gesprungen wird:-mPlayerWidget->getPos()
cv::Mat iplImgFilteredBGR;
bool writeFrameRet = false;
cv::VideoWriter outputVideo;
if(mCropZoomViewAct->isChecked())
viewImage =
new QImage(mView->viewport()->width(), mView->viewport()->height(), QImage::Format_RGB32);
viewImage = new QImage((int) mScene->width(), (int) mScene->height(), QImage::Format_RGB32);
outputVideo = cv::VideoWriter(
dest.toStdString(),
fourcc,
mAnimation->getFPS(),
cv::Size(viewImage->width(), viewImage->height()));
bool colored = (mImg.channels() > 1);
outputVideo = cv::VideoWriter(
dest.toStdString(), fourcc, mAnimation->getFPS(), cv::Size(mImg.cols, mImg.rows), colored);
if(mCropZoomViewAct->isChecked())
viewImage =
new QImage(mView->viewport()->width(), mView->viewport()->height(), QImage::Format_RGB32);
viewImage = new QImage((int) mScene->width(), (int) mScene->height(), QImage::Format_RGB32);
painter = new QPainter();
}
// test, if fileformat is supported
fileName = (dest + "/" + mAnimation->getFileBase() + "%1.png")
.arg(mPlayerWidget->getPos(), numLength, 10, QChar('0'));
if(mCropZoomViewAct->isChecked())
if(viewImage->save(fileName)) //, const char * format = 0 (format wird aus dateinamen geholt), int
// quality = -1 default normal (0..100)
{
formatIsSaveAble = true;
mPlayerWidget->frameForward();
}
}
else if(mImage->save(fileName)) //, const char * format = 0 (format wird aus dateinamen geholt), int quality
//= -1 default normal (0..100)
{
formatIsSaveAble = true;
mPlayerWidget->frameForward();
}
}
else if((mImgFiltered.channels() == 1) /*&& convert8To24bit*/)
size.height = mImgFiltered.rows;
iplImgFilteredBGR.create(size, CV_8UC3);
}
QProgressDialog progress("", "Abort save", 0, progEnd, this);
progress.setWindowModality(Qt::WindowModal); // blocks main window
progress.setValue(
mPlayerWidget->getPos() - memPos); // -mempos nur, wenn nicht an den anfang gesprungen wird
if(mCropZoomViewAct->isChecked())
cv::Mat frame(
viewImage->height(),
viewImage->width(),
CV_8UC4,
(unsigned char *) viewImage->bits(),
viewImage->bytesPerLine());
cv::cvtColor(frame, frame, cv::COLOR_RGBA2RGB); // need for right image interpretation
outputVideo.write(frame);
writeFrameRet = true;
cv::Mat frame = mImg.clone();
outputVideo.write(frame);
writeFrameRet = true;
PCritical(
this,
tr("PeTrack"),
tr("Cannot save %1 maybe because of wrong file extension or unsupported codec.").arg(dest));
break;
}
}
else
{
// single frame sequence
if(mCropZoomViewAct->isChecked())
fileName = (dest + "/" + mAnimation->getFileBase() + "%1.png")
.arg(mPlayerWidget->getPos(), numLength, 10, QChar('0'));
if(saveView)
{
fileName = dest + "/" + mAnimation->getCurrentFileName();
}
else
{
fileName = dest + "/" + QFileInfo(mAnimation->getCurrentFileName()).completeBaseName() + ".png";
saveRet = mImage->save(fileName, "PNG"); //, int quality = -1 default normal (0..100)
PCritical(this, tr("PeTrack"), tr("Cannot save %1.").arg(fileName));
} while(mPlayerWidget->frameForward());
{
delete viewImage;
delete painter;
}
// bei abbruch koennen es auch mPlayerWidget->getPos() frames sein, die bisher geschrieben wurden
//-memPos nur, wenn nicht an den anfang gesprungen wird
SPDLOG_INFO("wrote {} of {} frames.", mPlayerWidget->getPos() + 1 - memPos, mAnimation->getNumFrames());
}
mPlayerWidget->skipToFrame(memPos);
lastDir = dest;
}
}
/**
* @brief Saves the current View, including visualizations, in a file (.g. pdf)
*
* @param dest name of the saved file; if empty, a dialogue for the user opens
*/
void Petrack::saveView(QString dest) // default = ""
{
static QString lastFile;
if(mImage)
{
// if no destination file or folder is given
if(lastFile.isEmpty() && !mSeqFileName.isEmpty())
// alle unetrstuetzen fileformate erhaelt man mit
// QImageReader::supportedImageFormats() and QImageWriter::supportedImageFormats()
// gif muss nicht dabei sein, dazu muss qt mit -qt-gif uebersetzt worden sein
dest = QFileDialog::getSaveFileName(
this,
tr("Select image file"),
lastFile,
tr("PDF (*.pdf);;Postscript (*.ps *.eps);;Windows bitmaps (*.bmp);;JPEG (*.jpeg *.jpg);;Portable "
"network graphics (*.png);;Portable image format (*.pbm *.pgm *.ppm);;X11 Bitmap or Pixmap (*.xbm "
"*.xpm);;Pixel Images (*.bmp *.jpeg *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm);;All supported types "
"(*pdf *ps *.eps *.bmp *.jpeg *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm);;All files (*.*)"));
if(dest.right(4) == ".pdf" || dest.right(3) == ".ps" || dest.right(4) == ".eps")
QPdfWriter pdfWriter(dest);
pdfWriter.setPageMargins({0, 0, 0, 0});
QPageSize pageSize{mImage->size()};
pdfWriter.setPageSize(pageSize);
QPainter painter(&pdfWriter);
if(mCropZoomViewAct->isChecked())
}
else
{
// schwarzer rand links und unten?!
QImage *img;
if(mCropZoomViewAct->isChecked())
img = new QImage(mView->viewport()->width(), mView->viewport()->height(), QImage::Format_RGB32);
img = new QImage((int) mScene->width(), (int) mScene->height(), QImage::Format_RGB32);
if(mCropZoomViewAct->isChecked())
PCritical(
this, tr("PeTrack"), tr("Cannot save %1 maybe because of wrong file extension.").arg(dest));
delete img;
}
lastFile = dest;
}
}
}
void Petrack::saveImage(QString dest) // default = ""
{
static QString lastFile;
if(mImage)
{
// if no destination file or folder is given
if(lastFile.isEmpty() && !mSeqFileName.isEmpty())
// alle unetrstuetzen fileformate erhaelt man mit
// QImageReader::supportedImageFormats() and QImageWriter::supportedImageFormats()
// gif muss nict dabei sein, dazu muss qt mit -qt-gif uebesetz worden sein
dest = QFileDialog::getSaveFileName(
this,
tr("Select image file"),
lastFile,
tr("PDF (*.pdf);;Postscript (*.ps *.eps);;Windows bitmaps (*.bmp);;JPEG (*.jpeg *.jpg);;Portable "
"network graphics (*.png);;Portable image format (*.pbm *.pgm *.ppm);;X11 Bitmap or Pixmap (*.xbm "
"*.xpm);;Pixel Images (*.bmp *.jpeg *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm);;All supported types "
"(*pdf *ps *.eps *.bmp *.jpeg *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm);;All files (*.*)"));
if(dest.right(4) == ".pdf" || dest.right(3) == ".ps" || dest.right(4) == ".eps")
QPdfWriter pdfWriter(dest);
pdfWriter.setPageMargins({0, 0, 0, 0});
QPageSize pageSize{mImage->size()};
pdfWriter.setPageSize(pageSize);
QPainter painter(&pdfWriter);
QRect rect = painter.viewport();
QSize size = mImage->size();
size.scale(rect.size(), Qt::KeepAspectRatio);
painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
painter.setWindow(mImage->rect());
painter.drawImage(0, 0, *mImage);
}
else
{
if(!mImage->save(dest)) //, "PNG"
PCritical(
this, tr("PeTrack"), tr("Cannot save %1 maybe because of wrong file extension.").arg(dest));
}
lastFile = dest;
}
}
}
void Petrack::print()
{
if(mImage)
{
// HighResolution font zu gross! und laengere laufzeit und eher overflow
// aber so pixelig und keine schoenen linien
QPrinter printer(QPrinter::ScreenResolution); // ScreenResolution, HighResolution// liefert zu hause:
// QWin32PrintEngine::initialize: GetPrinter failed ()
printer.setPageSize(QPageSize{QPageSize::PageSizeId::A4});
QPainter painter(&printer);
mView->render(&painter);
}
}
else
PCritical(this, tr("PeTrack"), tr("Nothing to print!"));
}
void Petrack::resetSettings()
{
mAnimation->reset();
openXml(mDefaultSettings, false);
auto about = new AboutDialog(
this,
mPetrackVersion,
mGitCommitID,
mGitCommitDate,
mGitCommitBranch,
mCompilerID,
mCompilerVersion,
mCompileDate,
mAuthors);
about->show();
PMessageBox *mb = new PMessageBox{this, tr("Command line options"), commandLineOptionsString, QIcon()};
mb->setModal(false);
mb->show();
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
QString ctrlSign = (mCompileOS != "Darwin") ? "⌃ Ctrl" : "⌘ Cmd";
QString shiftSign = "⇧ Shift";
QString altSign = (mCompileOS != "Darwin") ? "⎇ Alt" : "⌥ Option";
QString arrowUp = "Arrow up ↑";
QString arrowDown = "Arrow down ↓";
QString arrowLeft = "Arrow left ←";
QString arrowRight = "Arrow right →";
const QString out =
tr("<p>Beside the space bar all bindings only affect inside the image.</p>"
"<dl><dt><kbd>Space bar</kbd></dt><dd>toggles between pause and last play direction</dd>"
"<dt><kbd>Mouse scroll wheel</kbd></dt><dd>zooms in and out to or from the pixel of the image at the "
"position "
"of the mouse pointer</dd>"
"<dt><kbd>%2 + mouse scroll wheel</kbd></dt><dd>plays forwards or backwards frame by frame</dd>"
"<dt><kbd>Holding left mouse button</kbd></dt><dd>moves image</dd>"
"<dt><kbd>%4/%5</kbd></dt><dd>zoom in/out</dd>"
"<dt><kbd>%6/%7</kbd></dt><dd>frame back/forward</dd>"
"<dt><kbd>Double-click left mouse button</kbd></dt><dd>opens video or image sequence</dd>"
"<dt><kbd>%1 + double-click left mouse button</kbd></dt><dd>inserts new or moves near trackpoint</dd>"
"<dt><kbd>%1 + %2 + double-click left mouse button</kbd></dt><dd>splits near trackpoint before current "
"frame</dd>"
"<dt><kbd>%1 + double-click right mouse button</kbd></dt><dd>deletes a trajectory of a near trackpoint</dd>"
"<dt><kbd>%2 + double-click right mouse button</kbd></dt><dd>deletes the past part of a trajectory of a "
"near trackpoint</dd>"
"<dt><kbd>%3 + double-click right mouse button</kbd></dt><dd>deletes the future part of a trajectory of a "
"near trackpoint</dd>"
"<dt><kbd>%1 + double-click middle mouse button</kbd></dt><dd>deletes all trajectories</dd>"
"<dt><kbd>%2 + double-click middle mouse button</kbd></dt><dd>deletes the past part of all trajectories</dd>"
"<dt><kbd>%3 + double-click middle mouse button</kbd></dt><dd>deletes the future part of all "
"trajectories</dd>"
"<dt><kbd>%2 + t</kbd></dt><dd>toggles tracking online calculation</dd>"
"<dt><kbd>%2 + double-click left mouse button</kbd></dt><dd>inserts new or moves near trackpoint and "
"enables showing only the modified trajectory</dd>"
"<dt><kbd>%1 + %3 + double-click left mouse button</kbd></dt><dd>jumps to frame of trackpoint under "
"cursor</dd>"
"<dt><kbd>%3 + holding left mouse button</kbd></dt><dd>moves trackpoint under cursor</dd>"
"<dt><kbd>%1 + e</kbd></dt><dd>export trajectories</dd>"
"<dt><kbd>%1 + mouse scroll wheel</kbd></dt><dd>change the displayed person (if show only people "
"enabled)</dd></dl>"
"<p>Further key bindings you will find next to the entries of the menus.</p>")
.arg(ctrlSign)
.arg(shiftSign)
.arg(altSign)
.arg(arrowUp)
.arg(arrowDown)
.arg(arrowLeft)
.arg(arrowRight);
PMessageBox *mb = new PMessageBox(this, tr("Key Bindings"), out, QIcon());
mb->setModal(false);
mb->show();
}
void Petrack::onlineHelp()
{
static QUrl url("https://jugit.fz-juelich.de/ped-dyn-emp/petrack/-/wikis/home");
if(!(QDesktopServices::openUrl(url)))
PCritical(this, tr("PeTrack"), tr("Cannot open external browser<br>with url ") + url.toString() + "!");
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
}
void Petrack::antialias()
{
mView->setRenderHint(QPainter::Antialiasing, mAntialiasAct->isChecked());
}
void Petrack::opengl()
{
mView->setViewport(mOpenGLAct->isChecked() ? new QGLWidget(QGLFormat(QGL::SampleBuffers)) : new QWidget);
// alten freigeben wegen new????
}
void Petrack::reset()
{
mViewWidget->resetView();
}
void Petrack::fitInView()
{
mViewWidget->fitInView();
}
void Petrack::fitInROI()
{
mViewWidget->fitInROI(getRecoRoiItem()->rect());
// what about trackingRoi???
}
void Petrack::setGlobalFont()
{
this->setFont(font); // font is set to the font the user selected
// the user canceled the dialog; font is set to the initial
// value, in this case Times, 12.
}
}
void Petrack::showHideControlWidget()
{
// show | hide Control
mViewWidget->hideControls(mHideControlsAct->isChecked());
}
void Petrack::setCamera()
{
#ifndef STEREO_DISABLED
if(mCameraLeftViewAct->isChecked())
if((mAnimation->getCamera()) != cameraLeft)
mAnimation->setCamera(cameraLeft); // war: hier wird direkt bei Umstellung neu gelesen
else
return;
}
else if(mCameraRightViewAct->isChecked())
if((mAnimation->getCamera()) != cameraRight)
mAnimation->setCamera(cameraRight); // war: hier wird direkt bei Umstellung neu gelesen
else
return;
}
else // kann eigentlich nicht vorkommen
{
mAnimation->setCamera(cameraUnset);
return;
}
updateImage(mAnimation->getFrameAtIndex(
mAnimation->getCurrentFrameNum())); // wird nur aufgerufen, wenn left / right sich geaendert hat
// mPlayerWidget->updateImage();
// mPlayerWidget->skipToFrame(mPlayerWidget->getPos()); // machtpasue!!
// updateImage(true); // nur dies aufrufen, wenn nicht links rechts gleichzeitig gehalten wird
/**
* @brief Helper function to create Actions for the menu bar
* @see Petrack::createMenus()
*/
void Petrack::createActions()
{
mOpenSeqAct = new QAction(tr("&Open Sequence"), this);
mOpenSeqAct->setShortcut(tr("Ctrl+Shift+O"));
connect(mOpenSeqAct, SIGNAL(triggered()), this, SLOT(openSequence()));
mOpenCameraAct = new QAction(tr("Open Camera Stream"), this);
// mOpenCameraAct->setShortcut(tr("Ctrl+C")); // because of some reason it is sometimes fired with
// Ctrl+LeftMouseButton ==> so disabled (it's also not really needed)
connect(mOpenCameraAct, SIGNAL(triggered()), this, SLOT(openCameraLiveStream()));
mOpenMoCapAct = new QAction(tr("Manage MoCap Files"), this);
connect(mOpenMoCapAct, &QAction::triggered, this, &Petrack::openMoCapFile);
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
mSaveSeqVidAct = new QAction(tr("Save Video"), this);
mSaveSeqVidAct->setEnabled(false);
connect(mSaveSeqVidAct, SIGNAL(triggered()), this, SLOT(saveVideo()));
mSaveSeqVidViewAct = new QAction(tr("Save Video View"), this);
mSaveSeqVidViewAct->setEnabled(false);
connect(mSaveSeqVidViewAct, SIGNAL(triggered()), this, SLOT(saveVideoView()));
mSaveSeqImgAct = new QAction(tr("Save Image S&equence"), this);
mSaveSeqImgAct->setShortcut(tr("Ctrl+F"));
mSaveSeqImgAct->setEnabled(false);
connect(mSaveSeqImgAct, SIGNAL(triggered()), this, SLOT(saveImageSequence()));
mSaveSeqViewAct = new QAction(tr("Save View S&equence"), this);
// mSaveSeqViewAct->setShortcut(tr("Ctrl+F"));
mSaveSeqViewAct->setEnabled(false);
connect(mSaveSeqViewAct, SIGNAL(triggered()), this, SLOT(saveViewSequence()));
mOpenPrAct = new QAction(tr("&Open Project"), this);
mOpenPrAct->setShortcut(tr("Ctrl+O"));
connect(mOpenPrAct, SIGNAL(triggered()), this, SLOT(openProject()));
mSavePrAct = new QAction(tr("&Save Project As"), this);
mSavePrAct->setShortcut(tr("Ctrl+Shift+S"));
connect(mSavePrAct, &QAction::triggered, this, &Petrack::saveProjectAs);
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
mSaveAct = new QAction(tr("&Save Project"), this);
mSaveAct->setShortcut(tr("Ctrl+S"));
connect(mSaveAct, SIGNAL(triggered()), this, SLOT(saveSameProject()));
mSaveImageAct = new QAction(tr("&Save Image"), this);
mSaveImageAct->setShortcut(tr("Ctrl+I"));
mSaveImageAct->setEnabled(false);
connect(mSaveImageAct, SIGNAL(triggered()), this, SLOT(saveImage()));
mSaveViewAct = new QAction(tr("&Save View"), this);
mSaveViewAct->setShortcut(tr("Ctrl+V"));
mSaveViewAct->setEnabled(false);
connect(mSaveViewAct, SIGNAL(triggered()), this, SLOT(saveView()));
mPrintAct = new QAction(tr("&Print"), this);
mPrintAct->setShortcut(tr("Ctrl+P"));
mPrintAct->setEnabled(false);
connect(mPrintAct, SIGNAL(triggered()), this, SLOT(print()));
mResetSettingsAct = new QAction(tr("&Reset Settings"), this);
// mResetSettingsAct->setShortcut(tr("Ctrl+R"));
mResetSettingsAct->setEnabled(false); // da es noch nicht fehlerfrei funktioniert
connect(mResetSettingsAct, SIGNAL(triggered()), this, SLOT(resetSettings()));
mExitAct = new QAction(tr("E&xit"), this);
mExitAct->setShortcut(tr("Ctrl+Q"));
connect(mExitAct, SIGNAL(triggered()), this, SLOT(close()));
mAntialiasAct = new QAction(tr("&Antialias"), this);
mAntialiasAct->setShortcut(tr("Ctrl+A"));
mAntialiasAct->setCheckable(true);
connect(mAntialiasAct, SIGNAL(triggered()), this, SLOT(antialias()));
mFontAct = new QAction(tr("&Font"), this);
connect(mFontAct, SIGNAL(triggered()), this, SLOT(setGlobalFont()));
mHideControlsAct = new QAction(tr("&Hide controls"), this);
mHideControlsAct->setShortcut(tr("Ctrl+H"));
mHideControlsAct->setCheckable(true);
connect(mHideControlsAct, SIGNAL(triggered()), this, SLOT(showHideControlWidget()));
connect(mHideControlsAct, SIGNAL(changed()), this, SLOT(showHideControlWidget()));
mCropZoomViewAct = new QAction(tr("&Transform while saving"), this); // Crop and zoom while saving
mCropZoomViewAct->setCheckable(true);
mOpenGLAct = new QAction(tr("Open&GL"), this);
mOpenGLAct->setShortcut(tr("Ctrl+G"));
mOpenGLAct->setCheckable(true);
connect(mOpenGLAct, SIGNAL(triggered()), this, SLOT(opengl()));
mResetAct = new QAction(tr("&Reset"), this);
mResetAct->setShortcut(tr("Ctrl+R"));
connect(mResetAct, SIGNAL(triggered()), this, SLOT(reset()));
mFitViewAct =
new QAction(tr("Fit in window"), this); // Resize to window; fit in view; show all; in fenster einpassen
mFitViewAct->setShortcut(tr("Ctrl+0"));
connect(mFitViewAct, SIGNAL(triggered()), this, SLOT(fitInView()));
mFitROIAct = new QAction(tr("Fit in region of interest"), this); // Resize ROI to window; fit in view;
mFitROIAct->setShortcut(tr("Ctrl+1"));
connect(mFitROIAct, SIGNAL(triggered()), this, SLOT(fitInROI()));
mCameraGroupView = new QActionGroup(this);
// mCameraGroupView->addAction(mCameraLeftViewAct);
// mCameraGroupView->addAction(mCameraRightViewAct);
mCameraLeftViewAct = new QAction(tr("&Left"), mCameraGroupView);
mCameraLeftViewAct->setShortcut(tr("Ctrl++Shift+L"));
mCameraLeftViewAct->setCheckable(true);
connect(mCameraLeftViewAct, SIGNAL(triggered()), this, SLOT(setCamera()));
mCameraRightViewAct = new QAction(tr("&Right"), mCameraGroupView);
mCameraRightViewAct->setShortcut(tr("Ctrl++Shift+R"));
mCameraRightViewAct->setCheckable(true);
connect(mCameraRightViewAct, SIGNAL(triggered()), this, SLOT(setCamera()));
mCameraRightViewAct->setChecked(true); // right wird als default genommen, da reference image in triclops auch right
// ist // erste trj wurden mit left gerechnet
mLimitPlaybackSpeed = new QAction(tr("&Limit playback speed"));
// Not checkable like Fix since this is also controlled through clicking on FPS and syncing currently would be
// bothersome
connect(
mLimitPlaybackSpeed,
&QAction::triggered,
mPlayerWidget,
[&]() { mPlayerWidget->setPlayerSpeedLimited(!mPlayerWidget->getPlayerSpeedLimited()); });
mFixPlaybackSpeed = new QAction(tr("&Fix playback speed"));
mFixPlaybackSpeed->setCheckable(true);
connect(mFixPlaybackSpeed, &QAction::toggled, mPlayerWidget, &Player::setPlayerSpeedFixed);
mSetToRealtime = new QAction(tr("&Realtime"));
connect(
mSetToRealtime, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(1.0); });
connect(mSetTo2p00, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(2.0); });
connect(mSetTo1p75, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(1.75); });
connect(mSetTo1p50, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(1.5); });
connect(mSetTo1p25, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(1.25); });
connect(mSetTo0p75, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(0.75); });
connect(mSetTo0p50, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(0.5); });
connect(mSetTo0p25, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(0.25); });
mPlayerLooping = new QAction(tr("&Loop"));
mPlayerLooping->setCheckable(true);
connect(mPlayerLooping, &QAction::triggered, mPlayerWidget, &Player::setLooping);
// -------------------------------------------------------------------------------------------------------
mDelPastAct = new QAction(tr("&Past part of all trj."), this);
connect(
mDelPastAct,
&QAction::triggered,
this,
[this]() { this->deleteTrackPointAll(PersonStorage::Direction::Previous); });
mDelFutureAct = new QAction(tr("&Future part of all trj."), this);
connect(
mDelFutureAct,
&QAction::triggered,
this,
[this]() { this->deleteTrackPointAll(PersonStorage::Direction::Following); });
mDelAllRoiAct = new QAction(tr("&Trj. moving through ROI"), this);
connect(mDelAllRoiAct, &QAction::triggered, this, &Petrack::deleteTrackPointROI);
mDelPartRoiAct = new QAction(tr("Part of Trj. inside &ROI"), this);
connect(mDelPartRoiAct, &QAction::triggered, this, &Petrack::deleteTrackPointInsideROI);
// -------------------------------------------------------------------------------------------------------
mCommandAct = new QAction(tr("&Command line options"), this);
connect(mCommandAct, SIGNAL(triggered()), this, SLOT(commandLineOptions()));
mKeyAct = new QAction(tr("&Key bindings"), this);
connect(mKeyAct, SIGNAL(triggered()), this, SLOT(keyBindings()));
mAboutAct = new QAction(tr("&About"), this);
connect(mAboutAct, SIGNAL(triggered()), this, SLOT(about()));
mOnlineHelpAct = new QAction(tr("Online &Help"), this);
mOnlineHelpAct->setShortcut(tr("Ctrl+H"));
connect(mOnlineHelpAct, SIGNAL(triggered()), this, SLOT(onlineHelp()));
}
/**
* @brief Helper function building menues out of QActions
* @see Petrack::createActions()
*/
void Petrack::createMenus()
{
mFileMenu = new QMenu(tr("&File"), this);
mFileMenu->addAction(mOpenPrAct);
mFileMenu->addAction(mSaveAct);
mFileMenu->addAction(mSavePrAct);
mFileMenu->addSeparator();
mFileMenu->addAction(mOpenSeqAct);
mFileMenu->addAction(mOpenCameraAct);
mFileMenu->addAction(mSaveSeqVidAct);
mFileMenu->addAction(mSaveSeqVidViewAct);
mFileMenu->addAction(mSaveImageAct);
mFileMenu->addAction(mSaveSeqImgAct);
mFileMenu->addAction(mSaveViewAct);
mFileMenu->addAction(mSaveSeqViewAct);
mFileMenu->addAction(mPrintAct);
mFileMenu->addSeparator();
mFileMenu->addAction(mResetSettingsAct);
mFileMenu->addSeparator();
mFileMenu->addAction(mExitAct);
mViewMenu = new QMenu(tr("&View"), this);
mViewMenu->addAction(mAntialiasAct);
mViewMenu->addAction(mOpenGLAct);
mViewMenu->addAction(mCropZoomViewAct);
mCameraMenu = mViewMenu->addMenu(tr("&Camera"));
mCameraMenu->addAction(mCameraLeftViewAct);
mCameraMenu->addAction(mCameraRightViewAct);
mViewMenu->addAction(mFixPlaybackSpeed);
mViewMenu->addAction(mLimitPlaybackSpeed);
mPlaybackSpeedMenu = mViewMenu->addMenu(tr("&Playback speed"));
mPlaybackSpeedMenu->addAction(mSetToRealtime);
mPlaybackSpeedMenu->addAction(mSetTo2p00);
mPlaybackSpeedMenu->addAction(mSetTo1p75);
mPlaybackSpeedMenu->addAction(mSetTo1p50);
mPlaybackSpeedMenu->addAction(mSetTo1p25);
mPlaybackSpeedMenu->addAction(mSetTo0p75);
mPlaybackSpeedMenu->addAction(mSetTo0p50);
mPlaybackSpeedMenu->addAction(mSetTo0p25);
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
mViewMenu->addSeparator();
mViewMenu->addAction(mFitViewAct);
mViewMenu->addAction(mFitROIAct);
mViewMenu->addAction(mResetAct);
mViewMenu->addSeparator();
mViewMenu->addAction(mFontAct);
mViewMenu->addSeparator();
mViewMenu->addAction(mHideControlsAct);
mDeleteMenu = new QMenu(tr("&Delete"), this);
mDeleteMenu->addAction(mDelPastAct);
mDeleteMenu->addAction(mDelFutureAct);
mDeleteMenu->addAction(mDelAllRoiAct);
mDeleteMenu->addAction(mDelPartRoiAct);
mHelpMenu = new QMenu(tr("&Help"), this);
mHelpMenu->addAction(mCommandAct);
mHelpMenu->addAction(mKeyAct);
mHelpMenu->addAction(mAboutAct);
mHelpMenu->addAction(mOnlineHelpAct);
menuBar()->addMenu(mFileMenu);
menuBar()->addMenu(mViewMenu);
menuBar()->addMenu(mDeleteMenu);
menuBar()->addMenu(mHelpMenu);
mCameraMenu->setEnabled(false);
}
/**
* @brief Helper function to create status bar at the bottom of the window
*/
QFont f("Courier", 12, QFont::Bold); // Times Helvetica, Normal
statusBar()->setMaximumHeight(28);
statusBar()->showMessage(tr("Ready"));
statusBar()->addPermanentWidget(mStatusLabelStereo = new QLabel(" "));
statusBar()->addPermanentWidget(mStatusLabelTime = new QLabel(" "));
statusBar()->addPermanentWidget(mStatusLabelFPS = new QLabel(" "));
statusBar()->addPermanentWidget(mStatusPosRealHeight = new QDoubleSpinBox());
connect(mStatusPosRealHeight, SIGNAL(valueChanged(double)), this, SLOT(setStatusPosReal()));
statusBar()->addPermanentWidget(mStatusLabelPosReal = new QLabel(" "));
statusBar()->addPermanentWidget(mStatusLabelPos = new QLabel(" "));
statusBar()->addPermanentWidget(mStatusLabelColor = new QLabel(" "));
mStatusLabelStereo->setFont(f);
mStatusLabelStereo->setMinimumWidth(200);
mStatusLabelTime->setFont(f);
mStatusLabelTime->setMinimumWidth(200);
mStatusLabelFPS->setFont(f);
mStatusLabelFPS->setMinimumWidth(80);
mStatusLabelFPS->setAutoFillBackground(true);
mStatusLabelFPS->setToolTip("Click to adapt play rate to fps rate");
mStatusPosRealHeight->setRange(-999.9, 9999.9); // in cm
mStatusPosRealHeight->setDecimals(1);
mStatusPosRealHeight->setFont(f);
mStatusLabelPosReal->setFont(f);
mStatusLabelPosReal->setMinimumWidth(340);
mStatusLabelPos->setFont(f);
mStatusLabelPos->setMinimumWidth(100);
mStatusLabelColor->setFont(f);
mStatusLabelColor->setMinimumWidth(90);
mStatusLabelColor->setAutoFillBackground(true);
}
void Petrack::resetUI()
{
/// Reset all UI elements to default settings
/// Noetig damit alle UI Elemente, welche in der neu geladenen Projekt-Datei z.B. noch nicht vorhanden sind, auf
/// sinnvolle Werte gesetzt werden. Anderenfalls kommt es evtl. beim nacheinander laden verschiedener Projekte zu
/// einem Programmabsturz
///
return;
}
void Petrack::setStatusStereo(float x, float y, float z)
{
mStatusLabelStereo->setText(QString("x= novalue y= novalue z= novalue "));
mStatusLabelStereo->setText(
QString("x=%1cm y=%2cm z=%3cm ").arg(x, 6, 'f', 1).arg(y, 6, 'f', 1).arg(z, 6, 'f', 1));
{
mStatusLabelFPS->setText(QString("%1fps ").arg(mShowFPS, 5, 'f', 1));
QPalette pal = mStatusLabelFPS->palette(); // static moeglich?
double diff = mShowFPS - mAnimation->getFPS();
int opacity = mPlayerWidget->getPlayerSpeedLimited() ? 128 : 20;
if(diff < -6) // very slow ==> red
color.setRgb(200, 0, 0, opacity);
else if(diff < -2) // better ==> yellow
color.setRgb(200, 200, 0, opacity);
else if(diff > -2) // nearly ok ==> green
color.setRgb(0, 200, 0, opacity);
pal.setColor(QPalette::Window, color);
mStatusLabelFPS->setPalette(pal);
}
}
void Petrack::setShowFPS(double fps)
{
if((fps == 0.) || (mShowFPS == 0))
mShowFPS = mShowFPS * .9 + fps * .1; // glaetten durch Hinzunahme des alten Wertes
/**
* @brief Updates the FPS shown to the User
*
* This method calculates the FPS by remembering how long
* it has been since it was called last time. If skipped is
* true, it doesn't directly update the FPS since 2
* skipped frames have essentially a time delay of 0 between
* them, which would make calculations wonky.
*
* @param skipped True, if this is a skipped frame; default false
*/
void Petrack::updateShowFPS(bool skipped)
{
static QElapsedTimer lastTime;
lastTime.invalidate();
int numFrames = skippedFrames > 0 ? skippedFrames + 1 : 1;
setShowFPS(numFrames * 1000. / lastTime.elapsed());
}
}
lastTime.start();
}
}
// ohne neue positionsangabe, sinnvoll, wenn berechnungsweise sich in getPosReal geaendert hat
// gebraucht in control.cpp
void Petrack::setStatusPosReal() // pos in cm
{
setStatusPosReal(mImageItem->getPosReal(mMousePosOnImage, getStatusPosRealHeight()));
void Petrack::setStatusPosReal(const QPointF &pos) // pos in cm
{
QChar deg(0xB0);
QString labelText = QString(" cm from ground:%1cm,%2cm,%3")
.arg(pos.x(), 6, 'f', 1)
.arg(pos.y(), 6, 'f', 1)
Loading
Loading full blame...