Skip to content
Snippets Groups Projects
petrack.cpp 180 KiB
Newer Older
d.kilic's avatar
d.kilic committed

    if (!dest.isEmpty() && mImage)
    {
        int rest = mAnimation->getNumFrames()-1;
        int numLength = 1;
        int memPos = mPlayerWidget->getPos();
        QString fileName = "";
#ifdef AVI
        AviFile aviFile;
#else
        AviFileWriter aviFile;
#endif
        //CvVideoWriter* videoWriter;
        //using namespace cv; oder cv::VideoWriter *vw;
        bool formatIsSaveAble = false;
        bool saveRet;
        QImage *viewImage = NULL; // =NULL, amit keine Warnung
        QPainter *painter = NULL; // =NULL, amit keine Warnung
        int progEnd = /*mAnimation->getNumFrames()-1*/mAnimation->getSourceOutFrameNum()-mPlayerWidget->getPos(); // nur wenn nicht an anfang gesprungen wird:-mPlayerWidget->getPos()
        Mat iplImgFilteredBGR;
        bool writeFrameRet = false;
        bool convert8To24bit = false;
        int mult;


        if (saveVideo)
        {
            //            //
            //            // Retreive the number of compressors.
            //            //
            //            int iNumCompressors = aviFile.enumerateCompressors(mIplImgFiltered->height, mIplImgFiltered->width, 8*mIplImgFiltered->nChannels, NULL, 0);
            //
            //            if(iNumCompressors)
            //            {
            //                ICINFO* picinfo = new ICINFO[iNumCompressors];
            //                COMPVARS* comp = new COMPVARS[iNumCompressors];
            //                char *c;
            //
            //                //
            //                // Retreive information about these compressors.
            //                //
            //                aviFile.enumerateCompressors(mIplImgFiltered->height, mIplImgFiltered->width, 8*mIplImgFiltered->nChannels, picinfo, iNumCompressors);
            //
            //                for (int i=0; i<iNumCompressors; i++)
            //                {
            //                    c = (char*) &(picinfo[i].fccHandler);
            //                    debout << c[0] << c[1] << c[2] << c[3] << " " << (char *) picinfo[i].szName << endl;
            //                    comp[i].cbSize = picinfo[i].dwSize;
            //                    //comp[i].lQ = 100.; //picinfo[i].;
            //                    comp[i].dwFlags = picinfo[i].dwFlags;
            //                    comp[i].fccHandler = picinfo[i].fccHandler;
            //                    comp[i].fccType = picinfo[i].fccType;
            //                    //comp[i].cbState = ;
            //                    //comp[i].lpState = ;
            //                }
            //
            //                //
            //                // Set the compressor to the first one found.
            //                //
            //                //aviFile.setCompressor(comp);
            //
            //                delete [] picinfo;
            //            }

            if (saveView)
            {
                if (mCropZoomViewAct->isChecked())
                    viewImage = new QImage(mView->viewport()->width(), mView->viewport()->height(), QImage::Format_RGB32);
                else
                    viewImage = new QImage((int) mScene->width(), (int) mScene->height(), QImage::Format_RGB32);
                painter = new QPainter();
            }
            //CvSize size;
            //size.width =  mIplImgFiltered->width;
            //size.height = mIplImgFiltered->height;
            if (convert8To24bit)
                mult = 3;
            else
                mult = 1;

            //debout << "width: " << mIplImgFiltered->width << " height: " << mIplImgFiltered->height << endl;
            //debout << "width: " << mView->viewport()->width() << " height: " << mView->viewport()->height() << endl;
            //debout << "width: " << mScene->width() << " height: " << mScene->height() << endl;
            //debout << "channels: " << mIplImgFiltered->nChannels << endl;
//            debout << "viewImage: " << viewImage->depth() << endl;

            bool ok = false;

            if( saveView )
                ok = aviFile.open(dest.toStdString().c_str(), viewImage->width(), viewImage->height(), viewImage->depth(), mAnimation->getFPS());
            else
                ok = aviFile.open(dest.toStdString().c_str(), mImg.cols, mImg.rows, mult*8*mImg.channels(), mAnimation->getFPS());
            ////vw = new cv::VideoWriter;
            ////vw->open(dest.toStdString().c_str(), CV_FOURCC_DEFAULT, mAnimation->getFPS(), size);
            //// -1 muss unter linux durch CV_FOURCC('P','I','M','1') ist mpeg1 oder CV_FOURCC('M','J','P','G') ersetzt werden oder CV_FOURCC_DEFAULT
            //// CV_FOURCC('D','I','B',' ') == 0 bedeutet rgb unkomprimiert - siehe http://opencvlibrary.sourceforge.net/VideoCodecs
            //if (autoSave)
            //    videoWriter = cvCreateVideoWriter(dest.toStdString().c_str(), CV_FOURCC_DEFAULT, mAnimation->getFPS(), size); //, int is_color=1
            //else
            //    videoWriter = cvCreateVideoWriter(dest.toStdString().c_str(), 0, mAnimation->getFPS(), size); //, int is_color=1
            //// if codec is not supported or no codec is selected
            //if (!videoWriter)
            //    return;
            if (!ok)
            {
                debout << "Error: opening AVI file: " << dest.toStdString().c_str() << endl;
                return;
            }
        }

        //         mPlayerWidget->skipToFrame(0); // koennte man auch weglassen, dann wurde von aktueller pos film geschrieben!!!

        if (!saveVideo)
        {
            if (saveView)
            {
                if (mCropZoomViewAct->isChecked())
                    viewImage = new QImage(mView->viewport()->width(), mView->viewport()->height(), QImage::Format_RGB32);
                else
                    viewImage = new QImage((int) mScene->width(), (int) mScene->height(), QImage::Format_RGB32);
                painter = new QPainter();
            }

            // test, if fileformat is supported
            if (mAnimation->isVideo())
            {
                // calculate string length of sequence number
                while ((rest/=10) > 0)
                    numLength++;
                fileName = (dest + "/" + mAnimation->getFileBase() + "%1.png").arg(mPlayerWidget->getPos(), numLength, 10, QChar('0'));
            }
            else
                fileName = dest + "/" + mAnimation->getCurrentFileName();

            if (saveView)
            {
                painter->begin(viewImage);
                if (mCropZoomViewAct->isChecked())
                    mView->render(painter);
                else
                    mScene->render(painter);
                painter->end();

                if (viewImage->save(fileName)) //, const char * format = 0 (format wird aus dateinamen geholt), int quality = -1 default normal (0..100)
                {
                    formatIsSaveAble = true;
                    mPlayerWidget->frameForward();
                }
            }
            else if (mImage->save(fileName)) //, const char * format = 0 (format wird aus dateinamen geholt), int quality = -1 default normal (0..100)
            {
                formatIsSaveAble = true;
                mPlayerWidget->frameForward();
            }
        }
        else if ((mImgFiltered.channels() == 1)  /*&& convert8To24bit*/)
        {
            Size size;
            size.width = mImgFiltered.cols;
            size.height = mImgFiltered.rows;
            iplImgFilteredBGR.create(size, CV_8UC3);
        }

        QProgressDialog progress("", "Abort save", 0, progEnd, this);
        progress.setWindowModality(Qt::WindowModal); // blocks main window

        if (saveVideo)
        {
            if (saveView)
                progress.setLabelText("Save video view...");
            else
                progress.setLabelText("Save video...");
        }else
        {
            if (saveView)
                progress.setLabelText("Save view sequence...");
            else
                progress.setLabelText("Save image sequence...");
        }


        do
        {
            progress.setValue(mPlayerWidget->getPos()-memPos); // -mempos nur, wenn nicht an den anfang gesprungen wird
            qApp->processEvents();
            if (progress.wasCanceled())
                break;

            if (saveVideo)
            {
                // video sequence
                if (saveView)
                {
                    painter->begin(viewImage);
                    if (mCropZoomViewAct->isChecked())
                        mView->render(painter);
                    else
                        mScene->render(painter);
                    painter->end();
                }
//                debout << "nChannels: " << mIplImgFiltered->nChannels << endl;
                if ((mImgFiltered.channels() == 1) /* && convert8To24bit*/)
                {
                    //cvCvtColor(mIplImgFiltered, iplImgFilteredBGR, CV_GRAY2BGR);
                    cvtColor(mImg, iplImgFilteredBGR, COLOR_GRAY2BGR);
d.kilic's avatar
d.kilic committed
                    if( saveView )
                        writeFrameRet = aviFile.appendFrame((const unsigned char*) viewImage->bits(), true); // 2. param besagt, ob vertikal gespiegel werden soll
                    else
                        writeFrameRet = aviFile.appendFrame((const unsigned char*) iplImgFilteredBGR.data, true); // 2. param besagt, ob vertikal gespiegel werden soll
                }
                else
                {
                    if( saveView ){
//                        debout << "." << endl;
                        writeFrameRet = aviFile.appendFrame((const unsigned char*) viewImage->bits(), true); // 2. param besagt, ob vertikal gespiegel werden soll
                    }else{
                        writeFrameRet = aviFile.appendFrame((const unsigned char*) mImg.data, true); // 2. param besagt, ob vertikal gespiegel werden soll
                    }
                }

                if (!writeFrameRet)
                {
                    progress.setValue(progEnd);
                    QMessageBox::critical(this, tr("PeTrack"), tr("Cannot save %1 maybe because of wrong file extension or unsupported codec.").arg(dest));
                    break;
                }
            }
            else
            {
                // single frame sequence
                if (saveView)
                {
                    painter->begin(viewImage);
                    if (mCropZoomViewAct->isChecked())
                        mView->render(painter);
                    else
                        mScene->render(painter);
                    painter->end();
                }
                if (mAnimation->isVideo())
                {
                    fileName = (dest + "/" + mAnimation->getFileBase() + "%1.png").arg(mPlayerWidget->getPos(), numLength, 10, QChar('0'));
                    if (saveView)
                        saveRet = viewImage->save(fileName);
                    else
                        saveRet = mImage->save(fileName);
                }
                else if (formatIsSaveAble)
                {
                    fileName = dest + "/" + mAnimation->getCurrentFileName();
                    if (saveView)
                        saveRet = viewImage->save(fileName);
                    else
                        saveRet = mImage->save(fileName);
                }
                else
                {
                    fileName = dest + "/" + QFileInfo(mAnimation->getCurrentFileName()).completeBaseName() + ".png";
                    if (saveView)
                        saveRet = viewImage->save(fileName);
                    else
                        saveRet = mImage->save(fileName, "PNG"); //, int quality = -1 default normal (0..100)
                }
                if (!saveRet)
                {
                    progress.setValue(progEnd);
                    QMessageBox::critical(this, tr("PeTrack"), tr("Cannot save %1.").arg(fileName));
                    break;
                }
            }
        }
        while (mPlayerWidget->frameForward());

        if (!saveVideo && saveView)
        {
            delete viewImage;
            delete painter;
        }

        // bei abbruch koennen es auch mPlayerWidget->getPos() frames sein, die bisher geschrieben wurden
        //-memPos nur, wenn nicht an den anfang gesprungen wird
        debout << "wrote " << mPlayerWidget->getPos()+1-memPos << " of " << mAnimation->getNumFrames() << " frames." << endl;
        progress.setValue(progEnd);

        if (saveVideo)
        {
            aviFile.close();
            //cvReleaseVideoWriter(&videoWriter);
//            if (iplImgFilteredBGR)
//                cvReleaseImage(&iplImgFilteredBGR);
        }

        mPlayerWidget->skipToFrame(memPos);
        lastDir = dest;
    }
}

