Skip to content
Snippets Groups Projects
petrack.cpp 156 KiB
Newer Older
        if(!dest.isEmpty())
d.kilic's avatar
d.kilic committed
        {
            QList<int> pers, frame;
            bool autoCorrectOnlyExport = (mReco.getRecoMethod() == reco::RecognitionMethod::MultiColor) && // multicolor
                                         mMultiColorMarkerWidget->autoCorrect->isChecked() &&
                                         mMultiColorMarkerWidget->autoCorrectOnlyExport->isChecked();
d.kilic's avatar
d.kilic committed

            if(dest.right(4) == ".trc")
d.kilic's avatar
d.kilic committed
            {
#ifdef TIME_MEASUREMENT
                double time1 = 0.0, tstart;
                tstart       = clock();
d.kilic's avatar
d.kilic committed
#endif
                QTemporaryFile file;

                if(!file.open() /*!file.open(QIODevice::WriteOnly | QIODevice::Text)*/)
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;
                }
d.kilic's avatar
d.kilic committed
                QProgressDialog progress(
                    "Export TRC-File", nullptr, 0, static_cast<int>(mPersonStorage.nbPersons() + 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();

                trcVersion = 4;
d.kilic's avatar
d.kilic committed

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

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

d.kilic's avatar
d.kilic committed
                tstart = clock();
#endif
                progress.setLabelText(QString("Save file ..."));
                qApp->processEvents();

                if(QFile::exists(dest))
d.kilic's avatar
d.kilic committed
                    QFile::remove(dest);
d.kilic's avatar
d.kilic committed

                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
d.kilic's avatar
d.kilic committed
                    statusBar()->showMessage(tr("Saved tracking data to %1.").arg(dest), 5000);
d.kilic's avatar
d.kilic committed

d.kilic's avatar
d.kilic committed
                progress.setValue(static_cast<int>(mPersonStorage.nbPersons() + 1));
d.kilic's avatar
d.kilic committed

                std::cout << " finished " << std::endl;
                mAutosave.resetTrackPersonCounter();
d.kilic's avatar
d.kilic committed

#ifdef TIME_MEASUREMENT
                time1 += clock() - tstart;
                time1 = time1 / CLOCKS_PER_SEC;
d.kilic's avatar
d.kilic committed
                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
d.kilic's avatar
d.kilic committed
            }
            else if(dest.right(4) == ".txt")
d.kilic's avatar
d.kilic committed
            {
                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 << " (" << mPersonStorage.nbPersons() << " person(s))..."
d.kilic's avatar
d.kilic committed

#ifdef TIME_MEASUREMENT
                double time1 = 0.0, tstart;
                tstart       = clock();
d.kilic's avatar
d.kilic committed
#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())
d.kilic's avatar
d.kilic committed
                {
                    if(mControlWidget->getCalibCoordDimension() == 0) // 3D
                        ; // Nothing to be done because z already the right height
                        mPersonStorage.recalcHeight(mControlWidget->coordAltitude->value());
d.kilic's avatar
d.kilic committed
                }
#ifdef TIME_MEASUREMENT
                time1 += clock() - tstart;
                time1 = time1 / CLOCKS_PER_SEC;
d.kilic's avatar
d.kilic committed
                cout << "  time(recalcHeight) = " << time1 << " sec." << endl;

d.kilic's avatar
d.kilic committed
                tstart = clock();
                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);
d.kilic's avatar
d.kilic committed
#ifdef TIME_MEASUREMENT
                time1 += clock() - tstart;
                time1 = time1 / CLOCKS_PER_SEC;
d.kilic's avatar
d.kilic committed
                cout << "  time(calculate) = " << time1 << " sec." << endl;

d.kilic's avatar
d.kilic committed
                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())
d.kilic's avatar
d.kilic committed
                {
                    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 < static_cast<int>(mPersonStorage.nbPersons()); ++i)
d.kilic's avatar
d.kilic committed
                    {
                        auto commentSplit = mPersonStorage.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 QString &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;
d.kilic's avatar
d.kilic committed
                file.flush();
                file.close();

                if(QFile::exists(dest))
d.kilic's avatar
d.kilic committed
                    QFile::remove(dest);
d.kilic's avatar
d.kilic committed

                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
d.kilic's avatar
d.kilic committed
                    statusBar()->showMessage(tr("Saved tracking data to %1.").arg(dest), 5000);
d.kilic's avatar
d.kilic committed

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

#ifdef TIME_MEASUREMENT
                time1 += clock() - tstart;
                time1 = time1 / CLOCKS_PER_SEC;
d.kilic's avatar
d.kilic committed
                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")
d.kilic's avatar
d.kilic committed
            {
                QTemporaryFile fileDat;

                if(!fileDat.open()) //! fileDat.open(QIODevice::WriteOnly | QIODevice::Text))
d.kilic's avatar
d.kilic committed
                {
                    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())
d.kilic's avatar
d.kilic committed
                {
                    mPersonStorage.recalcHeight(mControlWidget->coordAltitude->value());
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);

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

                if(QFile::exists(dest))
d.kilic's avatar
d.kilic committed
                    QFile::remove(dest);
d.kilic's avatar
d.kilic committed

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

                std::cout << " finished" << std::endl;
d.kilic's avatar
d.kilic committed
            }
            else if(dest.right(5) == ".trav")
d.kilic's avatar
d.kilic committed
            {
                // 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())
d.kilic's avatar
d.kilic committed
                {
                    mPersonStorage.recalcHeight(mControlWidget->coordAltitude->value());
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);
d.kilic's avatar
d.kilic committed

                QTemporaryFile fileXml;
                if(!fileXml.open()) //! fileXml.open(QIODevice::WriteOnly | QIODevice::Text))
d.kilic's avatar
d.kilic committed
                {
                    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 << " (" << mPersonStorage.nbPersons() << " person(s))..."
                       << std::endl;
                // already done: mTrackerReal->calculate(mTracker, mImageItem, mControlWidget->getColorPlot(),
                // getImageBorderSize(), mControlWidget->trackMissingFrames->checkState());
d.kilic's avatar
d.kilic committed
                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>" << mPersonStorage.nbPersons() << "</agents>" << Qt::endl;
                outXml << "        <frameRate>" << mAnimation->getFPS() << "</frameRate> <!--per second-->" << Qt::endl;
                // 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;

                mTrackerReal->exportXml(
                    outXml,
                    mControlWidget->trackAlternateHeight->checkState(),
                    mStereoWidget->stereoUseForExport->isChecked());
d.kilic's avatar
d.kilic committed

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

                if(QFile::exists(dest))
d.kilic's avatar
d.kilic committed
                    QFile::remove(dest);
d.kilic's avatar
d.kilic committed

                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
d.kilic's avatar
d.kilic committed
                    statusBar()->showMessage(tr("Saved tracking data to %1.").arg(dest), 5000);
d.kilic's avatar
d.kilic committed

                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");
            }
            mLastTrackerExport = dest;
d.kilic's avatar
d.kilic committed
        }
    }
}

