Skip to content
Snippets Groups Projects
petrack.cpp 142 KiB
Newer Older
            color.setRgb(0,200,0,opacity);
d.kilic's avatar
d.kilic committed

        pal.setColor(QPalette::Window, color);

        mStatusLabelFPS->setPalette(pal);
    }
}
void Petrack::setShowFPS(double fps)
{
    if ((fps == 0.) || (mShowFPS == 0))
        mShowFPS = fps;
    else
        mShowFPS = mShowFPS*.9+fps*.1; // glaetten durch Hinzunahme des alten Wertes
    setStatusFPS();
}

/**
 * @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;
    static int skippedFrames = 0;

    if(skipped){
        skippedFrames++;
        return;
    }
d.kilic's avatar
d.kilic committed

    if (mPlayerWidget->getPaused())
d.kilic's avatar
d.kilic committed
    {
        setShowFPS(0.);
d.kilic's avatar
d.kilic committed
    }
    else
    {
        if (lastTime.isValid())
        {
            if (lastTime.elapsed() > 0)
            {
                int numFrames = skippedFrames > 0 ? skippedFrames+1 : 1;
                setShowFPS(numFrames*1000./lastTime.elapsed());
                skippedFrames = 0;
d.kilic's avatar
d.kilic committed
    }
}

// ohne neue positionsangabe, sinnvoll, wenn berechnungsweise sich in getPosReal geaendert hat
// gebraucht in control.cpp
void Petrack::setStatusPosReal() // pos in cm
{
    if (mImageItem)
        setStatusPosReal(mImageItem->getPosReal(mMousePosOnImage, getStatusPosRealHeight()));
}
d.kilic's avatar
d.kilic committed
void Petrack::setStatusPosReal(const QPointF &pos) // pos in cm
{
    if (mStatusLabelPosReal)
    {
        QChar deg(0xB0);
        QString labelText = QString(" cm from ground:%1cm,%2cm,%3").arg(pos.x(), 6, 'f', 1).arg(pos.y(), 6, 'f', 1).arg(
                                    getImageItem()->getAngleToGround(mMousePosOnImage.x(), mMousePosOnImage.y(), getStatusPosRealHeight()), 5, 'f', 1);
        labelText.append(deg);
        mStatusLabelPosReal->setText(labelText);
    }
}
d.kilic's avatar
d.kilic committed
void Petrack::setStatusPos(const QPoint &pos) // pos in pixel
{
    mStatusLabelPos->setText(QString("%1x%2").arg(pos.x(), 4).arg(pos.y(), 4));
}
d.kilic's avatar
d.kilic committed
void Petrack::setStatusColor(const QRgb &col)
{
    QString s("#%1%2%3"); // static moeglich?
    s = s.arg(qRed(col), 2, 16, QChar('0')).arg(qGreen(col), 2, 16, QChar('0')).arg(qBlue(col), 2, 16, QChar('0'));
    if ((qRed(col)+qGreen(col)+qBlue(col))/3 < 128)
        mStatusLabelColor->setText(QString("<font color=\"#ffffff\">&nbsp;%1</font>").arg(s));
    else
        mStatusLabelColor->setText(QString("<font color=\"#000000\">&nbsp;%1</font>").arg(s));

    QPalette pal = mStatusLabelColor->palette(); // static moeglich?
    QColor color(qRed(col), qGreen(col), qBlue(col));

    pal.setColor(QPalette::Window, color);
    mStatusLabelColor->setPalette(pal);

    mControlWidget->getColorPlot()->setCursor(color);
    mControlWidget->getColorPlot()->replot();

}
d.kilic's avatar
d.kilic committed
void Petrack::setStatusColor()
{
    QPointF pos = getMousePosOnImage();
    if (pos.x() >= 0 && pos.x() < mImage->width() && pos.y() > 0 && pos.y() < mImage->height())
d.kilic's avatar
d.kilic committed
    {
        setStatusColor(mImage->pixel(pos.toPoint()));
d.kilic's avatar
d.kilic committed
    }
}

double Petrack::getStatusPosRealHeight()
{
    if (mStatusPosRealHeight)
        return mStatusPosRealHeight->value();
    else
        return 0.;
}

/**
 * @brief Reads (and applies) settings form platform-independent persistent storage
 *
 * The saved size and position of the application window get reconstructed. As well as
 * the options about antialiasing and the usage of OpenGL.
 * mSeqFileName and mProFileName get set, so the "Open Project" and "Open Sequence"
 * dialogues start at correct folder. The old project/sequence is NOT actually loaded.
 */
d.kilic's avatar
d.kilic committed
void Petrack::readSettings()
{
    QSettings settings("Forschungszentrum Juelich GmbH", "PeTrack by Maik Boltes, Daniel Salden");
    QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
    QSize size = settings.value("size", QSize(400, 400)).toSize();
    mAntialiasAct->setChecked(settings.value("antialias", false).toBool());
    mOpenGLAct->setChecked(settings.value("opengl", false).toBool());
    mSeqFileName = settings.value("seqFileName", QDir::currentPath()).toString();
    setProFileName(settings.value("proFilePath", QDir::currentPath()).toString());
d.kilic's avatar
d.kilic committed
    // nicht ganz sauber, da so immer schon zu anfang in calib file list etwas drin steht und somit auto ausgefuehrt werden kann
    // wird aber beim ersten openCalib... ueberschrieben
    mAutoCalib.addCalibFile(settings.value("calibFile", QDir::currentPath()).toString());
    resize(size);
    move(pos);
    antialias();
    opengl();
    mSplitter->restoreState(settings.value("controlSplitterSizes").toByteArray());
d.kilic's avatar
d.kilic committed
}