/**
 * @brief Saves the current View, including visualizations, in a file (.g. pdf)
 *
 * @param dest name of the saved file; if empty, a dialogue for the user opens
 */
d.kilic's avatar
d.kilic committed
void Petrack::saveView(QString dest) //default = ""
{
    static QString lastFile;

    if(mImage)
    {
        // if no destination file or folder is given
        if (dest.isEmpty())
        {
            if (lastFile.isEmpty() && !mSeqFileName.isEmpty())
                lastFile = QFileInfo(mSeqFileName).path();

            // alle unetrstuetzen fileformate erhaelt man mit
            // QImageReader::supportedImageFormats() and QImageWriter::supportedImageFormats()
            // gif muss nicht dabei sein, dazu muss qt mit -qt-gif uebersetzt worden sein
            dest = QFileDialog::getSaveFileName(this, tr("Select image file"), lastFile,
                                                tr("PDF (*.pdf);;Postscript (*.ps *.eps);;Windows bitmaps (*.bmp);;JPEG (*.jpeg *.jpg);;Portable network graphics (*.png);;Portable image format (*.pbm *.pgm *.ppm);;X11 Bitmap or Pixmap (*.xbm *.xpm);;Pixel Images (*.bmp *.jpeg *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm);;All supported types (*pdf *ps *.eps *.bmp *.jpeg *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm);;All files (*.*)"));
        }

        if (!dest.isEmpty())
        {
            if (dest.right(4) == ".pdf" || dest.right(3) == ".ps" || dest.right(4) == ".eps")
            {
                QPrinter printer(QPrinter::ScreenResolution); // HighResolution?
                printer.setColorMode(QPrinter::Color);
                //printer.setPageSize(QPrinter::A4);
                //printer.setOutputFormat(QPrinter::PdfFormat); //QPrinter::PostScriptFormat automatisch durch dateiendung
                printer.setOutputFileName(dest);
                QPainter painter(&printer);
                if (mCropZoomViewAct->isChecked())
                    mView->render(&painter);
                else
                    mScene->render(&painter);
            }
            else
            {
                // schwarzer rand links und unten?!
                QImage *img;
                if (mCropZoomViewAct->isChecked())
                    img = new QImage(mView->viewport()->width(), mView->viewport()->height(), QImage::Format_RGB32);
                else
                    img = new QImage((int) mScene->width(), (int) mScene->height(), QImage::Format_RGB32);
                QPainter painter(img);
                if (mCropZoomViewAct->isChecked())
                    mView->render(&painter);
                else
                    mScene->render(&painter);
                painter.end();
                if (!img->save(dest)) //, "PNG"
                    QMessageBox::critical(this, tr("PeTrack"), tr("Cannot save %1 maybe because of wrong file extension.").arg(dest));
                delete img;
            }
            lastFile = dest;
        }
    }
}

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

    if(mImage)
    {
        // if no destination file or folder is given
        if (dest.isEmpty())
        {
            if (lastFile.isEmpty() && !mSeqFileName.isEmpty())
                lastFile = QFileInfo(mSeqFileName).path();


            // alle unetrstuetzen fileformate erhaelt man mit
            // QImageReader::supportedImageFormats() and QImageWriter::supportedImageFormats()
            // gif muss nict dabei sein, dazu muss qt mit -qt-gif uebesetz worden sein
            dest = QFileDialog::getSaveFileName(this, tr("Select image file"), lastFile,
                                                tr("PDF (*.pdf);;Postscript (*.ps *.eps);;Windows bitmaps (*.bmp);;JPEG (*.jpeg *.jpg);;Portable network graphics (*.png);;Portable image format (*.pbm *.pgm *.ppm);;X11 Bitmap or Pixmap (*.xbm *.xpm);;Pixel Images (*.bmp *.jpeg *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm);;All supported types (*pdf *ps *.eps *.bmp *.jpeg *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm);;All files (*.*)"));
        }

        if (!dest.isEmpty())
        {
            if (dest.right(4) == ".pdf" || dest.right(3) == ".ps" || dest.right(4) == ".eps")
            {

                QPrinter printer(QPrinter::ScreenResolution); // HighResolution?
                printer.setColorMode(QPrinter::Color);
                //printer.setPageSize(QPrinter::A4);
                //printer.setOutputFormat(QPrinter::PdfFormat); //QPrinter::PostScriptFormat automatisch durch dateiendung
                printer.setOutputFileName(dest);
                QPainter painter(&printer);
                QRect rect = painter.viewport();
                QSize size = mImage->size();
                size.scale(rect.size(), Qt::KeepAspectRatio);
                painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
                painter.setWindow(mImage->rect());
                painter.drawImage(0, 0, *mImage);
            }
            else
            {
                if (!mImage->save(dest)) //, "PNG"
                    QMessageBox::critical(this, tr("PeTrack"), tr("Cannot save %1 maybe because of wrong file extension.").arg(dest));
            }
            lastFile = dest;
        }
    }
}