// fuer anschliessende groessenberechnung
void Petrack::playAll()
{
    int memPos  = mPlayerWidget->getPos();
d.kilic's avatar
d.kilic committed
    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()
d.kilic's avatar
d.kilic committed
        qApp->processEvents();
        if(progress.wasCanceled())
d.kilic's avatar
d.kilic committed
            break;
    } while(mPlayerWidget->frameForward());
d.kilic's avatar
d.kilic committed

    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;
d.kilic's avatar
d.kilic committed
    enum Qt::CheckState memCheckState = mControlWidget->trackOnlineCalc->checkState();
    enum Qt::CheckState memRecoState  = mControlWidget->performRecognition->checkState();
d.kilic's avatar
d.kilic committed

    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);
d.kilic's avatar
d.kilic committed
    progress.setWindowModality(Qt::WindowModal); // blocks main window

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

    if(mAutoBackTrack)
d.kilic's avatar
d.kilic committed
    {
        // 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(mPersonStorage.largestFirstFrame() + 5);
d.kilic's avatar
d.kilic committed
        mControlWidget->trackOnlineCalc->setCheckState(Qt::Checked);
        // progVal = 2*mAnimation->getNumFrames()-memPos-mPlayerWidget->getPos();
        progVal += mAnimation->getNumFrames() - mPlayerWidget->getPos();
        progress.setValue(progVal); // mPlayerWidget->getPos()
d.kilic's avatar
d.kilic committed

        // 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()
d.kilic's avatar
d.kilic committed
            qApp->processEvents();
            if(progress.wasCanceled())
d.kilic's avatar
d.kilic committed
                break;
            if(mPlayerWidget->getPos() == memPos + 1)
d.kilic's avatar
d.kilic committed
                mControlWidget->performRecognition->setCheckState(Qt::Checked);
        } while(mPlayerWidget->frameBackward());