/**
 * @brief Writes persistent setting.
 * @see Petrack::readSettings
 */
d.kilic's avatar
d.kilic committed
void Petrack::writeSettings()
{
    QSettings settings("Forschungszentrum Juelich GmbH", "PeTrack by Maik Boltes, Daniel Salden");
    settings.setValue("pos", pos());
    settings.setValue("size", size());
    settings.setValue("antialias", mAntialiasAct->isChecked());
    settings.setValue("opengl", mOpenGLAct->isChecked());
    settings.setValue("seqFileName", mSeqFileName);
    settings.setValue("proFilePath", QFileInfo(mProFileName).path()); // nur path, damit bei saveCurrentProject
    if (!mAutoCalib.isEmptyCalibFiles()) //!mCalibFiles.isEmpty()
        settings.setValue("calibFile", mAutoCalib.getCalibFile(0));
    settings.setValue("controlSplitterSizes", mSplitter->saveState());
d.kilic's avatar
d.kilic committed
}

bool Petrack::maybeSave()
{
    int ret = PWarning(this, tr("PeTrack"),
                                   tr("Do you want to save "
d.kilic's avatar
d.kilic committed
                                      "the current project?\n"
                                      "Be sure to save trajectories, background "
d.kilic's avatar
d.kilic committed
                                      "and 3D calibration point separately!"),
                                   PMessageBox::StandardButton::Yes |
                                    PMessageBox::StandardButton::No |
                                    PMessageBox::StandardButton::Cancel,
                                   PMessageBox::StandardButton::Yes);
d.kilic's avatar
d.kilic committed

    if (ret == PMessageBox::StandardButton::Yes)
d.kilic's avatar
d.kilic committed
    {
        if (saveSameProject())
            return true;
        else
            return false;
    }
    else if (ret == PMessageBox::StandardButton::Cancel)
d.kilic's avatar
d.kilic committed
        return false;
    else
        return true;
}

void Petrack::closeEvent(QCloseEvent *event)
{

    if (maybeSave())
    {
        writeSettings();
        event->accept();
    }
    else
        event->ignore();

}

/**
 * @brief Sets the mMousePosOnImage member variable and displayed pixel/real coordinates
 *
 * Gets called from ImageItem::hoverMoveEvent() and enables an easy access
 * to the mouse position.
 * @param pos Position of mouse cursor in image pixel coordinates
 */
d.kilic's avatar
d.kilic committed
void Petrack::setMousePosOnImage(QPointF pos)
{
    if (mImage)
    {
        mMousePosOnImage = pos;
        setStatusPosReal(mImageItem->getPosReal(pos, getStatusPosRealHeight()));

        // pixel coordinate
        QPoint pos1((int)(pos.x())+1, (int)(pos.y())+1);
        setStatusPos(pos1);
d.kilic's avatar
d.kilic committed
        // pixel color
        setStatusColor();
d.kilic's avatar
d.kilic committed
    }
}

void Petrack::keyPressEvent(QKeyEvent * event)
{
    switch (event->key()) {
    case Qt::Key_Left:
        mPlayerWidget->frameBackward();
        break;
    case Qt::Key_Right:
        mPlayerWidget->frameForward();
        break;
    case Qt::Key_Down:
        mViewWidget->zoomOut(1);
        break;
    case Qt::Key_Up:
        mViewWidget->zoomIn(1);
        break;
    case Qt::Key_Space:
        // space wird von buttons, wenn focus drauf ist als Aktivierung vorher abgegriffen und nicht durchgereicht
        mPlayerWidget->togglePlayPause();
        break;
    case Qt::Key_D:
        break;
    default:
        ;
    }
}

void Petrack::mousePressEvent(QMouseEvent *event)
{
    // mouse click in fps status label ?
    if( event->pos().x() >= mStatusLabelFPS->pos().x() && event->pos().x() <= mStatusLabelFPS->pos().x()+mStatusLabelFPS->width() )
    {
        mPlayerWidget->togglePlayerSpeedLimited();
d.kilic's avatar
d.kilic committed
        setStatusFPS();
    }
}

/// update control widget, if image size changed (especially because of changing border)
void Petrack::updateControlImage(cv::Mat &img)
d.kilic's avatar
d.kilic committed
{

    // auch moeglich hoehe und breite von bild stat border veraenderungen zu checken
    static int lastBorderSize = -1;

    if( isLoading() )
        lastBorderSize = -1;

    int diffBorderSize=0;
    int iW = img.cols;
    int iH = img.rows;

    // wird auch nochmal in ImageWidget gemacht, aber ist hier frueher noetig
    double cX = mControlWidget->getCalibCxValue(); // merken, da min/max value verandernkann wenn aus dem rahmen
    double cY = mControlWidget->getCalibCyValue();

    mControlWidget->setCalibCxMin(0  /*iW/2.-50.*/);
    mControlWidget->setCalibCxMax(iW /*iW/2.+50.*/);
    mControlWidget->setCalibCyMin(0  /*iH/2.-50.*/);
    mControlWidget->setCalibCyMax(iH /*iH/2.+50.*/);

    if (mControlWidget->fixCenter->checkState() == Qt::Checked)
    {
        mControlWidget->setCalibCxValue((iW-1)/2.);
        mControlWidget->setCalibCyValue((iH-1)/2.);
    }
    else
    {
        if (lastBorderSize != -1)
            diffBorderSize = getImageBorderSize()-lastBorderSize;
        lastBorderSize = getImageBorderSize();

        mControlWidget->setCalibCxValue(cX+diffBorderSize);
        mControlWidget->setCalibCyValue(cY+diffBorderSize);
    }
}