void Petrack::print()
{
    if(mImage)
    {
        // HighResolution font zu gross! und laengere laufzeit und eher overflow
        // aber so pixelig und keine schoenen linien
        QPrinter printer(QPrinter::ScreenResolution); //ScreenResolution, HighResolution// liefert zu hause: QWin32PrintEngine::initialize: GetPrinter failed ()
        printer.setPageSize(QPageSize{QPageSize::PageSizeId::A4});
d.kilic's avatar
d.kilic committed
        QPrintDialog dialog(&printer, this);
        //printer.setOutputFormat(QPrinter::PostScriptFormat);
        if (dialog.exec()) {
            QPainter painter(&printer);
            mView->render(&painter);

            //             QRect rect = painter.viewport();
            //             QSize size = imageWidget->pixmap()->size();
            //             size.scale(rect.size(), Qt::KeepAspectRatio);
            //             painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
            //             painter.setWindow(imageWidget->pixmap()->rect());
            //             painter.drawPixmap(0, 0, *imageWidget->pixmap());
            // // print the upper half of the viewport into the lower.
            //  // half of the page.
            //  QRect viewport = view.viewport()->rect();
            //  view.render(&painter,
            //              QRectF(0, printer.height() / 2,
            //                     printer.width(), printer.height() / 2),
            //              viewport.adjusted(0, 0, 0, -viewport.height() / 2));
        }
    }
    else
        QMessageBox::critical(this, tr("PeTrack"), tr("Nothing to print!"));
}

void Petrack::resetSettings()
{
    mAnimation->reset();
    openXml(mDefaultSettings);
//    resetUI();
}

void Petrack::about()
{
    //People/Pedestrian/Person tracking
    QMessageBox::about(this, tr("About PeTrack"),
                       tr("<p><b>PeTrack</b> - Pedestrian tracking<br>" //&nbsp;&nbsp;&nbsp;&nbsp;
                          "Version " VERSION "<br>"
                          "(Build " COMPILE_DATE " " COMPILE_TIME ")</p>"
                          "<p>by Maik Boltes, Daniel Salden<br>"
                          "&copy; Forschungszentrum Juelich GmbH</p>"));
    //©  &copy; &#169; (c)
    // folgender befehl wird erst nach About-Fenster ausgefuehrt und ersetzt Icon im Hauptfenster
    //QApplication::activeWindow()->setWindowIcon(QIcon(":/icon"));
    // siehe auch Petrack::Petrack()
}