d.kilic's avatar
d.kilic committed

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

    if(mAutoTrackOptimizeColor)
        mPersonStorage.optimizeColor();
d.kilic's avatar
d.kilic committed

    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)
d.kilic's avatar
d.kilic committed
        level = mControlWidget->trackRegionLevels->value();
    return (int) ((getHeadSize(pos, pers, frame) / pow(2., level)) * (mControlWidget->trackRegionScale->value() / 10.));
d.kilic's avatar
d.kilic committed
}

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
    //        "==========: "
    debout << "go  update: " << getElapsedTime() << endl;
d.kilic's avatar
d.kilic committed
#endif

    mCodeMarkerItem->resetSavedMarkers();

    static int  lastRecoFrame            = -10000;
d.kilic's avatar
d.kilic committed
    static bool borderChangedForTracking = false;
d.kilic's avatar
d.kilic committed
    // need semaphore to guarrantee that updateImage only called once
    // updateValue of control automatically calls updateImage!!!
    static QSemaphore semaphore(1);
    if(!mImg.empty() && mImage && semaphore.tryAcquire())
d.kilic's avatar
d.kilic committed
    {
        int frameNum = mAnimation->getCurrentFrameNum();

        setStatusTime();

        updateShowFPS();

        mImgFiltered = mImg;

        // have to store because evaluation sets the filter parameter to unchanged
        bool brightContrastChanged = mBrightContrastFilter.changed();
        bool swapChanged           = mSwapFilter.changed();
        bool borderChanged         = mBorderFilter.changed();
        bool calibChanged          = mCalibFilter->changed();
d.kilic's avatar
d.kilic committed

        // speicherverwaltung wird komplett von filtern ueberneommen

        // Filter anwenden, Reihenfolge wichtig - Rechenintensive moeglichst frueh
        // fkt so nur mit kopierenden filtern
#ifdef TIME_MEASUREMENT
        //        "==========: "
        debout << "vor filter: " << getElapsedTime() << endl;
d.kilic's avatar
d.kilic committed
#endif

        if(imageChanged || swapChanged)
d.kilic's avatar
d.kilic committed
            mImgFiltered = mSwapFilter.apply(mImgFiltered);
d.kilic's avatar
d.kilic committed
        else
d.kilic's avatar
d.kilic committed
            mImgFiltered = mSwapFilter.getLastResult();
d.kilic's avatar
d.kilic committed

        if(imageChanged || swapChanged || brightContrastChanged)
d.kilic's avatar
d.kilic committed
            mImgFiltered = mBrightContrastFilter.apply(mImgFiltered);
d.kilic's avatar
d.kilic committed
        else
d.kilic's avatar
d.kilic committed
            mImgFiltered = mBrightContrastFilter.getLastResult();
d.kilic's avatar
d.kilic committed

        if(imageChanged || swapChanged || brightContrastChanged || borderChanged)
d.kilic's avatar
d.kilic committed
            mImgFiltered = mBorderFilter.apply(mImgFiltered); // mIplImg
d.kilic's avatar
d.kilic committed
        else
d.kilic's avatar
d.kilic committed
            mImgFiltered = mBorderFilter.getLastResult();
d.kilic's avatar
d.kilic committed

#ifdef TIME_MEASUREMENT
        //        "==========: "
        debout << "nch filter: " << getElapsedTime() << endl;
d.kilic's avatar
d.kilic committed
#endif
        if(borderChanged)
d.kilic's avatar
d.kilic committed
            updateControlImage(mImgFiltered);
#ifndef STEREO_DISABLED
        if(imageChanged || swapChanged || brightContrastChanged || borderChanged || calibChanged)
d.kilic's avatar
d.kilic committed
        {
            if(mStereoContext)
d.kilic's avatar
d.kilic committed
                mStereoContext->init(mImgFiltered);
        }
d.kilic's avatar
d.kilic committed

#ifdef TIME_MEASUREMENT
        //        "==========: "
        debout << "vor  calib: " << getElapsedTime() << endl;
d.kilic's avatar
d.kilic committed
#endif
        if(imageChanged || swapChanged || brightContrastChanged || borderChanged || calibChanged)
d.kilic's avatar
d.kilic committed
            mImgFiltered = mCalibFilter->apply(mImgFiltered);
d.kilic's avatar
d.kilic committed
        else
d.kilic's avatar
d.kilic committed
            mImgFiltered = mCalibFilter->getLastResult();
d.kilic's avatar
d.kilic committed

#ifdef TIME_MEASUREMENT
        //        "==========: "
        debout << "nach calib: " << getElapsedTime() << endl;
d.kilic's avatar
d.kilic committed
#endif

        if(brightContrastChanged || swapChanged || borderChanged || calibChanged)
d.kilic's avatar
d.kilic committed
        {
            // abfrage hinzugenommen, damit beim laden von .pet bg-file angegeben werden kann fuer mehrere versuche und
            // beim nachladen von versuch nicht bg geloescht wird
            if(mBackgroundFilter.getFilename() != "")
                debout << "Warning: No background reset, because of explicit loaded background image!" << std::endl;
d.kilic's avatar
d.kilic committed
            else
                mBackgroundFilter
                    .reset(); // alle gesammelten hintergrundinfos werden verworfen und bg.changed auf true gesetzt
d.kilic's avatar
d.kilic committed
        }

        if(imageChanged || mBackgroundFilter.changed())
d.kilic's avatar
d.kilic committed
            mImgFiltered = mBackgroundFilter.apply(mImgFiltered);
d.kilic's avatar
d.kilic committed
        else
d.kilic's avatar
d.kilic committed
            mImgFiltered = mBackgroundFilter.getLastResult();
d.kilic's avatar
d.kilic committed

#ifdef TIME_MEASUREMENT
        //        "==========: "
        debout << "nach    bg: " << getElapsedTime() << endl;
d.kilic's avatar
d.kilic committed
#endif

        // delete track list, if intrinsic param have changed
        if(calibChanged && mPersonStorage.nbPersons() > 0) // mCalibFilter.getEnabled() &&
d.kilic's avatar
d.kilic committed
        {
            // Evtl. nicht Tracker loeschen sondern entsprechend der neuen Calibration verschieben?!?!?
            mPersonStorage.clear();
d.kilic's avatar
d.kilic committed
            mTracker->reset();
            if(!isLoading())
                debout << "Warning: deleted all tracking pathes because intrinsic parameters have changed."
                       << std::endl;
d.kilic's avatar
d.kilic committed
        }
        else
        {
#ifndef STEREO_DISABLED
d.kilic's avatar
d.kilic committed
            // calculate position in 3D space and height of person for "old" trackPoints, if checked "even"
            if(mStereoContext && mStereoWidget->stereoUseForHeightEver->isChecked() &&
               mStereoWidget->stereoUseForHeight->isChecked())
d.kilic's avatar
d.kilic committed
            {
                // buildt disparity picture if it should be used for height detection
                mStereoContext->getDisparity();

                mPersonStorage.calcPosition(frameNum);
d.kilic's avatar
d.kilic committed
            }
d.kilic's avatar
d.kilic committed
        }
        if(borderChanged)
d.kilic's avatar
d.kilic committed
            borderChangedForTracking = true;
d.kilic's avatar
d.kilic committed
        // tracking vor recognition, da dann neu gefundene punkte mit getrackten bereits ueberprueft werden koennen
        if((trackChanged() || imageChanged) &&
           (mControlWidget->trackOnlineCalc->checkState() == Qt::Checked)) // borderChanged ???
d.kilic's avatar
d.kilic committed
        {
            // Rect for tracking area
            QRect roi(
                myRound(mTrackingRoiItem->rect().x() + getImageBorderSize()),
                myRound(mTrackingRoiItem->rect().y() + getImageBorderSize()),
                myRound(mTrackingRoiItem->rect().width()),
                myRound(mTrackingRoiItem->rect().height()));
d.kilic's avatar
d.kilic committed

            if(borderChangedForTracking)
d.kilic's avatar
d.kilic committed
            {
                size.width  = mImgFiltered.cols;
d.kilic's avatar
d.kilic committed
                size.height = mImgFiltered.rows;
                mTracker->resize(size);

d.kilic's avatar
d.kilic committed
            }
#ifndef STEREO_DISABLED
d.kilic's avatar
d.kilic committed
            // buildt disparity picture if it should be used for height detection
            if(mStereoContext && mStereoWidget->stereoUseForHeight->isChecked())
d.kilic's avatar
d.kilic committed
                mStereoContext->getDisparity();
d.kilic's avatar
d.kilic committed

d.kilic's avatar
d.kilic committed
            getRoi(mImgFiltered, roi, rect);
            // Ignore all tracking points outside of rect

            // if (mPrevIplImgFiltered) // wenn ein vorheriges bild vorliegt
            //  mPrevIplImgFiltered == NULL zeigt an, dass neue bildfolge && mPrevFrame == -1 ebenso
            //  winSize(), wurde mal uebergeben
d.kilic's avatar
d.kilic committed
#ifdef TIME_MEASUREMENT
            debout << "vor  track: " << getElapsedTime() << endl;
d.kilic's avatar
d.kilic committed
#endif
            //            debout << "test" << endl;
            int anz = mTracker->track(
                mImgFiltered,
                rect,
                frameNum,
                mControlWidget->trackRepeat->isChecked(),
                mControlWidget->trackRepeatQual->value(),
                getImageBorderSize(),
                mReco.getRecoMethod(),
                mControlWidget->trackRegionLevels->value(),
                getPedestriansToTrack());
d.kilic's avatar
d.kilic committed
#ifdef TIME_MEASUREMENT
            debout << "nach track: " << getElapsedTime() << endl;
d.kilic's avatar
d.kilic committed
#endif
            mControlWidget->trackNumberNow->setText(QString("%1").arg(anz));
            mTrackChanged            = false;
d.kilic's avatar
d.kilic committed
            borderChangedForTracking = false;
        }
        else
d.kilic's avatar
d.kilic committed
            mControlWidget->trackNumberNow->setText(QString("0"));
d.kilic's avatar
d.kilic committed
        // hier muesste fuer ameisen etc allgemeinABC.getPosList(...)

        if(((((lastRecoFrame + mControlWidget->recoStep->value()) <= frameNum) ||
             ((lastRecoFrame - mControlWidget->recoStep->value()) >= frameNum)) &&
            imageChanged) ||
           mAnimation->isCameraLiveStream() || swapChanged || brightContrastChanged || borderChanged || calibChanged ||
           recognitionChanged())
d.kilic's avatar
d.kilic committed
        {
#ifndef STEREO_DISABLED
d.kilic's avatar
d.kilic committed
            // buildt disparity picture if it should be used for height detection or recognition
            if(mStereoContext &&
               (mStereoWidget->stereoUseForHeight->isChecked() || mStereoWidget->stereoUseForReco->isChecked()))
d.kilic's avatar
d.kilic committed
                mStereoContext->getDisparity(); // wird nicht neu berechnet, wenn vor tracking schon berechnet wurde
            if(borderChanged)
                mRecognitionRoiItem->restoreSize();
            if(mControlWidget->performRecognition->checkState() == Qt::Checked)
d.kilic's avatar
d.kilic committed
            {
                QRect rect(
                    myRound(mRecognitionRoiItem->rect().x() + getImageBorderSize()),
                    myRound(mRecognitionRoiItem->rect().y() + getImageBorderSize()),
                    myRound(mRecognitionRoiItem->rect().width()),
                    myRound(mRecognitionRoiItem->rect().height()));
d.kilic's avatar
d.kilic committed
                QList<TrackPoint> persList;
                auto              recoMethod = mReco.getRecoMethod();
d.kilic's avatar
d.kilic committed
#ifdef TIME_MEASUREMENT
                //        "==========: "
                debout << "vor   reco: " << getElapsedTime() << endl;
d.kilic's avatar
d.kilic committed
#endif
                if((recoMethod == reco::RecognitionMethod::Casern) || (recoMethod == reco::RecognitionMethod::Hermes) ||
                   (recoMethod == reco::RecognitionMethod::Color) || (recoMethod == reco::RecognitionMethod::Japan) ||
                   (recoMethod == reco::RecognitionMethod::MultiColor) ||
                   (recoMethod == reco::RecognitionMethod::Code)) // else
                    persList = mReco.getMarkerPos(
                        mImgFiltered, rect, mControlWidget, getImageBorderSize(), getBackgroundFilter());
d.kilic's avatar
d.kilic committed
                }
#ifndef STEREO_DISABLED
                if(mStereoContext && mStereoWidget->stereoUseForReco->isChecked())
d.kilic's avatar
d.kilic committed
                {
                    PersonList pl;
                    pl.calcPersonPos(mImgFiltered, rect, &persList, mStereoContext, getBackgroundFilter(), markerLess);
d.kilic's avatar
d.kilic committed
                }
d.kilic's avatar
d.kilic committed
#ifdef TIME_MEASUREMENT
                //        "==========: "
                debout << "nach  reco: " << getElapsedTime() << endl;
d.kilic's avatar
d.kilic committed
#endif
                mPersonStorage.addPoints(persList, frameNum, mReco.getRecoMethod());
d.kilic's avatar
d.kilic committed
                // folgendes lieber im Anschluss, ggf beim exportieren oder statt test direkt del:
                if(mStereoContext && mStereoWidget->stereoUseForReco->isChecked())
                    mPersonStorage.purge(frameNum); // bereinigen wenn weniger als 0.2 recognition und nur getrackt
d.kilic's avatar
d.kilic committed

                mControlWidget->recoNumberNow->setText(QString("%1").arg(persList.size()));
                mRecognitionChanged = false;
                if(false) // hier muss Abfage hin ob kasernen marker genutzt wird
                    mControlWidget->getColorPlot()
                        ->replot(); // oder nur wenn tab offen oder wenn sich mtracker geaendert hat???
d.kilic's avatar
d.kilic committed
            }
            else
d.kilic's avatar
d.kilic committed
                mControlWidget->recoNumberNow->setText(QString("0"));
d.kilic's avatar
d.kilic committed
            lastRecoFrame = frameNum;
        }
        else