void Petrack::importTracker(QString dest) //default = ""
{
    static QString lastFile;

    if (lastFile == "")
        lastFile = mTrcFileName;

    // if no destination file or folder is given
    if (dest.isEmpty())
    {
        dest = QFileDialog::getOpenFileName(this, tr("Select file for importing tracking pathes"), lastFile,
                                            tr("PeTrack tracker (*.trc *.txt);;All files (*.*)"));
    }

    if (!dest.isEmpty())
    {
        if (dest.right(4) == ".trc")
        {
            QFile file(dest);
            int i, sz;

            if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
            {
                // errorstring ist je nach Betriebssystem in einer anderen Sprache!!!!
                PCritical(this, tr("PeTrack"), tr("Cannot open %1:\n%2").arg(dest).arg(file.errorString()));
d.kilic's avatar
d.kilic committed
                return;
            }

            setTrackChanged(true);// flag changes of track parameters
            mTracker->reset();

            QTextStream in(&file);
            TrackPerson tp;
            QString comment;

            bool ok; // shows if int stands in first line - that was in the first version of trc file
            QString firstLine = in.readLine();
            sz = firstLine.toInt(&ok);
            if (!ok)
            {
                if (firstLine.contains("version 4",Qt::CaseInsensitive))
                {
                    trcVersion = 4;
                }
                else if (firstLine.contains("version 3",Qt::CaseInsensitive))
d.kilic's avatar
d.kilic committed
                {
                    trcVersion = 3;
                }
                else if(firstLine.contains("version 2",Qt::CaseInsensitive))
d.kilic's avatar
d.kilic committed
                {
                    trcVersion = 2;
d.kilic's avatar
d.kilic committed
                {
                    debout << "Error: wrong header while reading TRC file." << std::endl;
                    QMessageBox::critical(this, tr("PeTrack"), tr("Could not import tracker:\nNot supported trc version in file: %1.").arg(dest));
                    return;
d.kilic's avatar
d.kilic committed
                }
                in >> sz;
            }
            else
                trcVersion = 1;

            if ((sz > 0) && (mTracker->size() != 0))
                debout << "Warning: Overlapping trajectories will be joined not until tracking adds new trackpoints." << std::endl;
d.kilic's avatar
d.kilic committed
            for (i = 0; i < sz; ++i)
            {
                if( trcVersion == 2)
                {
                    in >> tp;
                }else if( trcVersion >= 3)
                {
                    in >> tp;
                }
                mTracker->append(tp);
                tp.clear();  // loeschen, sonst immer weitere pfade angehangen werden
            }

            mControlWidget->trackNumberAll->setText(QString("%1").arg(mTracker->size()));
            mControlWidget->trackShowOnlyNr->setMaximum(MAX(mTracker->size(),1));
            mControlWidget->trackNumberVisible->setText(QString("%1").arg(mTracker->visible(mAnimation->getCurrentFrameNum())));
            mControlWidget->colorPlot->replot();
            file.close();
            debout << "import " << dest << " (" << sz << " person(s), file version " << trcVersion << ")" << std::endl;
d.kilic's avatar
d.kilic committed
            mTrcFileName = dest; // fuer Project-File, dann koennte track path direkt mitgeladen werden, wenn er noch da ist
        }else
        if (dest.right(4) == ".txt") // 3D Koordinaten als Tracking-Daten importieren Zeilenformat: Personennr, Framenr, x, y, z
        {
            PWarning(this,tr("PeTrack"), tr("Are you sure you want to import 3D data from TXT-File? You have to make sure that the coordinate system now is exactly at the same position and orientation than at export time!"));
d.kilic's avatar
d.kilic committed

            QFile file(dest);
            // size of person list
            int sz = 0;

            if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
            {
                // errorstring ist je nach Betriebssystem in einer anderen Sprache!!!!
                PCritical(this, tr("PeTrack"), tr("Cannot open %1:\n%2").arg(dest).arg(file.errorString()));
d.kilic's avatar
d.kilic committed
                return;
            }

            setTrackChanged(true);// flag changes of track parameters
            mTracker->reset();

            QTextStream in(&file);
            TrackPerson tp;
            TrackPoint tPoint;
d.kilic's avatar
d.kilic committed

            QString line;
            QString headerline;
            bool exec_once_flag = false;
            double conversionFactorTo_cm = 1.0;
            int personNr = -1, frameNr = -1, current_personNr = 1;
            float x, y ,z;

            while( 1 )
            {

                // Falls Datei am Ende letzte Person abspeichern und Lese-Schleife beenden
                if( in.atEnd() )
                {
                    tp.setLastFrame(frameNr);
                    mTracker->append(tp);
                    ++sz;
                    tp.clear();
                    break;
                }

                line = in.readLine();

                // Kommentare ueberlesen
                if( line.startsWith("#",Qt::CaseInsensitive) )
                {
                    headerline = line;
                    continue;
                }

                if ((!exec_once_flag) && (!headerline.contains("cm")))
                {
                    conversionFactorTo_cm = 100.0;
                    exec_once_flag = true;
                    PWarning(this,tr("PeTrack"), tr("PeTrack will interpret position data as unit [m]. No header with [cm] found."));
d.kilic's avatar
d.kilic committed
                }

                QTextStream stream(&line);

                // Zeile als Stream einlesen Format: [id frame x y z]
                stream >> personNr
                       >> frameNr
                       >> x
                       >> y
                       >> z;

                // convert data to cm
                x = x * conversionFactorTo_cm;
                y = y * conversionFactorTo_cm;
                z = z * conversionFactorTo_cm;

                // 3-dimensionale Berechnung/Anzeige des Punktes
                if( mControlWidget->getCalibCoordDimension() == 0 )
                {
                    p2d = mExtrCalibration.getImagePoint(cv::Point3f(x,y,z));
d.kilic's avatar
d.kilic committed
                }
                // 2-dimensionale Berechnung/Anzeige des Punktes
                else
                {
                    QPointF pos = mImageItem->getPosImage(QPointF(x,y),z);
                    p2d.x = pos.x();
                    p2d.y = pos.y();
                }

                tPoint = TrackPoint(Vec2F(p2d.x,p2d.y),100);
                tPoint.setSp(x,y,-mControlWidget->getCalibExtrTrans3()-z); // fuer den Abstand zur Kamera in z-Richtung wie bei einer Stereokamera

                // Neue ID ? ==> letzte Person beendet ==> abspeichern
                if( personNr > current_personNr )
                {
                    mTracker->append(tp);
                    ++sz;
                    current_personNr++;
                    tp.clear();
                }

                // TrackPerson leer ? ==> Neue TrackPerson erstellen
                if ( tp.isEmpty() )
                {
                    tp = TrackPerson(personNr, frameNr, tPoint);
                    tp.setFirstFrame(frameNr);
                    tp.setHeight(z);
                }
                // TrackPoint an TrackPerson anhaengen
                else
                {
                    tp.setLastFrame(frameNr);
                    tp.append(tPoint);
                }
            }

            mControlWidget->trackNumberAll->setText(QString("%1").arg(mTracker->size()));
            mControlWidget->trackShowOnlyNr->setMaximum(MAX(mTracker->size(),1));
            mControlWidget->trackNumberVisible->setText(QString("%1").arg(mTracker->visible(mAnimation->getCurrentFrameNum())));
            mControlWidget->colorPlot->replot();
            file.close();
            debout << "import " << dest << " (" << sz << " person(s) )" << std::endl;
d.kilic's avatar
d.kilic committed
            mTrcFileName = dest; // fuer Project-File, dann koennte track path direkt mitgeladen werden, wenn er noch da ist
        }
        else
        {
            PCritical(this, tr("PeTrack"), tr("Cannot load %1 maybe because of wrong file extension.").arg(dest));
d.kilic's avatar
d.kilic committed
        }
        lastFile = dest;
    }
}

void Petrack::testTracker()
{
    static int idx=0; // index in Fehlerliste, die als letztes angesprungen wurde
    QList<int> pers, frame;

    mTracker->checkPlausibility(pers, frame,
                                mControlWidget->testEqual->isChecked(),
                                mControlWidget->testVelocity->isChecked(),
                                mControlWidget->testInside->isChecked(),
                                mControlWidget->testLength->isChecked());
    if (pers.length()<=idx)
        idx=0;
    if (pers.length()>idx)
    {
        mControlWidget->trackShowOnly->setCheckState(Qt::Checked);
        mControlWidget->trackShowOnlyNr->setValue(pers[idx]);
        mPlayerWidget->skipToFrame(frame[idx]);
d.kilic's avatar
d.kilic committed
        ++idx;
    }

}

int Petrack::calculateRealTracker()
{
    bool autoCorrectOnlyExport = (mReco.getRecoMethod() == reco::RecognitionMethod::MultiColor) && // multicolor
d.kilic's avatar
d.kilic committed
            mMultiColorMarkerWidget->autoCorrect->isChecked() &&
            mMultiColorMarkerWidget->autoCorrectOnlyExport->isChecked();
    int anz = mTrackerReal->calculate(mTracker, mImageItem, mControlWidget->getColorPlot(), getImageBorderSize(),
                            mControlWidget->anaMissingFrames->checkState(),
d.kilic's avatar
d.kilic committed
                            mStereoWidget->stereoUseForExport->isChecked(),
                            mControlWidget->trackAlternateHeight->checkState(), mControlWidget->coordAltitude->value(), mStereoWidget->stereoUseCalibrationCenter->isChecked(),
                            mControlWidget->exportElimTp->isChecked(), mControlWidget->exportElimTrj->isChecked(), mControlWidget->exportSmooth->isChecked(),
                            mControlWidget->exportViewDir->isChecked(), mControlWidget->exportAngleOfView->isChecked(), mControlWidget->exportMarkerID->isChecked(),
                            autoCorrectOnlyExport);

    mTrackerReal->calcMinMax();
    return anz;
}

void Petrack::exportTracker(QString dest) //default = ""
{
    static QString lastFile;

    if (lastFile == "")
        lastFile = mTrcFileName;

    if (mTracker)
    {
        // if no destination file or folder is given
        if (dest.isEmpty())
        {
            QFileDialog fileDialog(this,
                                   tr("Select file for exporting tracking pathes"),
                                   lastFile,
                                   tr("Tracker (*.*);;Petrack tracker (*.trc);;Text (*.txt);;Text for gnuplot(*.dat);;XML Travisto (*.trav);;All supported types (*.txt *.trc *.dat *.trav *.);;All files (*.*)"));
            fileDialog.setAcceptMode(QFileDialog::AcceptSave);
            fileDialog.setFileMode(QFileDialog::AnyFile);
            fileDialog.setDefaultSuffix("");

            if( fileDialog.exec() ){
                dest = fileDialog.selectedFiles().at(0);
            }
       }

        if (!dest.isEmpty())
        {
            QList<int> pers, frame;
            bool autoCorrectOnlyExport = (mReco.getRecoMethod() == reco::RecognitionMethod::MultiColor) && // multicolor
d.kilic's avatar
d.kilic committed
                    mMultiColorMarkerWidget->autoCorrect->isChecked() &&
                    mMultiColorMarkerWidget->autoCorrectOnlyExport->isChecked();

            if (dest.right(4) == ".trc")
            {
#ifdef TIME_MEASUREMENT
                double time1 = 0.0, tstart;
                tstart = clock();
#endif
                QTemporaryFile file;
                int i;

                if (!file.open()/*!file.open(QIODevice::WriteOnly | QIODevice::Text)*/)
                {
                    PCritical(this, tr("PeTrack"), tr("Cannot open %1:\n%2.").arg(dest).arg(file.errorString()));
d.kilic's avatar
d.kilic committed
                    return;
                }
                QProgressDialog progress("Export TRC-File",nullptr,0,mTracker->size()+1,this->window());
d.kilic's avatar
d.kilic committed
                progress.setWindowTitle("Export .trc-File");
                progress.setWindowModality(Qt::WindowModal);
                progress.setVisible(true);
                progress.setValue(0);
                progress.setLabelText(QString("Export tracking data ..."));

                qApp->processEvents();

d.kilic's avatar
d.kilic committed

                debout << "export tracking data to " << dest << " (" << mTracker->size() << " person(s), file version " << trcVersion << ")..." << std::endl;
d.kilic's avatar
d.kilic committed
                QTextStream out(&file);

                out << "version " << trcVersion << Qt::endl;
                out << mTracker->size() << Qt::endl;
d.kilic's avatar
d.kilic committed
                for (i = 0; i < mTracker->size(); ++i)
                {
                    qApp->processEvents();
                    progress.setLabelText(QString("Export person %1 of %2 ...").arg(i+1).arg(mTracker->size()));
                    progress.setValue(i+1);
d.kilic's avatar
d.kilic committed
                }
                file.flush();
                file.close();
#ifdef TIME_MEASUREMENT
                time1 += clock() - tstart;
                time1 = time1/CLOCKS_PER_SEC;
                cout << "  time(writing) = " << time1 << " sec." << endl;

                time1 = 0.0;
                tstart = clock();
#endif
                progress.setLabelText(QString("Save file ..."));
                qApp->processEvents();

                if (QFile::exists(dest))
                    QFile::remove(dest);

                if( !file.copy(dest) )
                    PCritical(this, tr("PeTrack"),
                                                tr("Could not export tracking data.\n"
                                                   "Please try again!"));
d.kilic's avatar
d.kilic committed
                else
                    statusBar()->showMessage(tr("Saved tracking data to %1.").arg(dest), 5000);

                progress.setValue(mTracker->size()+1);

                std::cout << " finished " << std::endl;
d.kilic's avatar
d.kilic committed

#ifdef TIME_MEASUREMENT
                time1 += clock() - tstart;
                time1 = time1/CLOCKS_PER_SEC;
                cout << "  time(copying) = " << time1 << " sec." << endl;

//                time1 = 0.0;
//                tstart = clock();
#endif
d.kilic's avatar
d.kilic committed
#ifdef TIME_MEASUREMENT
//                time1 += clock() - tstart;
//                time1 = time1/CLOCKS_PER_SEC;
//                cout << "  time(checkPlausibility) = " << time1 << " sec." << endl;
#endif
                mTrcFileName = dest; // fuer Project-File, dann koennte track path direkt mitgeladen werden, wenn er noch da ist
            }
            else if (dest.right(4) == ".txt")
            {
                QTemporaryFile file;

                if (!file.open())
d.kilic's avatar
d.kilic committed
                {
                    PCritical(this, tr("PeTrack"), tr("Cannot open %1:\n%2.").arg(dest).arg(file.errorString()));
d.kilic's avatar
d.kilic committed
                    return;
                }

                debout << "export tracking data to " << dest << " (" << mTracker->size() << " person(s))..." << std::endl;
d.kilic's avatar
d.kilic committed

#ifdef TIME_MEASUREMENT
                double time1 = 0.0, tstart;
                tstart = clock();
#endif
                // recalcHeight true, wenn personenhoehe ueber trackpoints neu berechnet werden soll (z.b. um waehrend play mehrfachberuecksichtigung von punkten auszuschliessen, aenderungen in altitude neu in berechnung einfliessen zu lassen)
                if (mControlWidget->trackRecalcHeight->checkState())
                {
                    if ( mControlWidget->getCalibCoordDimension() == 0 ) // 3D
                        ;//Nothing to be done because z already the right height
                    else // 2D
                        mTracker->recalcHeight(mControlWidget->coordAltitude->value());
                }
#ifdef TIME_MEASUREMENT
                time1 += clock() - tstart;
                time1 = time1/CLOCKS_PER_SEC;
                cout << "  time(recalcHeight) = " << time1 << " sec." << endl;

                time1 = 0.0;
                tstart = clock();
d.kilic's avatar
d.kilic committed
                mTrackerReal->calculate(mTracker, mImageItem, mControlWidget->getColorPlot(), getImageBorderSize(),
                                        mControlWidget->trackMissingFrames->checkState(),
                                        mStereoWidget->stereoUseForExport->isChecked(),
                                        mControlWidget->trackAlternateHeight->checkState(), mControlWidget->coordAltitude->value(), mStereoWidget->stereoUseCalibrationCenter->isChecked(),
                                        mControlWidget->exportElimTp->isChecked(), mControlWidget->exportElimTrj->isChecked(), mControlWidget->exportSmooth->isChecked(),
                                        mControlWidget->exportViewDir->isChecked(), mControlWidget->exportAngleOfView->isChecked(), mControlWidget->exportMarkerID->isChecked(),
                                        autoCorrectOnlyExport);
#ifdef TIME_MEASUREMENT
                time1 += clock() - tstart;
                time1 = time1/CLOCKS_PER_SEC;
                cout << "  time(calculate) = " << time1 << " sec." << endl;

                time1 = 0.0;
                tstart = clock();
#endif

                QTextStream out(&file);

                out << "# PeTrack project: "     << QFileInfo(getProFileName()).fileName() << Qt::endl;
                out << "# raw trajectory file: " << QFileInfo(getTrackFileName()).fileName() << Qt::endl;
                out << "# framerate: "           << mAnimation->getFPS() << " fps" << Qt::endl;
d.kilic's avatar
d.kilic committed

                if (mControlWidget->exportComment->isChecked())
                {
                    out << "# personal information:" << Qt::endl;
                    out << "# ID| Comment" << Qt::endl;
d.kilic's avatar
d.kilic committed

                    // std out
                    std::cout << std::endl << "Printing comment table..." << std::endl << std::endl;
                    std::cout << "ID  | Comment" << std::endl;
                    std::cout << "----|----------------" << std::endl;
d.kilic's avatar
d.kilic committed

                    for(int i=0;i<mTracker->size();++i)
                    {
                        auto commentSplit = mTracker->at(i).comment().split("\n", Qt::KeepEmptyParts);
                        out << "#" << qSetFieldWidth(3) << (i+1) << qSetFieldWidth(0) << "|" << commentSplit.at(0) << Qt::endl;
                        std::cout  << std::setw(4) << (i+1) << "|" << commentSplit.at(0) << std::endl;

                        commentSplit.pop_front();
                        for (const auto& line : commentSplit)
                        {
                            out << "#" << qSetFieldWidth(3) << " " << qSetFieldWidth(0) << "|" << line << Qt::endl;
                            std::cout << "    |" << line << std::endl;
                        }
d.kilic's avatar
d.kilic committed
                    }
                }
                mTrackerReal->exportTxt(out,
                                        mControlWidget->trackAlternateHeight->checkState(),
                                        mStereoWidget->stereoUseForExport->isChecked(),
                                        mControlWidget->exportViewDir->isChecked(),
                                        mControlWidget->exportAngleOfView->isChecked(),
                                        mControlWidget->exportUseM->isChecked(),
                                        mControlWidget->exportMarkerID->isChecked());
                //out << *mTrackerReal;
                file.flush();
                file.close();

                if (QFile::exists(dest))
                    QFile::remove(dest);

                if( !file.copy(dest) )
d.kilic's avatar
d.kilic committed
                                                   tr("Could not export tracking data.\n"
d.kilic's avatar
d.kilic committed
                else
                    statusBar()->showMessage(tr("Saved tracking data to %1.").arg(dest), 5000);

                std::cout << " finished" << std::endl;
d.kilic's avatar
d.kilic committed

#ifdef TIME_MEASUREMENT
                time1 += clock() - tstart;
                time1 = time1/CLOCKS_PER_SEC;
                cout << "  time(export) = " << time1 << " sec." << endl;

//                time1 = 0.0;
//                tstart = clock();
#endif
d.kilic's avatar
d.kilic committed
#ifdef TIME_MEASUREMENT
//                time1 += clock() - tstart;
//                time1 = time1/CLOCKS_PER_SEC;
//                cout << "  time(checkPlausibility) = " << time1 << " sec." << endl;
#endif
            }
            else if (dest.right(4) == ".dat")
            {
                QTemporaryFile fileDat;

                if (!fileDat.open()) //!fileDat.open(QIODevice::WriteOnly | QIODevice::Text))
                {
                    PCritical(this, tr("PeTrack"), tr("Cannot open %1:\n%2.").arg(dest).arg(fileDat.errorString()));
d.kilic's avatar
d.kilic committed
                    return;
                }
                // recalcHeight true, wenn personenhoehe ueber trackpoints neu berechnet werden soll (z.b. um waehrend play mehrfachberuecksichtigung von punkten auszuschliessen, aenderungen in altitude neu in berechnung einfliessen zu lassen)
                if (mControlWidget->trackRecalcHeight->checkState())
                {
                    mTracker->recalcHeight(mControlWidget->coordAltitude->value());
                }
                mTrackerReal->calculate(mTracker, mImageItem, mControlWidget->getColorPlot(), getImageBorderSize(),
                                        mControlWidget->trackMissingFrames->checkState(),
                                        mStereoWidget->stereoUseForExport->isChecked(),
                                        mControlWidget->trackAlternateHeight->checkState(), mControlWidget->coordAltitude->value(), mStereoWidget->stereoUseCalibrationCenter->isChecked(),
                                        mControlWidget->exportElimTp->isChecked(), mControlWidget->exportElimTrj->isChecked(), mControlWidget->exportSmooth->isChecked(),
                                        mControlWidget->exportViewDir->isChecked(), mControlWidget->exportAngleOfView->isChecked(), mControlWidget->exportMarkerID->isChecked(),
                                        autoCorrectOnlyExport);

                debout << "export tracking data to " << dest << " (" << mTracker->size() << " person(s))..." << std::endl;
d.kilic's avatar
d.kilic committed
                QTextStream outDat(&fileDat);
                mTrackerReal->exportDat(outDat, mControlWidget->trackAlternateHeight->checkState(), mStereoWidget->stereoUseForExport->isChecked());
                fileDat.flush();
                fileDat.close();

                if (QFile::exists(dest))
                    QFile::remove(dest);

                if( !fileDat.copy(dest) )
d.kilic's avatar
d.kilic committed
                                                   tr("Could not export tracking data.\n"
d.kilic's avatar
d.kilic committed
                else
                    statusBar()->showMessage(tr("Saved tracking data to %1.").arg(dest), 5000);

                std::cout << " finished" << std::endl;
d.kilic's avatar
d.kilic committed
            }
            else if (dest.right(5) == ".trav")
            {
                // recalcHeight true, wenn personenhoehe ueber trackpoints neu berechnet werden soll (z.b. um waehrend play mehrfachberuecksichtigung von punkten auszuschliessen, aenderungen in altitude neu in berechnung einfliessen zu lassen)
                if (mControlWidget->trackRecalcHeight->checkState())
                {
                    mTracker->recalcHeight(mControlWidget->coordAltitude->value());
                }

                mTrackerReal->calculate(mTracker, mImageItem, mControlWidget->getColorPlot(), getImageBorderSize(),
                                        mControlWidget->trackMissingFrames->checkState(),
                                        mStereoWidget->stereoUseForExport->isChecked(),
                                        mControlWidget->trackAlternateHeight->checkState(), mControlWidget->coordAltitude->value(), mStereoWidget->stereoUseCalibrationCenter->isChecked(),
                                        mControlWidget->exportElimTp->isChecked(), mControlWidget->exportElimTrj->isChecked(), mControlWidget->exportSmooth->isChecked(),
                                        mControlWidget->exportViewDir->isChecked(), mControlWidget->exportAngleOfView->isChecked(), mControlWidget->exportMarkerID->isChecked(),
                                        autoCorrectOnlyExport);

                QTemporaryFile fileXml;
                if (!fileXml.open()) //!fileXml.open(QIODevice::WriteOnly | QIODevice::Text))
                {
                    PCritical(this, tr("PeTrack"), tr("Cannot open %1:\n%2.").arg(dest).arg(fileXml.errorString()));
d.kilic's avatar
d.kilic committed
                    return;
                }
                debout << "export tracking data to " << dest << " (" << mTracker->size() << " person(s))..." << std::endl;
d.kilic's avatar
d.kilic committed
                // already done: mTrackerReal->calculate(mTracker, mImageItem, mControlWidget->getColorPlot(), getImageBorderSize(), mControlWidget->trackMissingFrames->checkState());
                QTextStream outXml(&fileXml);
                outXml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << Qt::endl;
                outXml << "<trajectoriesDataset>" << Qt::endl;
                outXml << "    <header version=\"1.0\">" << Qt::endl;
                outXml << "        <roomCaption>PeTrack: " << mAnimation->getFileBase() << "</roomCaption>" << Qt::endl;
                outXml << "        <roomID>0</roomID>" << Qt::endl;
                outXml << "        <agents>" << mTracker->size() << "</agents>" << Qt::endl;
                outXml << "        <frameRate>" << mAnimation->getFPS() << "</frameRate> <!--per second-->" << Qt::endl;
d.kilic's avatar
d.kilic committed
                // outXml << "        <timeStep>" << 1000./mAnimation->getFPS() << "</timeStep>   <!-- millisecond-->" << endl; inverse von
                outXml << "        <timeFirstFrame sec=\"" << mAnimation->getFirstFrameSec() << "\" microsec=\"" << mAnimation->getFirstFrameMicroSec()
                       << "\"/> <!-- " << mAnimation->getTimeString(0) << " -->" << Qt::endl;
                outXml << "    </header>" << Qt::endl<< Qt::endl;
d.kilic's avatar
d.kilic committed

                mTrackerReal->exportXml(outXml, mControlWidget->trackAlternateHeight->checkState(), mStereoWidget->stereoUseForExport->isChecked());

                outXml << "</trajectoriesDataset>" << Qt::endl;
d.kilic's avatar
d.kilic committed
                fileXml.flush();
                fileXml.close();

                if (QFile::exists(dest))
                    QFile::remove(dest);

                if( !fileXml.copy(dest) )
                    PCritical(this, tr("PeTrack"),
                                                tr("Could not export tracking data.\n"
                                                    "Please try again!"));
d.kilic's avatar
d.kilic committed
                else
                    statusBar()->showMessage(tr("Saved tracking data to %1.").arg(dest), 5000);

                std::cout << " finished" << std::endl;
d.kilic's avatar
d.kilic committed
            }
            else
            { // wenn keine Dateiendung, dann wird trc und txt herausgeschrieben
                exportTracker(dest + ".trc");
                exportTracker(dest + ".txt");
            }
            lastFile = dest;
        }
    }
}

// fuer anschliessende groessenberechnung
void Petrack::playAll()
{
    int memPos = mPlayerWidget->getPos();
    int progVal = 0;

    QProgressDialog progress("Playing whole sequence...", "Abort playing", 0, mAnimation->getNumFrames(), this);
    progress.setWindowModality(Qt::WindowModal); // blocks main window

    // vorwaertslaufen ab aktueller Stelle und trackOnlineCalc zum tracken nutzen
    do
    {
        progress.setValue(++progVal); //mPlayerWidget->getPos()
        qApp->processEvents();
        if (progress.wasCanceled())
            break;
    }
    while (mPlayerWidget->frameForward());

    mPlayerWidget->skipToFrame(memPos);
}

/**
 * @brief Activates tracking and reco; calcs through the video (in both ways)
 *
 * This method activates tracking and reco and plays the whole video (from current
 * frame on) till the end. Then, if mAutoBackTrack is set, it jumps back to the
 * largest first frame, i.e. the last time a new person was added/recognized, and
 * tracks backwards till the beginning of the video.
 *
 * The old settings for tracking and reco will be restored. No interaction with the
 * main window is possible for the time of tracking.
 */
d.kilic's avatar
d.kilic committed
void Petrack::trackAll()
{
    int memPos = mPlayerWidget->getPos();
    int progVal = 0;
    enum Qt::CheckState memCheckState = mControlWidget->trackOnlineCalc->checkState();
    enum Qt::CheckState memRecoState = mControlWidget->performRecognition->checkState();

    mControlWidget->trackOnlineCalc->setCheckState(Qt::Checked);
    mControlWidget->performRecognition->setCheckState(Qt::Checked);

    QProgressDialog progress("Tracking pedestrians through all frames...", "Abort tracking", 0, 2*mAnimation->getNumFrames()-memPos, this);
    progress.setWindowModality(Qt::WindowModal); // blocks main window

    // vorwaertslaufen ab aktueller Stelle und trackOnlineCalc zum tracken nutzen
    do
    {
        progress.setValue(++progVal); //mPlayerWidget->getPos()
        qApp->processEvents();
        if (progress.wasCanceled())
            break;
    }
    while (mPlayerWidget->frameForward());

    if (mAutoBackTrack)
    {
        // zuruecksprinegn an die stelle, wo der letzte trackPath nicht vollstaendig
        // etwas spaeter, da erste punkte in reco path meist nur ellipse ohne markererkennung
        mControlWidget->trackOnlineCalc->setCheckState(Qt::Unchecked);
        mPlayerWidget->skipToFrame(mTracker->largestFirstFrame()+5);
        mControlWidget->trackOnlineCalc->setCheckState(Qt::Checked);
        //progVal = 2*mAnimation->getNumFrames()-memPos-mPlayerWidget->getPos();
        progVal += mAnimation->getNumFrames()-mPlayerWidget->getPos();
        progress.setValue(progVal); //mPlayerWidget->getPos()

        // recognition abstellen, bis an die stelle, wo trackAll begann
        // UEBERPRUEFEN, OB TRACKPATH NICHT RECOGNITION PUNKTE UEBERSCHREIBT!!!!!!!!!!
        // repeate und repaetQual koennte temporaer umgestellt werden
        mControlWidget->performRecognition->setCheckState(Qt::Unchecked);

        // rueckwaertslaufen
        do
        {
            if (progVal+1 < 2*mAnimation->getNumFrames()-memPos)
                progress.setValue(++progVal); //mPlayerWidget->getPos()
            qApp->processEvents();
            if (progress.wasCanceled())
                break;
            if (mPlayerWidget->getPos() == memPos+1)
                mControlWidget->performRecognition->setCheckState(Qt::Checked);
        }
        while (mPlayerWidget->frameBackward());

        // bei abbruch koennen es auch mPlayerWidget->getPos() frames sein, die bisher geschrieben wurden
        progress.setValue(2*mAnimation->getNumFrames()-memPos);
    }

    if (mAutoTrackOptimizeColor)
        mTracker->optimizeColor();

    mControlWidget->performRecognition->setCheckState(memRecoState);
    mControlWidget->trackOnlineCalc->setCheckState(Qt::Unchecked);
    mPlayerWidget->skipToFrame(memPos);
    mControlWidget->trackOnlineCalc->setCheckState(memCheckState);
}

// default: (QPointF *pos=NULL, int pers=-1, int frame=-1);
int Petrack::winSize(QPointF *pos, int pers, int frame, int level)
{
    // default of mControlWidget->trackRegionScale->value() is 16, so that
    // a factor of 1.6 of the headsize is used
    if (level == -1)
        level = mControlWidget->trackRegionLevels->value();
    return (int)((getHeadSize(pos, pers, frame) / pow(2.,level)) * (mControlWidget->trackRegionScale->value() / 10.));
}

void Petrack::updateImage(bool imageChanged) // default = false (only true for new animation frame)
{

#ifdef TIME_MEASUREMENT
    // die reine Ausgabe  folgender Zeile kostet 1-2 Millisekunden
    //        "==========: "