void Petrack::commandLineOptions()
{
    //QTextBrowser(this);
    //static QMessageBox* mb = NULL;
    //if (mb == NULL)
    //{
    QMessageBox* mb = new QMessageBox(this); //QMessageBox mb(this);
    mb->setAttribute(Qt::WA_DeleteOnClose);
    mb->setWindowTitle(tr("Command line options"));
    //mb->setWindowModality(Qt::NonModal);
    mb->setModal(false); // if you want it non-modal
    mb->setText(commandLineOptionsString);
    mb->setStandardButtons(QMessageBox::Ok);
    //}

    //"<style>spantab {padding-left: 4em; margin-left:5em}</style><span class=\"tab\"></span>"
    //"<p>Only to convert a video <kbd>video.avi</kbd> with settings stored in a petrack project file <kbd>project.pet</kbd> to an image sequence to be stored in the directory <kbd>folder</kbd> call:<br>"
    //"<code>petrack.exe -project project.pet </code><br>"
    //"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>-sequence video.avi </code><br>"
    //"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>-autoSave folder</code></p>"
    //To generate trajectories from a single image sequence frame000.jpg to frame345.jpg
    //with settings stored in project.pet, export tracker file tracker_file and exit
    //with saving the project to project.pet again:
    //petrack.exe -project project.pet -sequence frame000.jpg -autoTrack tracker_file -autoSave project.pet
    //For more information (especially key bindings) see http://www.fz-juelich.de/jsc/petrack/.
    //Normal usage is interactive usage.



    mb->show(); //mb->exec(); //mb->open();

    //    QMessageBox::about(this, tr("Command line options"), tr(
//"Beside the space bar all bindings only affect inside the image.<p>"
//"Space bar<br>blavbla"));

//Usage: petrack [-help|-?] [[-project] project.pet] [-sequence image_sequence_or_video] [-autoSave|-autosave image_folder_or_video|project.pet|tracker_file] [-autoTrack|-autotrack tracker_file] [-autoPlay|-autoplay tracker_file]

//Usage:
//    ------
//    petrack [-help|-?] [[-project] project.pet] [-sequence image_sequence_or_video] [-autoSave|-autosave image_folder_or_video|project.pet|tracker_file] [-autoTrack|-autotrack tracker_file] [-autoPlay|-autoplay tracker_file]

//    -help|-? shows help information for command line options
//    -project optional option to set project file to project.pet; otherwise the argument without option flag is used as project file
//    -sequence loads image sequence or video image_sequence_or_video; option overwrites SRC attribute in project file
//    -autoSave|-autosave if the argument ends with pet, a project file will be written to proj.pet at the end;
//        if the argument ends with txt, dat or trav, the trajectories will be written in a format according to the suffix of tracker_file;
//        otherwise image_folder_or_video is the folder to store the image sequence or a name of a video file for the direct export;
//        in all cases PeTrack ends after finishing the work
//    -autoTrack|-autotrack calculates automatically the trajectories of marked pedestrians and stores the result to tracker_file
//    -autoPlay|-autoplay plays the video or image sequence and stores the trajectories to tracker_file

}

void Petrack::keyBindings()
{
    QMessageBox* mb = new QMessageBox(this);
    mb->setAttribute(Qt::WA_DeleteOnClose);
    mb->setWindowTitle(tr("Command line options"));
    mb->setModal(false); // if you want it non-modal
    mb->setText(tr(
"<p>Beside the space bar all bindings only affect inside the image.</p>"
"<dl><dt><kbd>Space bar</kbd></dt><dd>toggles between pause and last play direction</dd>"
"<dt><kbd>Mouse scroll wheel</kbd></dt><dd>zooms in and out to or from the pixel of the image at the position of the mouse pointer</dd>"
"<dt><kbd>Shift + mouse scroll wheel</kbd></dt><dd>plays forwards or backwards frame by frame</dd>"
"<dt><kbd>Holding left mouse button</kbd></dt><dd>moves image</dd>"
"<dt><kbd>Arrows up/down</kbd></dt><dd>zoom in/out</dd>"
"<dt><kbd>Arrows left/right</kbd></dt><dd>frame back/forward</dd>"
"<dt><kbd>Double-click left mouse button</kbd></dt><dd>opens video or image sequence</dd>"
"<dt><kbd>Ctrl + double-click left mouse button</kbd></dt><dd>inserts new or moves near trackpoint</dd>"
"<dt><kbd>Ctrl + Shift + double-click left mouse button</kbd></dt><dd>splits near trackpoint before actual frame</dd>"
"<dt><kbd>Ctrl + double-click right mouse button</kbd></dt><dd>deletes a trajectory of a near trackpoint</dd>"
"<dt><kbd>Shift + double-click right mouse button</kbd></dt><dd>deletes the past part of a trajectory of a near trackpoint</dd>"
"<dt><kbd>Alt + double-click right mouse button</kbd></dt><dd>deletes the future part of a trajectory of a near trackpoint</dd>"
"<dt><kbd>Ctrl + double-click middle mouse button</kbd></dt><dd>deletes all trajectories</dd>"
"<dt><kbd>Shift + double-click middle mouse button</kbd></dt><dd>deletes the past part of all trajectories</dd>"
"<dt><kbd>Alt + double-click middle mouse button</kbd></dt><dd>deletes the future part of all trajectories</dd>"
"<dt><kbd>Shift + t</kbd></dt><dd>toggles tracking online calculation</dd>"
"<dt><kbd>Shift + double-click left mouse button</kbd></dt><dd>inserts new or moves near trackpoint and enables showing only the modified trajectory</dd></dl>"
"<p>Further key bindings you will find next to the entries of the menus.</p>"
                    ));

//"Beside the space bar all bindings only affect inside the image.<p>"
//"Space bar<br>"
//"    toggles between pause and last play direction<br>"
//"Mouse scroll wheel<br>"
//"    zooms in and out to or from the pixel of the image at the position of the mouse pointer<br>"
//"Shift + mouse scroll wheel<br>"
//"    plays forwards or backwards<br>"
//"Holding left mouse button<br>"
//"    moves image<br>"
//"Arrows<br>"
//"    moves image<br>"
//"Double-click left mouse button<br>"
//"    opens video or image sequence<br>"
//"Ctrl + double-click left mouse button<br>"
//"    inserts new or moves near trackpoint<br>"
//"Ctrl + double-click right mouse button<br>"
//"    deletes a trajectory of a near trackpoint<br>"
//"Shift + double-click right mouse button<br>"
//"    deletes the past part of a trajectory of a near trackpoint<br>"
//"Alt + double-click right mouse button<br>"
//"    deletes the future part of a trajectory of a near trackpoint<br>"
//"Ctrl + double-click middle mouse button<br>"
//"    deletes all trajectories<br>"
//"Shift + double-click middle mouse button<br>"
//"    deletes the past part of all trajectories<br>"
//"Alt + double-click middle mouse button<br>"
//"    deletes the future part of all trajectories<br>"
//"Shift + t<br>"
//"    toggles tracking online calculation<br>"
//"Shift + double-click left mouse button<br>"
//"    inserts new or moves near trackpoint and enables showing only the modified trajectory<p>"
//"Further key bindings you will find next to the entries of the menus."

    mb->setStandardButtons(QMessageBox::Ok);
    mb->show();
    //QMessageBox::about(NULL, tr("Key bindings"), tr(
}