d.kilic's avatar
d.kilic committed
            mControlWidget->recoNumberNow->setText(QString("0"));
d.kilic's avatar
d.kilic committed

        mControlWidget->trackNumberAll->setText(
            QString("%1").arg(mPersonStorage.nbPersons())); // kann sich durch reco und tracker aendern
        mControlWidget->trackShowOnlyNr->setMaximum(
d.kilic's avatar
d.kilic committed
            static_cast<int>(MAX(mPersonStorage.nbPersons(), 1))); // kann sich durch reco und tracker aendern
        mControlWidget->trackNumberVisible->setText(
            QString("%1").arg(mPersonStorage.visible(frameNum))); // kann sich durch reco und tracker aendern
d.kilic's avatar
d.kilic committed

        // in anzuzeigendes Bild kopieren
        // erst hier wird die bildgroesse von mimage an filteredimg mit border angepasst
        copyToQImage(*mImage, mImgFiltered);
d.kilic's avatar
d.kilic committed

        if(borderChanged)
d.kilic's avatar
d.kilic committed
            mImageItem->setImage(mImage);
d.kilic's avatar
d.kilic committed
        else
        {
            getScene()->update(); // repaint();
            qApp->processEvents();
d.kilic's avatar
d.kilic committed
            // update pixel color (because image pixel moves)
            setStatusColor();
        }

