Newer
Older
/*
* PeTrack - Software for tracking pedestrians movement in videos
* Copyright (C) 2010-2020 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 <QtWidgets>
#include <QtOpenGL>
#include <QSignalMapper>
// Added for Qt5 support
#include <QtPrintSupport/QPrinter>
#include <QtPrintSupport/QPrintDialog>
#include "stereoItem.h"
#include "stereoWidget.h"
#include "colorMarkerItem.h"
#include "multiColorMarkerItem.h"
#include "colorRangeWidget.h"
#include "colorMarkerWidget.h"
#include "codeMarkerWidget.h"
#include "multiColorMarkerWidget.h"
#include "petrack.h"
#include "control.h"
#include "view.h"
#include "gridItem.h"
#include "imageItem.h"
#include "logoItem.h"
#include "animation.h"
#include "player.h"
#include "calibFilter.h"
#include "autoCalib.h"
#include "trackerItem.h"
#include "backgroundItem.h"
#include "pMessageBox.h"
#include "trackingRoiItem.h"
#include "recognitionRoiItem.h"
#ifdef AVI
#include "aviFile.h"
#else
#include "aviFileWriter.h"
#endif
#include "person.h"
//temp muss spaeter herausgenommen werden,
// dient dazu, in anderen dateien um schnell ueber cw->temp1->value() an einstellbare daten zu kommen
Control *cw;
int Petrack::trcVersion = 0;
// Reihenfolge des anlegens der objekte ist sehr wichtig
Petrack::Petrack() : mAuthors(IO::readAuthors(QCoreApplication::applicationDirPath()+ "/.zenodo.json"))
{
QIcon icon;
icon.addFile(":/icon"); // about
icon.addFile(":/icon_smallest"); // window title bar
mScene = nullptr;
mTracker = nullptr;
mTrackerReal = nullptr; // damit beim zeichnen von control mit analysePlot nicht auf einen feheler laeuft
mStatusLabelFPS = nullptr;
mStatusPosRealHeight = nullptr;
mStatusLabelPosReal = nullptr;
mImageItem = nullptr;
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
mScene = new QGraphicsScene(this);
mControlWidget = new Control(*this, *mScene, mReco);
cw = mControlWidget; // muss spaeter geloescht werden
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
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);
mTrackingRoiItem = new TrackingRoiItem(this);
mTrackingRoiItem->setZValue(4); // groesser heisst weiter oben
mRecognitionRoiItem = new RecognitionRoiItem(this);
mRecognitionRoiItem->setZValue(5); // groesser heisst weiter oben
mViewWidget = new ViewWidget(this);
mView = mViewWidget->view();
mView->setScene(mScene);
connect(mView, SIGNAL(mouseDoubleClick()), this, SLOT(openSequence()));
connect(mView, SIGNAL(mouseShiftDoubleClick(QPointF)), this, SLOT(addManualTrackPointOnlyVisible(QPointF))); //const QPoint &pos funktionierte nicht
connect(mView, SIGNAL(mouseShiftControlDoubleClick(QPointF)), this, SLOT(splitTrackPerson(QPointF))); //const QPoint &pos funktionierte nicht
connect(mView, SIGNAL(mouseControlDoubleClick(QPointF)), this, SLOT(addOrMoveManualTrackPoint(QPointF))); //const QPoint &pos funktionierte nicht
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
connect(mView, SIGNAL(mouseRightDoubleClick(QPointF, int)), this, SLOT(deleteTrackPoint(QPointF, int))); //const QPoint &pos funktionierte nicht
connect(mView, SIGNAL(mouseMiddleDoubleClick(int)), this, SLOT(deleteTrackPointAll(int))); //const QPoint &pos funktionierte nicht
connect(mView, SIGNAL(mouseShiftWheel(int)), this, SLOT(skipToFrameWheel(int)));
mPlayerWidget = new Player(mAnimation, this);
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->setSpacing(space);
vLayout->addWidget(mViewWidget);
vLayout->addWidget(mPlayerWidget);
//---------------------------
mTracker = new Tracker(this);
mTrackerReal = new TrackerReal(this);
mTrackerItem = new TrackerItem(this, mTracker);
mTrackerItem->setZValue(5); // groesser heisst weiter oben
mControlWidget->getColorPlot()->setTracker(mTracker);
#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();
// TODO delete once we get Options to be value only (i.e. no Pointer/Ref anymore)
mReco.getCodeMarkerOptions().setControlWidget(mControlWidget);
mReco.getCodeMarkerOptions().setCodeMarkerItem(mCodeMarkerItem);
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
mSeqFileName = QDir::currentPath(); //fuer allerersten Aufruf des Programms
readSettings();
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;
delete cw;
// 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)
{
if (event->mimeData()->hasUrls())
event->acceptProposedAction();
}
/**
* @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
*/
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
void Petrack::dropEvent(QDropEvent *event)
{
if (event->mimeData()->hasUrls())
{
if (event->mimeData()->urls().first().toLocalFile().right(4) == ".pet")
openProject(event->mimeData()->urls().first().toLocalFile());
else if (event->mimeData()->urls().first().toLocalFile().right(4) == ".trc")
importTracker(event->mimeData()->urls().first().toLocalFile());
else
openSequence(event->mimeData()->urls().first().toLocalFile());
event->acceptProposedAction();
}
}
void Petrack::updateSceneRect()
{
double iW=0, iH=0, bS=0;
if (mImage)
{
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);
}
else
mScene->setSceneRect(-bS, -bS, iW, iH);
}
/**
* @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
*/
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
void Petrack::openXml(QDomDocument &doc, bool openSeq)
{
QDomElement root = doc.firstChildElement("PETRACK");
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.tagName() == "MAIN")
{
if (elem.hasAttribute("SRC"))
{
seq = elem.attribute("SRC");
QString tmpSeq = getExistingFile(seq, mProFileName);
if (tmpSeq != "")
seq = tmpSeq;
}
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")
{
mStereoWidget->getXml(elem);
}
else if (elem.tagName() == "COLOR_MARKER")
{
mColorMarkerWidget->getXml(elem);
}
else if (elem.tagName() == "CODE_MARKER")
{
mCodeMarkerWidget->getXml(elem);
}
else if (elem.tagName() == "MULTI_COLOR_MARKER")
{
mMultiColorMarkerWidget->getXml(elem);
}
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"))
onlyPeopleNr = tmpElem.attribute("ONLY_PEOPLE_NR").toInt();
if (tmpElem.hasAttribute("ONLY_PEOPLE_NR_LIST"))
onlyPeopleNrList = tmpElem.attribute("ONLY_PEOPLE_NR_LIST");
}
else if (elem.tagName() == "EXTR_CALIBRATION")
{
mExtrCalibration.getXml(elem);
}
else if (elem.tagName() == "PLAYER")
{
if (elem.hasAttribute("FRAME"))
{
frame = elem.attribute("FRAME").toInt();
}
if (elem.hasAttribute("FPS"))
{
fps = elem.attribute("FPS").toDouble();
}
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);
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;
}
if (elem.hasAttribute("CAMERA"))
{
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
debout << "Unknown PETRACK tag " << elem.tagName() << std::endl;
}
// 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!
if (openSeq && (seq != ""))
openSequence(seq); // wenn leer, dann kommt abfrage hoch, welche datei; abbrechen, wenn aktuelle gewuenscht
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())))
debout << "Error: loading background file " << mBackgroundFilter.getFilename() << "!" << std::endl;
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
}
mPlayerWidget->setFrameInNum( sourceFrameIn == -1 ? mAnimation->getSourceInFrameNum() : sourceFrameIn );
mPlayerWidget->setFrameOutNum( sourceFrameOut == -1 ? mAnimation->getSourceOutFrameNum() : sourceFrameOut );
mPlayerWidget->update();
if (frame != -1)
{
if (mControlWidget->filterBg->isChecked() && !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
}
else if (loaded)
updateImage();
// nicht schon in control, sonst loescht opensequence wieder tracker
if (mTrcFileName != "")
{
// 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 ((mTracker->largestLastFrame() >= frame) && (mTracker->smallestFirstFrame() <= frame))
{
mTracker->clear();
mTracker->reset();
}
importTracker(mTrcFileName);
}
mControlWidget->trackShowOnlyNr->setValue(onlyPeopleNr);
mControlWidget->trackShowOnlyNrList->setText(onlyPeopleNrList);
if (cam == cameraLeft)
mCameraLeftViewAct->setChecked(true);
else if (cam == cameraRight)
mCameraRightViewAct->setChecked(true);
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
if (!maybeSave())
return;
// if no destination file or folder is given
if (fileName.isEmpty())
fileName = QFileDialog::getOpenFileName(this, tr("Select project file"), QFileInfo(mProFileName).path(),
tr("PeTrack project file (*.pet);;All files (*.*)"));
if (!fileName.isEmpty())
{
QFile file(fileName);
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
if (!doc.setContent(&file))
{
PCritical(this, tr("PeTrack"), tr("Cannot read content from %1.").arg(fileName));
debout << "open " << fileName << std::endl;
QDomElement root = doc.firstChildElement("PETRACK");
if (root.hasAttribute("VERSION"))
{
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")));
openXml(doc, openSeq);
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 = "";
if (mImage)
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);
}
/// rueckgabewert zeigt an, ob gesichert werden konnte
bool Petrack::saveSameProject()
{
return saveProject(mProFileName);
}
/// 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 (*.*)"));
}
if (!fileName.isEmpty())
{
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);
debout << "save project to " << fileName << std::endl;
updateWindowTitle();
return true;
}
else
return false;
}
void Petrack::writeXmlElement(QXmlStreamWriter& xmlStream, QDomElement element)
{
xmlStream.writeStartElement(element.tagName());
QVector<QString> attribute_names;
const QDomNamedNodeMap attributes = element.attributes();
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()){
const QDomNodeList children = element.childNodes();
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*/)
{
if (camID == -1)
{
// if more than one camera connected show to choose
//camID = selectedID;
debout << "No camera ID delivered: Set CameraID to 0 (default Camera)" << std::endl;
camID = 0; // default
}
if (!mAnimation->openCameraStream(camID))
{
PCritical(this, tr("PeTrack"), tr("Cannot start Camera Livestream."));
debout << "open " << mSeqFileName << " (" << mAnimation->getNumFrames() << " frames; " << mAnimation->getFPS() << " fps; " << mAnimation->getSize().width() << "x" << mAnimation->getSize().height() << " pixel)" << std::endl; //size
updateSequence();
updateWindowTitle();
mPlayerWidget->setFPS(mAnimation->getFPS());
if (mOpenGLAct->isChecked())
mLogoItem->fadeOut(1);
else
mLogoItem->fadeOut(50);
updateCoord();
}
void Petrack::openSequence(QString fileName) // default fileName = ""
{
if (fileName.isEmpty())
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 (!fileName.isEmpty())
{
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
if (mAnimation->isStereoVideo())
{
if (mStereoContext)
delete mStereoContext;
mStereoContext = new pet::StereoContext(this);
}
bool lastIsStereoVideo = mAnimation->isStereoVideo();
if (mCalibFilter == NULL || (mAnimation->isStereoVideo() != lastIsStereoVideo))
{
bool lastCalibFilterEnabled = false;
if (mCalibFilter != NULL)
{
lastCalibFilterEnabled = mCalibFilter->getEnabled();
delete mCalibFilter;
}
if (mAnimation->isStereoVideo())
{
mCalibFilter = new CalibStereoFilter;
((CalibStereoFilter *) mCalibFilter)->setStereoContext(mStereoContext);
}
else
mCalibFilter = new CalibFilter;
mCalibFilter->setEnabled(lastCalibFilterEnabled);
}
#endif
mSeqFileName = fileName;
debout << "open " << mSeqFileName << " (" << mAnimation->getNumFrames() << " frames; " << mAnimation->getFPS() << " fps; " << mAnimation->getSize().width() << "x" << mAnimation->getSize().height() << " pixel)" << std::endl; //size
updateSequence();
updateWindowTitle();
mPlayerWidget->setFPS(mAnimation->getFPS());
if (mOpenGLAct->isChecked())
mLogoItem->fadeOut(1);
else
mLogoItem->fadeOut(50);
updateCoord();
}
}
void Petrack::openMoCapFile(){
OpenMoCapDialog dialog(this, mMoCapController);
dialog.exec();
}
void Petrack::updateWindowTitle()
{
QString title;
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 += "; ";
}
if (mAnimation->isVideo())
title += "sequence: " + mAnimation->getCurrentFileName() + tr(" (%1").arg(mAnimation->getNumFrames()) + tr(" frames; %1x%2").arg(size.width()).arg(size.height()) + " pixel)";
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;
// bool autoSave = false;
// if no destination file or folder is given
if (dest.isEmpty())
{
if (lastDir.isEmpty() && !mSeqFileName.isEmpty())
lastDir = QFileInfo(mSeqFileName).path();
if (saveVideo)
{
dest = QFileDialog::getSaveFileName(this, tr("Select video file"), lastDir,
tr("Video (*.avi);;All files (*.*)")); //? *.mpg *.mpeg
}
else
{
if (saveView)
dest = QFileDialog::getExistingDirectory(this, tr("Select directory to save view sequence"),
lastDir, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
else
dest = QFileDialog::getExistingDirectory(this, tr("Select directory to save image sequence"),
lastDir, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
}
}
else // uebergabe von saveVideo spielt keine roll mehr, sondern wird hier analysiert anhand von Dateiendung
{
// autoSave = true; // command line option
if (dest.right(4) == ".avi")
saveVideo = true;
else
saveVideo = false;
}
if (!dest.isEmpty() && mImage)
{
int rest = mAnimation->getNumFrames()-1;
int numLength = 1;
int memPos = mPlayerWidget->getPos();
QString fileName = "";
#ifdef AVI
AviFile aviFile;
#else
AviFileWriter aviFile;
#endif
bool formatIsSaveAble = false;
bool saveRet;
QImage *viewImage = nullptr;
QPainter *painter = nullptr;
int progEnd = mAnimation->getSourceOutFrameNum()-mPlayerWidget->getPos(); // nur wenn nicht an anfang gesprungen wird:-mPlayerWidget->getPos()
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
bool writeFrameRet = false;
bool convert8To24bit = false;
int mult;
if (saveVideo)
{
if (saveView)
{
if (mCropZoomViewAct->isChecked())
viewImage = new QImage(mView->viewport()->width(), mView->viewport()->height(), QImage::Format_RGB32);
else
viewImage = new QImage((int) mScene->width(), (int) mScene->height(), QImage::Format_RGB32);
painter = new QPainter();
}
if (convert8To24bit)
mult = 3;
else
mult = 1;
bool ok = false;
if( saveView )
ok = aviFile.open(dest.toStdString().c_str(), viewImage->width(), viewImage->height(), viewImage->depth(), mAnimation->getFPS());
else
ok = aviFile.open(dest.toStdString().c_str(), mImg.cols, mImg.rows, mult*8*mImg.channels(), mAnimation->getFPS());
debout << "Error: opening AVI file: " << dest.toStdString().c_str() << std::endl;