void Petrack::onlineHelp()
{
    static QUrl url("https://jugit.fz-juelich.de/ped-dyn-emp/petrack/-/wikis/home");
d.kilic's avatar
d.kilic committed
    if (!(QDesktopServices::openUrl(url)))
        QMessageBox::critical(this, tr("PeTrack"), tr("Cannot open external browser<br>with url ") + url.toString() + "!");
}

void Petrack::antialias()
{
    mView->setRenderHint(QPainter::Antialiasing, mAntialiasAct->isChecked());
}
void Petrack::opengl()
{
    mView->setViewport(mOpenGLAct->isChecked() ? new QGLWidget(QGLFormat(QGL::SampleBuffers)) : new QWidget);

    // alten freigeben wegen new????
}
void Petrack::reset()
{
    mViewWidget->resetView();
}
void Petrack::fitInView()
{
    mViewWidget->fitInView();
}
void Petrack::fitInROI()
{
    mViewWidget->fitInROI(getRecoRoiItem()->rect());
    // what about trackingRoi???
}
void Petrack::setGlobalFont()
{
    bool ok;
    QFont font = QFontDialog::getFont(&ok, this->font(), this);
    if (ok) {
        this->setFont(font); // font is set to the font the user selected
    } else {
        // the user canceled the dialog; font is set to the initial
        // value, in this case Times, 12.
    }
    //static QFont font("Courier", 10, QFont::Normal); //Times Helvetica, Normal Bold // QFont("Times", 12)
    //this->setFont(font);
}

void Petrack::showHideControlWidget()
{
    // show | hide Control
    mViewWidget->hideControls(mHideControlsAct->isChecked());
}

void Petrack::setCamera()
{
#ifndef STEREO_DISABLED
d.kilic's avatar
d.kilic committed
    if (mAnimation)
    {
        if (mCameraLeftViewAct->isChecked())
        {
            if ((mAnimation->getCamera()) != cameraLeft)
                mAnimation->setCamera(cameraLeft); // war: hier wird direkt bei Umstellung neu gelesen
            else
                return;
        }
        else if (mCameraRightViewAct->isChecked())
        {
            if ((mAnimation->getCamera()) != cameraRight)
                mAnimation->setCamera(cameraRight); // war: hier wird direkt bei Umstellung neu gelesen
            else
                return;
        }
        else // kann eigentlich nicht vorkommen
        {
            mAnimation->setCamera(cameraUnset);
            return;
        }
        updateImage(mAnimation->getFrameAtIndex(mAnimation->getCurrentFrameNum())); // wird nur aufgerufen, wenn left / right sich geaendert hat
        //mPlayerWidget->updateImage();
        //mPlayerWidget->skipToFrame(mPlayerWidget->getPos()); // machtpasue!!
        //updateImage(true); // nur dies aufrufen, wenn nicht links rechts gleichzeitig gehalten wird
    }
d.kilic's avatar
d.kilic committed
}

/**
 * @brief Helper function to create Actions for the menu bar
 * @see Petrack::createMenus()
 */