#ifdef QWT
        mControlWidget->getAnalysePlot()->setActFrame(frameNum);
        if(mControlWidget->anaMarkAct->isChecked())
d.kilic's avatar
d.kilic committed
        {
            mControlWidget->getAnalysePlot()->replot();
        }
#endif

        semaphore.release();
    }
#ifdef TIME_MEASUREMENT
    //        "==========: "
    debout << "stp update: " << getElapsedTime() << endl;
d.kilic's avatar
d.kilic committed
#endif
}
void Petrack::updateImage(const cv::Mat &img)
d.kilic's avatar
d.kilic committed
{
    mImg = img;
    updateImage(true);
}


void Petrack::updateSequence()
{
    QImage *oldImage = mImage;

    QSize size = mAnimation->getSize();
    size.setWidth(size.width() + 2 * getImageBorderSize()); // border is inside the mImage!
    size.setHeight(size.height() + 2 * getImageBorderSize());
    mImage = new QImage(size, QImage::Format_RGB888); // 32); //wird in updateImage gemacht
d.kilic's avatar
d.kilic committed

    // set roi for recognition if image size changes or roi is zero
    // in oldImage steckt border drin, mIplImg->height zeigt noch auf altes ursprungsbild
d.kilic's avatar
d.kilic committed
    // mRecognitionRoiItem->rect().width() != 0 && oldImage == NULL wenn projektdatei eingelesen wird!!!!!
    if((mRecognitionRoiItem->rect().width() == 0) || // default while initialization, after that >= MIN_SIZE
       (oldImage && ((oldImage->width() != mImage->width()) || (oldImage->height() != mImage->height()))))
d.kilic's avatar
d.kilic committed
        mRecognitionRoiItem->setRect(-getImageBorderSize(), -getImageBorderSize(), mImage->width(), mImage->height());
    if((mTrackingRoiItem->rect().width() == 0) ||
       (oldImage && ((oldImage->width() != mImage->width()) || (oldImage->height() != mImage->height()))))
d.kilic's avatar
d.kilic committed
        mTrackingRoiItem->setRect(-getImageBorderSize(), -getImageBorderSize(), mImage->width(), mImage->height());
d.kilic's avatar
d.kilic committed

    size2.width  = mTrackingRoiItem->rect().width();
d.kilic's avatar
d.kilic committed
    size2.height = mTrackingRoiItem->rect().height();
    mTracker->init(size2);

    mPlayerWidget->setAnim(mAnimation);
    mPlayerWidget->skipToFrame(0);
    mImageItem->setImage(mImage); // wird in updateImage gemacht
d.kilic's avatar
d.kilic committed
    delete oldImage;
    mSaveSeqVidAct->setEnabled(true);
    mSaveSeqVidViewAct->setEnabled(true);
    mSaveSeqImgAct->setEnabled(true);
    mSaveSeqViewAct->setEnabled(true);
    mSaveImageAct->setEnabled(true);
    mSaveViewAct->setEnabled(true);
    mPrintAct->setEnabled(true);
    mResetSettingsAct->setEnabled(true);
}


