Skip to content
Snippets Groups Projects
petrack.cpp 180 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * 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>
    
    d.kilic's avatar
    d.kilic committed
    #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 "recognition.h"
    #include "trackerItem.h"
    #include "backgroundItem.h"
    #include "tracker.h"
    #include "trackerReal.h"
    #include "cmath"
    #ifdef AVI
    #include "aviFile.h"
    #else
    #include "aviFileWriter.h"
    #endif
    #include "person.h"
    
    #include <time.h>
    
    #include <cstdlib>
    
    #include <iomanip>
    
    
    #include "opencv2/opencv.hpp"
    
    d.kilic's avatar
    d.kilic committed
    // Zeitausgabe aktivieren
    //#define TIME_MEASUREMENT
    
    //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;
    
    using namespace::cv;
    
    using namespace std;
    
    d.kilic's avatar
    d.kilic committed
    
    // Reihenfolge des anlegens der objekte ist sehr wichtig
    Petrack::Petrack()
    {
        QIcon icon;
        icon.addFile(":/icon"); // about
        //     icon.addFile(":/icon_small");
        //     icon.addFile(":/icon_smaller");
        icon.addFile(":/icon_smallest"); // window title bar
        setWindowIcon(icon); // QIcon(":/icon")fuer about und icon in windows titel bar top left
        mHeadSize = -1;
        mCmPerPixel = -1;
        mScene = NULL;
        mTracker = NULL;
        mTrackerReal = NULL; // damit beim zeichnen von control mit analysePlot nicht auf einen feheler laeuft
        mStatusLabelFPS = NULL;
        mStatusPosRealHeight = NULL;
        mStatusLabelPosReal = NULL;
        mImageItem = NULL;
        mRecognitionChanged = true;
        mTrackChanged = true;
        mCoordItem = NULL;
        mImage = NULL;
    //    mIplImg = NULL;
    //    mIplImgFiltered = NULL;
        setLoading(true);
        //     mPrevIplImgFiltered = NULL;
        //     mPrevFrame = -1;
    
        setAcceptDrops(true);
    
    //    grabKeyboard(); // nimmt alle Keyboard Eingaben entgegen, eintragen in Text-Felder dann nicht mehr moeglich
    //    grabMouse(); // nimmt alle MouseEvents eintgegen, Doppelklick etc. dann nicht mehr moeglich
    
        int space = 2;
        //    setAccessibleName("PeTrack");
    
        mBrightContrastFilter.disable();
        //     mContrastFilter.disable();
        //     mBrightFilter.disable();
        mBorderFilter.disable();
        mSwapFilter.disable();
        mBackgroundFilter.disable();
        mStereoContext = NULL;
        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
        //mCalibFilter.disable(); //enable();
    
        //mImageBorderSize=0;
    
        mControlWidget = new Control(this);
        mControlWidget->setFixedWidth(mControlWidget->geometry().width());
        mControlWidget->setMinimumHeight(mControlWidget->geometry().height());
        mControlWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
        //setFixedSize(mControlWidget->geometry().width(),mControlWidget->geometry().height());
        cw =  mControlWidget; // muss spaeter geloescht werden
    
        mStereoWidget = new StereoWidget(this);
        mStereoWidget->setWindowFlags(Qt::Window);
        mStereoWidget->setWindowTitle("Stereo parameter");
        //mStereoWidget->show();
    
        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");
        //mColorMarkerWidget->show();
    
        mCodeMarkerWidget = new CodeMarkerWidget(this);
        mCodeMarkerWidget->setWindowFlags(Qt::Window);
        mCodeMarkerWidget->setWindowTitle("Code marker parameter");
        //mCodeMarkerWidget->show();
    
    
        mMultiColorMarkerWidget = new MultiColorMarkerWidget(this);
        mMultiColorMarkerWidget->setWindowFlags(Qt::Window);
        mMultiColorMarkerWidget->setWindowTitle("MultiColor marker parameter");
        //mColorMarkerWidget->show();
    
    
        mScene = new QGraphicsScene(this);
    
    d.kilic's avatar
    d.kilic committed
    
        mImageItem = new ImageItem(this); // durch uebergabe von scene wird indirekt ein scene->addItem() aufgerufen
        mControlWidget->setScene(mScene);
    
        // wird in controll.cpp behandelt!!!
        //     if (mControlWidget->filterBright->checkState() == Qt::Checked)
        //         mBrightFilter.enable();
        //     else //Qt::Unchecked
        //         mBrightFilter.disable();
        //     if (mControlWidget->filterContrast->checkState() == Qt::Checked)
        //         mContrastFilter.enable();
        //     else //Qt::Unchecked
        //         mContrastFilter.disable();
        //     if (mControlWidget->filterContrast->checkState() == Qt::Checked)
        //         mContrastFilter.enable();
        //     else //Qt::Unchecked
        //         mContrastFilter.disable();
    
        mAnimation = new Animation(this);
    
        //     mImage = new QImage; // wird erst bei neuer sequenz erstellt, da dort groesse bekannt,
        //      zudem kann so ueber mImage==NULL beginn abgefragt werden
        //     // hier koennte ein Einfuehrungsbild mit logo etc eingeblendet werden
        //     mImage->load(":/logo");
        //     //C:/Dokumente und Einstellungen/Maik Boltes/Eigene Dateien/diss/logo/logo.png
        //     mImageItem->setLogo(mImage);
        //     // so wurde gruene recogniton area zurueckgesetzt:
        //     //mImageItem->setImage(mImage);
        mLogoItem = new LogoItem(this); // durch uebergabe von scene wird indirekt ein scene->addItem() aufgerufen
        mLogoItem->setZValue(6); // groesser heisst weiter oben
    
        mExtrCalibration.setMainWindow(this);
        //mExtCalibration = new ExtrCalibration(this); // muss vor CoordItem (und GridItem) stehen damit man auf useExtCalib abfragen kann
    
        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();
        //mScene->setSceneRect(0, 0, 0, 0);
        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(addManualTrackPoint(QPointF))); //const QPoint &pos funktionierte nicht
        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)));
        //connect(mView, SIGNAL(mouseRightClick(QPointF)), this, SLOT(showContextMenu(QPointF)));
    
        mPlayerWidget = new Player(mAnimation, this);
    
        QVBoxLayout *vLayout = new QVBoxLayout;
        vLayout->setSpacing(space);
        vLayout->addWidget(mViewWidget);
        vLayout->addWidget(mPlayerWidget);
    
        QVBoxLayout *vControlLayout = new QVBoxLayout;
        //vControlLayout->setSpacing(space);
        vControlLayout->addWidget(mControlWidget);
    
        //---------------------------
    
        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);
        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);
    
        /// 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);
        mCentralLayout->addLayout(vLayout);
        mCentralLayout->addLayout(vControlLayout);
        //mCentralLayout->addWidget(mControlWidget); //, 0, Qt::AlignTop
        setWindowTitle(tr("PeTrack"));
    
        //---------------------------
        mAutoCalib.setMainWindow(this);
        //---------------------------
    
        createActions();
        createMenus();
        //createToolBars();
        createStatusBar();
    
        mSeqFileName = QDir::currentPath(); //fuer allerersten Aufruf des Programms
        readSettings();
    
        saveXml(mDefaultSettings); //noch nicht noetig, da eh noch nicht fkt
    //    mDefaultSettings = QString(QDir::tempPath() + "/default.pet");
    //    saveProject(mDefaultSettings); // save default settings for later restore
    
        //#include <time.h>
    
        mShowFPS = 0;
        //    mLastTime = -1;
    
        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
    
    //    resetUI();
    
        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
     */
    
    d.kilic's avatar
    d.kilic committed
    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::contextMenuEvent(QContextMenuEvent *event){
    //        QMenu menu(this);
    //        menu.addAction(mDelPastAct);
    //        menu.addAction(mDelFutureAct);
    //        menu.addAction(mDelAllRoiAct);
    //        menu.exec(event->globalPos());
    //}
    
    void Petrack::updateSceneRect()
    {
        double iW=0, iH=0, bS=0;
    
        //     // must be set explicitly, because the bounding box of the whole scene raises automatically but not gets smaller
        //     cout << "Image: "<< boundingRect().x() << " " << boundingRect().width() <<endl;
        //     cout << "Image: "<< sceneBoundingRect().x() << " " << sceneBoundingRect().width() <<endl;
        //     cout << "Image: "<< mScene->itemsBoundingRect().x() << " " << mScene->itemsBoundingRect().width() <<endl;
        //     mScene->setSceneRect(mScene->itemsBoundingRect()); // klappte nicht so gut, warum?
    
        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
     */
    
    d.kilic's avatar
    d.kilic committed
    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 (openSeq && (seq != ""))
    //                    openSequence(seq); // wenn leer, dann kommt abfrage hoch, welche datei; abbrechen, wenn aktuelle gewuenscht
    
                }
                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() == "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() == "PLAYER")
            {
                if (elem.hasAttribute("FRAME"))
                {
                    frame = elem.attribute("FRAME").toInt();
                }
                if (elem.hasAttribute("FPS"))
                {
                    //mAnimation->setFPS(elem.attribute("FPS").toDouble());
                    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());
    
    d.kilic's avatar
    d.kilic committed
                }
            }
            else if (elem.tagName() == "VIEW")
            {
                if (elem.hasAttribute("ANTIALIAS"))
                {
    
                    mAntialiasAct->setChecked(elem.attribute("ANTIALIAS").toInt() == Qt::Checked);
    
    d.kilic's avatar
    d.kilic committed
                }
                if (elem.hasAttribute("OPENGL"))
                {
    
                    mOpenGLAct->setChecked(elem.attribute("OPENGL").toInt() == Qt::Checked);
    
    d.kilic's avatar
    d.kilic committed
                }
                if (elem.hasAttribute("SAVE_TRANSFORMED"))
                {
    
                    mCropZoomViewAct->setChecked(elem.attribute("SAVE_TRANSFORMED") == Qt::Checked);
    
    d.kilic's avatar
    d.kilic committed
                }
                if (elem.hasAttribute("TRANSFORMATION"))
                {
                    QString matStr = elem.attribute("TRANSFORMATION");
                    QTextStream in(&matStr);
                    in >> zoom >> rotate >> hScroll >> vScroll;
                    //elem.attribute("TRANSFORMATION").sscanf("%f %f %f %f %f %f", &m11, &m12, &m21, &m22, &dx, &dy);
                    //mView->setMatrix(QMatrix(m11, m12, m21, m22, dx, dy));
                    //mView->centerOn(m21, m22);
                }
                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);
    
    d.kilic's avatar
    d.kilic committed
                }
            } 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() << 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() << "!" << endl;
        }
    
        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();
                //mTracker->init();
            }
            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 (*.*)"));
        // folgende zeilen nicht noetig, da dies nicht in pet-datei steht!
        //     else
        //         fileName = getExistingFile(fileName); // ueberprueft die ;-getrennten Dateinamen auf existenz und gibt ersten zurueck - interessant fuer relativen und absoluten pfad
    
        if (!fileName.isEmpty())
        {
            QFile file(fileName);
            if (!file.open(QIODevice::ReadOnly))
            {
                QMessageBox::critical(this, tr("PeTrack"), tr("Cannot open %1:\n%2.").arg(fileName).arg(file.errorString()));
                return;
            }
            resetSettings();
            QDomDocument doc("PETRACK"); // eigentlich Pfad zu Beschreibungsdatei fuer Dateiaufbau
            if (!doc.setContent(&file))
            {
                QMessageBox::critical(this, tr("PeTrack"), tr("Cannot read content from %1.").arg(fileName));
                file.close();
                return;
            }
    
    //        resetUI();
            debout << "open " << fileName << endl;
            file.close();
            mProFileName = fileName;
    
            QDomElement root = doc.firstChildElement("PETRACK");
            if (root.hasAttribute("VERSION"))
                if (root.attribute("VERSION") != VERSION)
                {
                    QMessageBox::warning(this, tr("PeTrack"), tr("Reading %1:\nDifferent version numbers %2 (application) and %3 (file) may cause problems.").arg(fileName).arg(VERSION).arg(root.attribute("VERSION")));
                    //tr("Cannot read content from %1\nbecause of different version numbers\n%2 (application) and %3 (file).").arg(fileName).arg(VERSION).arg(root.attribute("VERSION")));
                    //return;
                }
            openXml(doc, openSeq);
            updateWindowTitle();
        }
    }
    
    void Petrack::saveXml(QDomDocument &doc)
    {
        QDomElement elem;
    
        QDomElement root = doc.createElement("PETRACK");
        root.setAttribute("VERSION", VERSION);
        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);
    
        // 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);
    
        // 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());
    
    d.kilic's avatar
    d.kilic committed
    
        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());
        //         QMatrix mat = mView->matrix();
        //         QPointF center = (mView->sceneRect()).center();
        // kein rect oder so gefunden, was den sichtbaren bereich in viewport angibt
        //        elem.setAttribute("TRANSFORMATION", QString("%1 %2 %3 %4 %5 %6").arg(mat.m11()).arg(mat.m12()).arg(mat.m21()).arg(mat.m22()).arg(mat.dx()).arg(mat.dy()));
        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
    
    d.kilic's avatar
    d.kilic committed
        elem.setAttribute("CAMERA", mAnimation->getCamera());
    
    #else
        elem.setAttribute("CAMERA", cameraUnset);
    #endif
    
    d.kilic's avatar
    d.kilic committed
        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
    
    d.kilic's avatar
    d.kilic committed
    bool Petrack::saveSameProject()
    {
        return saveProject(mProFileName);
    }
    
    
    /// rueckgabewert zeigt an, ob gesichert werden konnte
    
    d.kilic's avatar
    d.kilic committed
    bool Petrack::saveProject(QString fileName) // default fileName=""
    {
        // if no destination file or folder is given
        if (fileName.isEmpty() || QFileInfo(mProFileName).isDir())
        {
            //QFileInfo(mProFileName).path()
            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))
            {
                QMessageBox::critical(this, tr("PeTrack"), tr("Cannot save %1:\n%2.").arg(fileName).arg(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 << endl;
    
            mProFileName = fileName;
            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){
    
    d.kilic's avatar
    d.kilic committed
            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){
    
    d.kilic's avatar
    d.kilic committed
                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*/)
    
    d.kilic's avatar
    d.kilic committed
    {
        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)" << endl;
            camID = 0; // default
    
        }
        if (!mAnimation->openCameraStream(camID))
        {
            QMessageBox::critical(this, tr("PeTrack"), tr("Cannot start Camera Livestream."));
            return;
        }
        mSeqFileName = "camera live stream";
        debout << "open " << mSeqFileName << " (" << mAnimation->getNumFrames() << " frames; " << mAnimation->getFPS() << " fps; " << mAnimation->getSize().width() << "x" << mAnimation->getSize().height() << " pixel)" << endl; //size
        updateSequence();
        updateWindowTitle();
        mPlayerWidget->setFPS(mAnimation->getFPS());
        if (mOpenGLAct->isChecked())
            mLogoItem->fadeOut(1);
        else
            mLogoItem->fadeOut(50);
        updateCoord();
    
    
        mPlayerWidget->play(PlayerState::FORWARD);
    
    d.kilic's avatar
    d.kilic committed
    }
    
    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 (*.*)"));
        // in control
        //     else
        //         fileName = getExistingFile(fileName); // ueberprueft die ;-getrennten Dateinamen auf existenz und gibt ersten zurueck - interessant fuer relativen und absoluten pfad
        if (!fileName.isEmpty())
        {
            if (!mAnimation->openAnimation(fileName))
            {
                QMessageBox::critical(this, tr("PeTrack"), tr("Cannot load %1.").arg(fileName));
                return;
            }
    
            //updateSourceInOutFrames();
            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();
    
    d.kilic's avatar
    d.kilic committed
            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)" << endl; //size
            updateSequence();
            updateWindowTitle();
            mPlayerWidget->setFPS(mAnimation->getFPS());
            if (mOpenGLAct->isChecked())
                mLogoItem->fadeOut(1);
            else
                mLogoItem->fadeOut(50);
            updateCoord();
        }
    }
    
    void Petrack::updateWindowTitle()
    {
        QString title;
        QSize size = mAnimation->getSize();
    
        if (QFileInfo(mProFileName).isDir())
            title = tr("PeTrack (v") + VERSION + tr("): ");
        else
        {
            title = tr("PeTrack (v") + VERSION + 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)"; //size getFileBase()+".avi"
          //title += "sequence: " + mAnimation->getCurrentFileName() + tr(" (%1").arg(mAnimation->getNumFrames()) + tr(" frames; %1").arg(mAnimation->getFPS()) + tr(" fps; %1x%2").arg(size.width()).arg(size.height()) + " pixel)"; //size getFileBase()+".avi"
        else if (mAnimation->isImageSequence())
            title += "sequence: " + mAnimation->getCurrentFileName() + tr(" ... (%1").arg(mAnimation->getNumFrames()) + tr(" frames; %1x%2").arg(size.width()).arg(size.height()) + " pixel)"; //size getFileBase()
          //title += "sequence: " + mAnimation->getCurrentFileName() + tr(" ... (%1").arg(mAnimation->getNumFrames()) + tr(" frames; %1").arg(mAnimation->getFPS()) + tr(" fps; %1x%2").arg(size.width()).arg(size.height()) + " pixel)"; //size getFileBase()
        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
     */
    
    d.kilic's avatar
    d.kilic committed
    void Petrack::saveSequence(bool saveVideo, bool saveView, QString dest) // default saveView= false, dest=""
    {
        static QString lastDir;
    
    d.kilic's avatar
    d.kilic committed
    
        // 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
    
    d.kilic's avatar
    d.kilic committed
            if (dest.right(4) == ".avi")
                saveVideo = true;
            else
                saveVideo = false;
        }
    
        if (!dest.isEmpty() && mImage)
        {