d.kilic's avatar
d.kilic committed
void Petrack::createActions()
{
    mOpenSeqAct = new QAction(tr("&Open Sequence"), this);
    mOpenSeqAct->setShortcut(tr("Ctrl+Shift+O"));
    connect(mOpenSeqAct, SIGNAL(triggered()), this, SLOT(openSequence()));

    mOpenCameraAct = new QAction(tr("Open Camera Stream"), this);
    //mOpenCameraAct->setShortcut(tr("Ctrl+C")); // because of some reason it is sometimes fired with Ctrl+LeftMouseButton ==> so disabled (it's also not really needed)
    connect(mOpenCameraAct, SIGNAL(triggered()), this, SLOT(openCameraLiveStream()));

    mSaveSeqVidAct = new QAction(tr("Save Video"), this);
    //mSaveSeqVidAct->setShortcut(tr("Ctrl+E"));
    mSaveSeqVidAct->setEnabled(false);
    connect(mSaveSeqVidAct, SIGNAL(triggered()), this, SLOT(saveVideo()));

    mSaveSeqVidViewAct = new QAction(tr("Save Video View"), this);
    mSaveSeqVidViewAct->setShortcut(tr("Ctrl+E"));
    mSaveSeqVidViewAct->setEnabled(false);
    connect(mSaveSeqVidViewAct, SIGNAL(triggered()), this, SLOT(saveVideoView()));

    mSaveSeqImgAct = new QAction(tr("Save Image S&equence"), this);
    mSaveSeqImgAct->setShortcut(tr("Ctrl+F"));
    mSaveSeqImgAct->setEnabled(false);
    connect(mSaveSeqImgAct, SIGNAL(triggered()), this, SLOT(saveImageSequence()));

    mSaveSeqViewAct = new QAction(tr("Save View S&equence"), this);
    //    mSaveSeqViewAct->setShortcut(tr("Ctrl+F"));
    mSaveSeqViewAct->setEnabled(false);
    connect(mSaveSeqViewAct, SIGNAL(triggered()), this, SLOT(saveViewSequence()));

    mOpenPrAct = new QAction(tr("&Open Project"), this);
    mOpenPrAct->setShortcut(tr("Ctrl+O"));
    connect(mOpenPrAct, SIGNAL(triggered()), this, SLOT(openProject()));

    mSavePrAct = new QAction(tr("&Save Project As"), this);
    mSavePrAct->setShortcut(tr("Ctrl+Shift+S"));
    connect(mSavePrAct, SIGNAL(triggered()), this, SLOT(saveProject()));

    mSaveAct = new QAction(tr("&Save Project"), this);
    mSaveAct->setShortcut(tr("Ctrl+S"));
    connect(mSaveAct, SIGNAL(triggered()), this, SLOT(saveSameProject()));

    mSaveImageAct = new QAction(tr("&Save Image"), this);
    mSaveImageAct->setShortcut(tr("Ctrl+I"));
    mSaveImageAct->setEnabled(false);
    connect(mSaveImageAct, SIGNAL(triggered()), this, SLOT(saveImage()));

    mSaveViewAct = new QAction(tr("&Save View"), this);
    mSaveViewAct->setShortcut(tr("Ctrl+V"));
    mSaveViewAct->setEnabled(false);
    connect(mSaveViewAct, SIGNAL(triggered()), this, SLOT(saveView()));

    mPrintAct = new QAction(tr("&Print"), this);
    mPrintAct->setShortcut(tr("Ctrl+P"));
    mPrintAct->setEnabled(false);
    connect(mPrintAct, SIGNAL(triggered()), this, SLOT(print()));

    mResetSettingsAct = new QAction(tr("&Reset Settings"), this);
//    mResetSettingsAct->setShortcut(tr("Ctrl+R"));
    mResetSettingsAct->setEnabled(false); // da es noch nicht fehlerfrei funktioniert
    connect(mResetSettingsAct, SIGNAL(triggered()), this, SLOT(resetSettings()));

    mExitAct = new QAction(tr("E&xit"), this);
    mExitAct->setShortcut(tr("Ctrl+Q"));
    connect(mExitAct, SIGNAL(triggered()), this, SLOT(close()));

    mAntialiasAct = new QAction(tr("&Antialias"), this);
    mAntialiasAct->setShortcut(tr("Ctrl+A"));
    mAntialiasAct->setCheckable(true);
    connect(mAntialiasAct, SIGNAL(triggered()), this, SLOT(antialias()));

    mFontAct = new QAction(tr("&Font"), this);
    connect(mFontAct, SIGNAL(triggered()), this, SLOT(setGlobalFont()));

    mHideControlsAct = new QAction(tr("&Hide controls"), this);
    mHideControlsAct->setShortcut(tr("Ctrl+H"));
    mHideControlsAct->setCheckable(true);
    connect(mHideControlsAct, SIGNAL(triggered()), this, SLOT(showHideControlWidget()));
    connect(mHideControlsAct, SIGNAL(changed()),this, SLOT(showHideControlWidget()));

    mCropZoomViewAct = new QAction(tr("&Transform while saving"), this); //Crop and zoom while saving
    mCropZoomViewAct->setCheckable(true);

    mOpenGLAct = new QAction(tr("Open&GL"), this);
    mOpenGLAct->setShortcut(tr("Ctrl+G"));
    mOpenGLAct->setCheckable(true);
    connect(mOpenGLAct, SIGNAL(triggered()), this, SLOT(opengl()));

    mResetAct = new QAction(tr("&Reset"), this);
    mResetAct->setShortcut(tr("Ctrl+R"));
    connect(mResetAct, SIGNAL(triggered()), this, SLOT(reset()));

    mFitViewAct = new QAction(tr("Fit in window"), this); // Resize to window; fit in view; show all; in fenster einpassen
    mFitViewAct->setShortcut(tr("Ctrl+0"));
    connect(mFitViewAct, SIGNAL(triggered()), this, SLOT(fitInView()));

    mFitROIAct = new QAction(tr("Fit in region of interest"), this); // Resize ROI to window; fit in view;
    mFitROIAct->setShortcut(tr("Ctrl+1"));
    connect(mFitROIAct, SIGNAL(triggered()), this, SLOT(fitInROI()));

    mCameraGroupView = new QActionGroup(this);
    //mCameraGroupView->addAction(mCameraLeftViewAct);
    //mCameraGroupView->addAction(mCameraRightViewAct);
    mCameraLeftViewAct = new QAction(tr("&Left"), mCameraGroupView);
    mCameraLeftViewAct->setShortcut(tr("Ctrl++Shift+L"));
    mCameraLeftViewAct->setCheckable(true);
    connect(mCameraLeftViewAct, SIGNAL(triggered()), this, SLOT(setCamera()));
    mCameraRightViewAct = new QAction(tr("&Right"), mCameraGroupView);
    mCameraRightViewAct->setShortcut(tr("Ctrl++Shift+R"));
    mCameraRightViewAct->setCheckable(true);
    connect(mCameraRightViewAct, SIGNAL(triggered()), this, SLOT(setCamera()));
    mCameraRightViewAct->setChecked(true); // right wird als default genommen, da reference image in triclops auch right ist // erste trj wurden mit left gerechnet

    mLimitPlaybackSpeed = new QAction(tr("&Limit playback speed"));
    // Not checkable like Fix since this is also controlled through clicking on FPS and syncing currently would be bothersome
    connect(mLimitPlaybackSpeed, &QAction::triggered, mPlayerWidget, [&](){mPlayerWidget->setPlayerSpeedLimited(!mPlayerWidget->getPlayerSpeedLimited());});
    mFixPlaybackSpeed = new QAction(tr("&Fix playback speed"));
    mFixPlaybackSpeed->setCheckable(true);
    connect(mFixPlaybackSpeed, &QAction::toggled, mPlayerWidget, &Player::setPlayerSpeedFixed);
    mSetToRealtime = new QAction(tr("&Realtime"));
    connect(mSetToRealtime, &QAction::triggered, mPlayerWidget, [&](){mPlayerWidget->setSpeedRelativeToRealtime(1.0);});
    mSetTo2p00 = new QAction(tr("&x2"));
    connect(mSetTo2p00, &QAction::triggered, mPlayerWidget, [&](){mPlayerWidget->setSpeedRelativeToRealtime(2.0);});
    mSetTo1p75 = new QAction(tr("&x1.75"));
    connect(mSetTo1p75, &QAction::triggered, mPlayerWidget, [&](){mPlayerWidget->setSpeedRelativeToRealtime(1.75);});
    mSetTo1p50 = new QAction(tr("&x1.5"));
    connect(mSetTo1p50, &QAction::triggered, mPlayerWidget, [&](){mPlayerWidget->setSpeedRelativeToRealtime(1.5);});
    mSetTo1p25 = new QAction(tr("&x1.25"));
    connect(mSetTo1p25, &QAction::triggered, mPlayerWidget, [&](){mPlayerWidget->setSpeedRelativeToRealtime(1.25);});
    mSetTo0p75 = new QAction(tr("&x0.75"));
    connect(mSetTo0p75, &QAction::triggered, mPlayerWidget, [&](){mPlayerWidget->setSpeedRelativeToRealtime(0.75);});
    mSetTo0p50 = new QAction(tr("&x0.5"));
    connect(mSetTo0p50, &QAction::triggered, mPlayerWidget, [&](){mPlayerWidget->setSpeedRelativeToRealtime(0.5);});
    mSetTo0p25 = new QAction(tr("&x0.25"));
    connect(mSetTo0p25, &QAction::triggered, mPlayerWidget, [&](){mPlayerWidget->setSpeedRelativeToRealtime(0.25);});
d.kilic's avatar
d.kilic committed

    mPlayerLooping = new QAction(tr("&Loop"));
    mPlayerLooping->setCheckable(true);
    connect(mPlayerLooping, &QAction::triggered, mPlayerWidget, &Player::setLooping);
d.kilic's avatar
d.kilic committed
    // -------------------------------------------------------------------------------------------------------

    QSignalMapper* signalMapper = new QSignalMapper(this);

    mDelPastAct = new QAction(tr("&Past part of all trj."), this);
    connect(mDelPastAct, SIGNAL(triggered()), signalMapper, SLOT(map()));
    signalMapper->setMapping(mDelPastAct, -1);
    connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(deleteTrackPointAll(int))); // -1

    mDelFutureAct = new QAction(tr("&Future part of all trj."), this);
    connect(mDelFutureAct, SIGNAL(triggered()), signalMapper, SLOT(map()));
    signalMapper->setMapping(mDelFutureAct, 1);
    connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(deleteTrackPointAll(int))); // 1

    mDelAllRoiAct = new QAction(tr("&Trj. moving through ROI"), this);
    connect(mDelAllRoiAct, SIGNAL(triggered()), this, SLOT(deleteTrackPointROI()));
    mDelPartRoiAct = new QAction(tr("Part of Trj. inside &ROI"), this);
    connect(mDelPartRoiAct, SIGNAL(triggered()), this, SLOT(deleteTrackPointInsideROI()));

    // -------------------------------------------------------------------------------------------------------

    mCommandAct = new QAction(tr("&Command line options"), this);
    connect(mCommandAct, SIGNAL(triggered()), this, SLOT(commandLineOptions()));

    mKeyAct = new QAction(tr("&Key bindings"), this);
    connect(mKeyAct, SIGNAL(triggered()), this, SLOT(keyBindings()));

    mAboutAct = new QAction(tr("&About"), this);
    connect(mAboutAct, SIGNAL(triggered()), this, SLOT(about()));

    mOnlineHelpAct = new QAction(tr("Online &Help"), this);
    mOnlineHelpAct->setShortcut(tr("Ctrl+H"));
    connect(mOnlineHelpAct, SIGNAL(triggered()), this, SLOT(onlineHelp()));
}