/**
 * @brief Gets cm per pixel. Only recalculates when calculating head size.
 * @return cm per pixel
 */
double Petrack::getCmPerPixel() const
d.kilic's avatar
d.kilic committed
{
    return mCmPerPixel;
}

/**
 * @brief Sets the size of the circle of the average head circumference in pixel.
 *
 * Assumption for default calculation: <br>
 * 21cm avg head length <br>
 * default height of person according to mapDefaultHeigt <br>
 *
 * Default case recalculates mCmPerPixel
 *
 * If headsize get recalulated also mCmPerPixel will be calculated!
 * @param hS new headsize, if hS==-1 mHeadSize will be calculated instead of set
d.kilic's avatar
d.kilic committed
void Petrack::setHeadSize(double hS)
{
d.kilic's avatar
d.kilic committed
    {
        mCmPerPixel = getImageItem()->getCmPerPixel();
        // debout << mCmPerPixel <<endl;
        mHeadSize = (HEAD_SIZE * mControlWidget->coordAltitude->value() /
                     (mControlWidget->coordAltitude->value() - mControlWidget->mapDefaultHeight->value())) /
                    mCmPerPixel;
d.kilic's avatar
d.kilic committed
    }
    else
d.kilic's avatar
d.kilic committed
        mHeadSize = hS;
d.kilic's avatar
d.kilic committed
}
// gibt Kopfgroesse zurueck
// default: (QPointF *pos=NULL, int pers=-1, int frame=-1)
double Petrack::getHeadSize(QPointF *pos, int pers, int frame)
{
    double z, h;

    if((pers >= 0) && (pers < static_cast<int>(mPersonStorage.nbPersons())) &&
       mPersonStorage.at(pers).trackPointExist(frame))
d.kilic's avatar
d.kilic committed
    {
        if(mControlWidget->getCalibCoordDimension() == 0)
d.kilic's avatar
d.kilic committed
        {
            int         diff;
            cv::Point3f p3d = getExtrCalibration()->get3DPoint(
                cv::Point2f(
                    mPersonStorage.at(pers).trackPointAt(frame).x(), mPersonStorage.at(pers).trackPointAt(frame).y()),
                mControlWidget->mapDefaultHeight->value());

            cv::Point2f p3d_x1 =
                getExtrCalibration()->getImagePoint(cv::Point3f(p3d.x + HEAD_SIZE * 0.5, p3d.y, p3d.z));
            cv::Point2f p3d_x2 =
                getExtrCalibration()->getImagePoint(cv::Point3f(p3d.x - HEAD_SIZE * 0.5, p3d.y, p3d.z));
            cv::Point2f p3d_y1 =
                getExtrCalibration()->getImagePoint(cv::Point3f(p3d.x, p3d.y + HEAD_SIZE * 0.5, p3d.z));
            cv::Point2f p3d_y2 =
                getExtrCalibration()->getImagePoint(cv::Point3f(p3d.x, p3d.y - HEAD_SIZE * 0.5, p3d.z));

            diff = (int) std::max(
                sqrt(pow(p3d_x2.x - p3d_x1.x, 2) + pow(p3d_x2.y - p3d_x1.y, 2)),
                sqrt(pow(p3d_y2.x - p3d_y1.x, 2) + pow(p3d_y2.y - p3d_y1.y, 2)));
            return diff; // < 8 ? 8 : diff;
        }
        else
d.kilic's avatar
d.kilic committed
        {
            z = mPersonStorage.at(pers).trackPointAt(frame).sp().z();
            h = mPersonStorage.at(pers).height();
                return (HEAD_SIZE * mControlWidget->coordAltitude->value() / z) / getImageItem()->getCmPerPixel();
            else if(h > MIN_HEIGHT)
                return (HEAD_SIZE * mControlWidget->coordAltitude->value() /
                        (mControlWidget->coordAltitude->value() - h)) /
                       getImageItem()->getCmPerPixel();
d.kilic's avatar
d.kilic committed
            else
d.kilic's avatar
d.kilic committed
                return mHeadSize;
d.kilic's avatar
d.kilic committed
        }
    }