/**
 * @brief Helper function building menues out of QActions
 * @see Petrack::createActions()
 */
d.kilic's avatar
d.kilic committed
void Petrack::createMenus()
{
    mFileMenu = new QMenu(tr("&File"), this);
    mFileMenu->addAction(mOpenPrAct);
    mFileMenu->addAction(mSaveAct);
    mFileMenu->addAction(mSavePrAct);
    mFileMenu->addSeparator();
    mFileMenu->addAction(mOpenSeqAct);
    mFileMenu->addAction(mOpenCameraAct);
    mFileMenu->addAction(mSaveSeqVidAct);
    mFileMenu->addAction(mSaveSeqVidViewAct);
    mFileMenu->addAction(mSaveImageAct);
    mFileMenu->addAction(mSaveSeqImgAct);
    mFileMenu->addAction(mSaveViewAct);
    mFileMenu->addAction(mSaveSeqViewAct);
    mFileMenu->addAction(mPrintAct);
    mFileMenu->addSeparator();
    mFileMenu->addAction(mResetSettingsAct);
    mFileMenu->addSeparator();
    mFileMenu->addAction(mExitAct);

    mViewMenu = new QMenu(tr("&View"), this);
    mViewMenu->addAction(mAntialiasAct);
    mViewMenu->addAction(mOpenGLAct);
    mViewMenu->addAction(mCropZoomViewAct);
    mCameraMenu = mViewMenu->addMenu(tr("&Camera"));
    mCameraMenu->addAction(mCameraLeftViewAct);
    mCameraMenu->addAction(mCameraRightViewAct);
    mViewMenu->addAction(mFixPlaybackSpeed);
    mViewMenu->addAction(mLimitPlaybackSpeed);
    mPlaybackSpeedMenu = mViewMenu->addMenu(tr("&Playback speed"));
    mPlaybackSpeedMenu->addAction(mSetToRealtime);
    mPlaybackSpeedMenu->addAction(mSetTo2p00);
    mPlaybackSpeedMenu->addAction(mSetTo1p75);
    mPlaybackSpeedMenu->addAction(mSetTo1p50);
    mPlaybackSpeedMenu->addAction(mSetTo1p25);
    mPlaybackSpeedMenu->addAction(mSetTo0p75);
    mPlaybackSpeedMenu->addAction(mSetTo0p50);
    mPlaybackSpeedMenu->addAction(mSetTo0p25);
d.kilic's avatar
d.kilic committed
    mViewMenu->addAction(mPlayerLooping);
d.kilic's avatar
d.kilic committed
    mViewMenu->addSeparator();
    mViewMenu->addAction(mFitViewAct);
    mViewMenu->addAction(mFitROIAct);
    mViewMenu->addAction(mResetAct);
    mViewMenu->addSeparator();
    mViewMenu->addAction(mFontAct);
    mViewMenu->addSeparator();
    mViewMenu->addAction(mHideControlsAct);

    mDeleteMenu = new QMenu(tr("&Delete"), this);
    mDeleteMenu->addAction(mDelPastAct);
    mDeleteMenu->addAction(mDelFutureAct);
    mDeleteMenu->addAction(mDelAllRoiAct);
    mDeleteMenu->addAction(mDelPartRoiAct);

    mHelpMenu = new QMenu(tr("&Help"), this);
    mHelpMenu->addAction(mCommandAct);
    mHelpMenu->addAction(mKeyAct);
    mHelpMenu->addAction(mAboutAct);
    mHelpMenu->addAction(mOnlineHelpAct);

    menuBar()->addMenu(mFileMenu);
    menuBar()->addMenu(mViewMenu);
    menuBar()->addMenu(mDeleteMenu);
    menuBar()->addMenu(mHelpMenu);

    mCameraMenu->setEnabled(false);
}

/**
 * @brief Helper function to create status bar at the bottom of the window
 */
d.kilic's avatar
d.kilic committed
void Petrack::createStatusBar()
{
    QFont f("Courier", 12, QFont::Bold); //Times Helvetica, Normal
    statusBar()->setMaximumHeight(28);
    statusBar()->showMessage(tr("Ready"));
    statusBar()->addPermanentWidget(mStatusLabelStereo = new QLabel(" "));
    statusBar()->addPermanentWidget(mStatusLabelTime = new QLabel(" "));
    statusBar()->addPermanentWidget(mStatusLabelFPS = new QLabel(" "));
    statusBar()->addPermanentWidget(mStatusPosRealHeight = new QDoubleSpinBox());
    connect(mStatusPosRealHeight, SIGNAL(valueChanged(double)), this, SLOT(setStatusPosReal()));

    //mStatusPosRealHeight->setEnabled(false); // temporaer, damit nichts eingetragen werden kann!!!!!!
    statusBar()->addPermanentWidget(mStatusLabelPosReal = new QLabel(" "));
    statusBar()->addPermanentWidget(mStatusLabelPos = new QLabel(" "));
    statusBar()->addPermanentWidget(mStatusLabelColor = new QLabel(" "));
    mStatusLabelStereo->setFont(f);
    mStatusLabelStereo->setMinimumWidth(200);
    mStatusLabelTime->setFont(f);
    mStatusLabelTime->setMinimumWidth(200);
    //mStatusLabelTime->setAlignment(Qt::AlignRight); ??? verschiebt text nach oben???!!!
    mStatusLabelFPS->setFont(f);
    mStatusLabelFPS->setMinimumWidth(80);    
    mStatusLabelFPS->setAutoFillBackground(true);
    mStatusLabelFPS->setToolTip("Click to adapt play rate to fps rate");
    //mStatusLabelFPS->setFrameStyle(QFrame::VLine);
    mStatusPosRealHeight->setRange(-999.9, 9999.9); // in cm
    mStatusPosRealHeight->setDecimals(1);
    mStatusPosRealHeight->setFont(f);
    mStatusLabelPosReal->setFont(f);
    mStatusLabelPosReal->setMinimumWidth(340);
    //     mStatusLabelPosReal->setFrameStyle(QFrame::Sunken|QFrame::Panel);
    mStatusLabelPos->setFont(f);
    mStatusLabelPos->setMinimumWidth(100);
    //mStatusLabelPos->setFrameStyle(QFrame::VLine|QFrame::Sunken);
    // debout << mStatusLabelPos->frameWidth() <<endl; ???? warum 0, daher wird auch sunken, vline nicht richtig gesetzt!!!!
    mStatusLabelColor->setFont(f);
    mStatusLabelColor->setMinimumWidth(90);
    mStatusLabelColor->setAutoFillBackground(true);
}

void Petrack::resetUI()
{
    ///ToDo:
    ///
    /// Reset all UI elements to default settings
    /// Noetig damit alle UI Elemente, welche in der neu geladenen Projekt-Datei z.B. noch nicht vorhanden sind, auf sinnvolle Werte gesetzt werden.
    /// Anderenfalls kommt es evtl. beim nacheinander laden verschiedener Projekte zu einem Programmabsturz
    ///
    return;
    /// sequence , height
    mSeqFileName = "";
    mAnimation->free();
    if( mImage )
    {
        mImage->fill(QColor::fromRgb(255,255,255));
        mImageItem->setImage(mImage);
        mLogoItem->show();
    }
    mStatusPosRealHeight->setValue(180.0);
    /// calibration params
    /// image filters
    mControlWidget->filterBrightContrast->setCheckState(Qt::Unchecked);
    mControlWidget->filterBrightParam->setValue(0);
    mControlWidget->filterContrastParam->setValue(0);

    mControlWidget->filterBorder->setCheckState(Qt::Unchecked);
    mControlWidget->filterBorderParamSize->setValue(0);
    QColor defaultBorder = Qt::black;
    getBorderFilter()->getBorderColR()->setValue(defaultBorder.red());
    getBorderFilter()->getBorderColG()->setValue(defaultBorder.green());
    getBorderFilter()->getBorderColB()->setValue(defaultBorder.blue());

    mControlWidget->filterBg->setCheckState(Qt::Unchecked);
    mControlWidget->filterBgDeleteNumber->setValue(3);
    mControlWidget->filterBgDeleteTrj->setCheckState(Qt::Checked);
    mControlWidget->filterBgShow->setCheckState(Qt::Unchecked);
    mControlWidget->filterBgUpdate->setCheckState(Qt::Unchecked);
    getBackgroundFilter()->setFilename(NULL);
    getBackgroundFilter()->reset();

    mControlWidget->filterSwap->setCheckState(Qt::Unchecked);