Skip to content
Snippets Groups Projects
trackerItem.cpp 40.1 KiB
Newer Older
/*
 * PeTrack - Software for tracking pedestrians movement in videos
 * Copyright (C) 2010-2020 Forschungszentrum Jülich GmbH,
 * Maik Boltes, Juliane Adrian, Ricardo Martin Brualla, Arne Graf, Paul Häger, Daniel Hillebrand,
 * Deniz Kilic, Paul Lieberenz, Daniel Salden, Tobias Schrödter, Ann Katrin Seemann
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

d.kilic's avatar
d.kilic committed
#include <QtWidgets>
#include <QInputDialog>

Schrödter, Tobias's avatar
Schrödter, Tobias committed
#include "animation.h"
d.kilic's avatar
d.kilic committed
#include "petrack.h"
#include "control.h"
#include "view.h"
#include "trackerItem.h"
#include "tracker.h"
Schrödter, Tobias's avatar
Schrödter, Tobias committed
#include "recognitionRoiItem.h"
#include "trackingRoiItem.h"
d.kilic's avatar
d.kilic committed

// in x und y gleichermassen skaliertes koordinatensystem,
// da von einer vorherigen intrinsischen kamerakalibrierung ausgegenagen wird,
// so dass pixel quadratisch 
TrackerItem::TrackerItem(QWidget *wParent, Tracker *tracker, QGraphicsItem * parent)
    : QGraphicsItem(parent)
{
    mMainWindow = (class Petrack*) wParent;
    mControlWidget = mMainWindow->getControlWidget();
    mTracker = tracker;
}

/**
 * @brief Bounding box of drawn to area.
 *
 * This bounding box is used to determine if this Item needs to be redrawn or not.
 * See the official Qt Docs for QGraphicsItem
 *
 * @return (updated) bounding rect of this item
 */
d.kilic's avatar
d.kilic committed
QRectF TrackerItem::boundingRect() const
{
    if (mMainWindow->getImage())
        return QRectF(-mMainWindow->getImageBorderSize(), -mMainWindow->getImageBorderSize(), mMainWindow->getImage()->width(), mMainWindow->getImage()->height());
    else
        return QRectF(0, 0, 0, 0);
}
void TrackerItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    if( !(event->modifiers() & Qt::ShiftModifier || event->modifiers() & Qt::ControlModifier || event->modifiers() & Qt::AltModifier) )
    {
        TrackPoint p((Vec2F) event->pos(), 110); // 110 ist ueber 100 (hoechste Qualitaetsstufe) und wird nach einfuegen auf 100 gesetzt
        bool found = false;
        int i, iNearest = -1;
        float dist, minDist = 1000000.;
d.kilic's avatar
d.kilic committed

        QSet<int> onlyVisible = mMainWindow->getOnlyVisible();
        int frame = mMainWindow->getAnimation()->getCurrentFrameNum();
d.kilic's avatar
d.kilic committed

        for (i = 0; i < mTracker->size(); ++i) // !found &&  // ueber TrackPerson
d.kilic's avatar
d.kilic committed
        {
            if (((onlyVisible.empty()) || (onlyVisible.contains(i))) && mTracker->at(i).trackPointExist(frame))
d.kilic's avatar
d.kilic committed
            {
                dist = mTracker->at(i).trackPointAt(frame).distanceToPoint(p);
                if (( dist < mMainWindow->getHeadSize(nullptr, i, frame)/2.) ||
                    ( (mTracker->at(i).trackPointAt(frame).distanceToPoint(p.colPoint()) < mMainWindow->getHeadSize(nullptr, i, frame)/2.)))
d.kilic's avatar
d.kilic committed
                {
                        debout << "Warning: more possible trackpoints for point" << std::endl;
                        debout << "         " << p << " in frame " << frame << " with low distance:" << std::endl;
                        debout << "         person " << i+1 << " (distance: " << dist << "), " << std::endl;
                        debout << "         person " << iNearest+1 << " (distance: " << minDist << "), " << std::endl;
                        if (minDist > dist)
                        {
                            minDist = dist;
                            iNearest = i;
                        }
                    }
                    else
d.kilic's avatar
d.kilic committed
                    {
                        minDist = dist;
                        iNearest = i;
                        // WAR: break inner loop
                        found = true;
d.kilic's avatar
d.kilic committed
                    }
                }
            }
        }
        QMenu menu;
        TrackPerson tp;
        float height = 0.f;
        bool height_set_by_user = false;
        QAction *delTrj = nullptr, *delFutureTrj = nullptr, *delPastTrj = nullptr, *creTrj = nullptr, *infoTrj = nullptr, *addComment = nullptr, *setHeight = nullptr, *resetHeight = nullptr;
d.kilic's avatar
d.kilic committed

d.kilic's avatar
d.kilic committed
        {
            i = iNearest;
            tp = mTracker->at(i);
            height = tp.height();
            if (height < MIN_HEIGHT+1)
            {
                if (tp.color().isValid())
                    height = mControlWidget->getColorPlot()->map(tp.color());
            }else
            {
                height_set_by_user = true;
            }
            infoTrj = menu.addAction(QString("PersonNr: %1 height: %2 frames: [%3..%4]").arg(i+1).arg(height).arg(tp.firstFrame()).arg(tp.lastFrame()));
            delTrj = menu.addAction("Delete whole trajectory");
            delFutureTrj = menu.addAction("Delete past part of the trajectory");
            delPastTrj = menu.addAction("Delete future part of the trajectory");
            setHeight = menu.addAction("Set person height");
            if(height_set_by_user) resetHeight = menu.addAction("Reset height");
                addComment = menu.addAction("Edit comment");
        }
        else
d.kilic's avatar
d.kilic committed
        {
            creTrj = menu.addAction("Create new trajectory");
d.kilic's avatar
d.kilic committed
        }

        QAction *selectedAction = menu.exec(event->screenPos());
        if( selectedAction == creTrj )
d.kilic's avatar
d.kilic committed
        {
            mMainWindow->addOrMoveManualTrackPoint(event->scenePos());
        }else if( selectedAction == delTrj )
d.kilic's avatar
d.kilic committed
        {
            mMainWindow->deleteTrackPoint(event->scenePos(),0);
        }else if( selectedAction == delFutureTrj )
d.kilic's avatar
d.kilic committed
        {
            mMainWindow->deleteTrackPoint(event->scenePos(),-1);
        }else if( selectedAction == delPastTrj )
d.kilic's avatar
d.kilic committed
        {
            mMainWindow->deleteTrackPoint(event->scenePos(),1);
        }else if( selectedAction == addComment )
        {
            mMainWindow->editTrackPersonComment(event->scenePos());
        }else if( selectedAction == setHeight )
        {
            mMainWindow->setTrackPersonHeight(event->scenePos());
        }else if( selectedAction == resetHeight )
        {
            mMainWindow->resetTrackPersonHeight(event->scenePos());
        }else if( selectedAction == infoTrj )
        {
            if (found)
            {
                QString out;
                QMessageBox msgBox;
                msgBox.setText(QString("Info for trajectory number %1:").arg(i+1));
d.kilic's avatar
d.kilic committed

                if(height_set_by_user)
                {
                    out = QString("<table>"
                              "<tr><td>height:</td><td>%0 cm (edited by user)</td></tr>"
                              "<tr><td>frames:</td><td>[%1...%2]</td></tr>"
                              "<tr><td>color:</td><td><font style='display:inline;background:%3;color:#fff;'>%4</font></td></tr>"
                              "<tr><td>comment:</td><td>%5</td></tr>"
                              "<tr><td></td><td></td></tr>");
                }
                else
                {
                    out = QString("<table>"
                              "<tr><td>height:</td><td>%0 cm</td></tr>"
                              "<tr><td>frames:</td><td>[%1...%2]</td></tr>"
                              "<tr><td>color:</td><td><font style='display:inline;background:%3;color:#fff;'>%4</font></td></tr>"
                              "<tr><td>comment:</td><td>%5</td></tr>"
                              "<tr><td></td><td></td></tr>");
                }
d.kilic's avatar
d.kilic committed

                if( tp.lastFrame()-tp.firstFrame() > 5 )
                {
                    out.append(QString("<tr><td>frame [%6]:</td><td>[%7, %8]</td></tr>"
                                                    "<tr><td>frame [%9]:</td><td>[%10, %11]</td></tr>"
                                                    "<tr><td colspan='2'>...</td></tr>"
                                                    "<tr><td colspan='2'>...</td></tr>"
                                                    "<tr><td>frame [%12]:</td><td>[%13, %14]</td></tr>"
                                                    "<tr><td>frame [%15]:</td><td>[%16, %17]]</td></tr>"
                                                  "</table>").toLatin1());
                    msgBox.setInformativeText( out.arg(height)
                                              .arg(tp.firstFrame())
                                              .arg(tp.lastFrame())
                                              .arg(tp.color().name())
                                              .arg(tp.color().name())
                                              .arg(tp.comment())
                                              .arg(tp.firstFrame())
                                              .arg(tp.at(0).x())
                                              .arg(tp.at(0).y())
                                              .arg(tp.firstFrame()+1)
                                              .arg(tp.at(1).x())
                                              .arg(tp.at(1).y())
                                              .arg(tp.lastFrame()-1)
                                              .arg(tp.at(tp.size()-2).x())
                                              .arg(tp.at(tp.size()-2).y())
                                              .arg(tp.lastFrame())
                                              .arg(tp.at(tp.size()-1).x())
                                              .arg(tp.at(tp.size()-1).y()));
                }
                else
                {
                    out.append(QString("</table>"));
                    msgBox.setInformativeText( out.arg(height)
                                               .arg(tp.firstFrame())
                                               .arg(tp.lastFrame())
                                               .arg(tp.color().name())
                                               .arg(tp.color().name())
                                               .arg(tp.comment()));
                }
                out = QString();

                for(int frameTrackperson=tp.firstFrame(); frameTrackperson <= tp.lastFrame(); frameTrackperson++)
                {
                    out.append(QString("frame [%0]: [%1, %2]\n").arg(frameTrackperson).arg(tp.at(frameTrackperson - tp.firstFrame()).x()).arg(tp.at(frameTrackperson - tp.firstFrame()).y()));
                }

                msgBox.setDetailedText(out);

                msgBox.setWindowTitle("PeTrack");
                msgBox.setIcon(QMessageBox::Information);
                msgBox.setStandardButtons(QMessageBox::Ok);
                msgBox.setDefaultButton(QMessageBox::Ok);
                msgBox.setEscapeButton(QMessageBox::Ok);
                msgBox.exec();
            }
d.kilic's avatar
d.kilic committed
        }
    }
    mMainWindow->getScene()->update();
}
    
void TrackerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
d.kilic's avatar
d.kilic committed
{
    int from, to;
    int curFrame = mMainWindow->getAnimation()->getCurrentFrameNum();
    QPen ellipsePen;
    QRectF rect;
    Vec2F n;
    cv::Subdiv2D subdiv;
d.kilic's avatar
d.kilic committed
    int i, j;
    QPen linePen;
    QPen numberPen;
    QPen groundPositionPen;
    QPen groundPathPen;
    double pSP = (double) mControlWidget->trackCurrentPointSize->value();
    double pS  = (double) mControlWidget->trackPointSize->value();
    double pSC = (double) mControlWidget->trackColColorSize->value();
    double pSM = (double) mControlWidget->trackColorMarkerSize->value();
    double pSN = (double) mControlWidget->trackNumberSize->value();
    double pSG = (double) mControlWidget->trackGroundPositionSize->value();
    double pSGP = (double) mControlWidget->trackGroundPathSize->value();

    QColor pGPC = mControlWidget->getTrackGroundPathColor();
    QColor pTPC = mControlWidget->getTrackPathColor();
d.kilic's avatar
d.kilic committed
    QFont font, heightFont;
    float x_offset=0, y_offset=0;
    float y_switch=0, x_switch=0;
    double hS;

    painter->drawRect( boundingRect() );

    linePen.setColor(pTPC);
    linePen.setWidth(mControlWidget->trackPathWidth->value());

    ellipsePen.setWidth(3);

    if (mControlWidget->trackNumberBold->checkState() == Qt::Checked)
        font.setBold(true);
    else
        font.setBold(false);
    font.setPixelSize(mControlWidget->trackNumberSize->value());
    heightFont.setPixelSize(mControlWidget->trackColColorSize->value());
    painter->setFont(font);
    numberPen.setColor(Qt::red);
    groundPositionPen.setColor(Qt::green);
    groundPositionPen.setWidth(pSG);
    groundPathPen.setColor(pGPC);
    groundPathPen.setWidth(pSGP);


    if(mControlWidget->showVoronoiCells->isChecked() && !mTracker->isEmpty())
    {
        // ToDo: adjust subdiv rect to correct area
        QRectF qrect = mMainWindow->getRecoRoiItem()->rect();

        cv::Point3f leftTop = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(qrect.left(),qrect.top()),0);
        cv::Point3f rightBottom = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(qrect.right(),qrect.bottom()),0);
d.kilic's avatar
d.kilic committed

        x_offset = -std::min(leftTop.x,rightBottom.x);
        y_offset = -std::min(leftTop.y,rightBottom.y);
d.kilic's avatar
d.kilic committed
        x_switch = rightBottom.x < leftTop.x ? abs(rightBottom.x-leftTop.x) : 0;
        y_switch = rightBottom.y < leftTop.y ? abs(leftTop.y-rightBottom.y) : 0;
        debout << "x_offset: " << x_offset << ", y_offset: " << y_offset << ", x_switch: " << x_switch << ", y_switch: " << y_switch << std::endl;
d.kilic's avatar
d.kilic committed

        cv::Rect rect(cv::Rect(leftTop.x+x_offset,leftTop.y+y_offset,x_switch>0 ? x_switch : (rightBottom.x-leftTop.x),y_switch>0 ? y_switch : (rightBottom.y-leftTop.y)));
        debout << "Rect size: P(" << rect.x << ", " << rect.y << "), width: " << rect.width << ", height: " << rect.height << std::endl;
d.kilic's avatar
d.kilic committed

        subdiv.initDelaunay(rect);
    }
    for (i = 0; i < mTracker->size(); ++i) // ueber TrackPerson
    {
        // show current frame
        if ((!(mControlWidget->trackShowOnly->checkState() == Qt::Checked) && !(mControlWidget->trackShowOnlyList->checkState() == Qt::Checked)) ||
d.kilic's avatar
d.kilic committed
            (((mControlWidget->trackShowOnly->checkState() == Qt::Checked) || (mControlWidget->trackShowOnlyList->checkState() == Qt::Checked)) &&
                mMainWindow->getOnlyVisible().contains((i))))
        {
            if (mTracker->at(i).trackPointExist(curFrame))
            {
                if (mControlWidget->trackHeadSized->checkState() == Qt::Checked)
                    pSP = mMainWindow->getHeadSize(nullptr, i, curFrame); //headSize;
d.kilic's avatar
d.kilic committed
                const TrackPoint &tp = (*mTracker)[i][curFrame-mTracker->at(i).firstFrame()];
                if (mControlWidget->trackShowCurrentPoint->checkState() == Qt::Checked) //(mControlWidget->recoShowColor->checkState() == Qt::Checked)
                {
                    painter->setBrush(Qt::NoBrush);
                    if (mTracker->at(i).newReco())
                        painter->setPen(Qt::green);
                    else
                        painter->setPen(Qt::blue);
                    rect.setRect(tp.x()-pSP/2., tp.y()-pSP/2., pSP, pSP);
d.kilic's avatar
d.kilic committed
                    painter->drawEllipse(rect); // direkt waere nur int erlaubt tp.x()-5., tp.y()-5., 10., 10.
                }

                if (mControlWidget->trackShowSearchSize->checkState() == Qt::Checked)
                {
                    painter->setBrush(Qt::NoBrush);
                    painter->setPen(Qt::yellow);
                    hS = mMainWindow->winSize(nullptr, i, curFrame);
d.kilic's avatar
d.kilic committed
                    if (hS < 2) 
                        hS = 2; // entspricht Vorgehen in tracker.cpp
                    for (j = 0; j <= mControlWidget->trackRegionLevels->value(); ++j)
                    {
                        rect.setRect(tp.x()-hS/2., tp.y()-hS/2., hS, hS);
                        painter->drawRect(rect);
                        hS *= 2;
d.kilic's avatar
d.kilic committed
                    }
                }

                if (mControlWidget->trackShowColorMarker->checkState() == Qt::Checked)
d.kilic's avatar
d.kilic committed
                {
                    // farbe des trackpoints
                    if (tp.color().isValid())
                    {
                        painter->setBrush(Qt::NoBrush);
                        ellipsePen.setColor(tp.color());
                        painter->setPen(ellipsePen);
                        rect.setRect(tp.colPoint().x()-pSM/2., tp.colPoint().y()-pSM/2., pSM, pSM);
d.kilic's avatar
d.kilic committed
                        painter->drawEllipse(rect);
                    }
                }

                // berechnung der normalen, die zur positionierung der nummerieung und der gesamtfarbe dient
                if (((mControlWidget->trackShowColColor->checkState() == Qt::Checked) && (mTracker->at(i).color().isValid())) ||
                    (mControlWidget->trackShowNumber->checkState() == Qt::Checked) ||
                    ((mControlWidget->trackShowColColor->checkState() == Qt::Checked) &&
                     ((mTracker->at(i).height() > MIN_HEIGHT) || ((tp.sp().z() > 0.) && (mControlWidget->trackShowHeightIndividual->checkState() == Qt::Checked))))) //  Hoehe kann auf Treppen auch negativ werden, wenn koord weiter oben angesetzt wird
d.kilic's avatar
d.kilic committed
                {
                    if (tp.color().isValid())
                    {
                        n = (tp-tp.colPoint()).normal();
                        n.normalize();
                        if (n.length()<.001) // wenn to und colpoint aufeinander liegen z bei colorMarker!
                            n.set(1., 0.);
                    }
                    else
                    {
                        // man koennte auch lastNormal von anderem trackpath nehmen statt 1, 0
                        n.set(1., 0.);
                        // den vorherigen trackpoint finden, wo reco farbe erzeugt hat und somit colpoint vorliegt
                        for (j = curFrame-mTracker->at(i).firstFrame(); j > -1; --j)
                            if (mTracker->at(i).at(j).color().isValid())
                            {
                                n = (mTracker->at(i).at(j)-mTracker->at(i).at(j).colPoint()).normal();
                                n.normalize();
                                break;
                            }
                        // einen nachfolgenden trackpoint suchen, wenn vorher keiner mit farbe war
                        // zB wenn rueckwaerts abgespielt wird
                        if ((n.x()==1.) && (n.y()==0.))
                        {
                            for (j = curFrame-mTracker->at(i).firstFrame()+1; j < mTracker->at(i).size(); ++j)
                                if (mTracker->at(i).at(j).color().isValid())
                                {
                                    n = (mTracker->at(i).at(j)-mTracker->at(i).at(j).colPoint()).normal();
                                    n.normalize();
                                    break;
                                }
                        }
                    }
                }

                // farbe der gesamten trackperson
                double height = mTracker->at(i).height();
                if (mControlWidget->trackShowColColor->checkState() == Qt::Checked)
                {
                    painter->setPen(numberPen);
                    painter->setBrush(Qt::NoBrush);
                    rect.setRect(tp.x()+10,tp.y()+10,15*pSC,10*pSC);
                    painter->drawText(rect,mTracker->at(i).comment());
                    rect.setRect(tp.x()-pSC,tp.y()-pSC,50,50);
                    if (tp.getMarkerID()>0)
d.kilic's avatar
d.kilic committed
                    {
                        painter->drawText(rect,QString("id=%1").arg(tp.getMarkerID()));
d.kilic's avatar
d.kilic committed
                    }

                }

                if ((mControlWidget->trackShowColColor->checkState() == Qt::Checked) && (mTracker->at(i).color().isValid()))
                {
                    painter->setPen(Qt::NoPen);
                    painter->setBrush(QBrush(mTracker->at(i).color()));
                    rect.setRect(tp.x()+(pSP+pSC)*0.6*n.x()-pSC/2., tp.y()+(pSP+pSC)*0.6*n.y()-pSC/2., pSC, pSC); // 11
                    painter->drawEllipse(rect);
                }
                else if ((mControlWidget->trackShowColColor->checkState() == Qt::Checked) &&
                         ((height > MIN_HEIGHT) || ((tp.sp().z() > 0.) && (mControlWidget->trackShowHeightIndividual->checkState() == Qt::Checked)))) // Hoehe  && (mTracker->at(i).height() > 0.) Hoehe kann auf Treppen auch negativ werden, wenn koord weiter oben angesetzt wird
                {
                    painter->setFont(heightFont);
                    if ((mControlWidget->trackShowHeightIndividual->checkState() == Qt::Checked) && (tp.sp().z() > 0.)) // Hoehe incl individual fuer jeden trackpoint
                    {
                        painter->setPen(numberPen);
                        painter->setBrush(Qt::NoBrush);
                        rect.setRect(tp.x()+(pSP+pSC)*0.6*n.x()-pSC/2., tp.y()+(pSP+pSC)*0.6*n.y()-pSC/2., 3*pSC, 2.5*pSC); // 11
                        if (height < MIN_HEIGHT+1)
                        {
                            if (mControlWidget->getCalibCoordDimension() == 0) // 3D
                                painter->drawText(rect, Qt::AlignHCenter, QString("-\n%2").arg(-mControlWidget->getCalibExtrTrans3()-tp.sp().z(), 6, 'f', 1));
                            else
                                painter->drawText(rect, Qt::AlignHCenter, QString("-\n%2").arg(mControlWidget->coordAltitude->value()-tp.sp().z(), 6, 'f', 1));

                        }else
                        {
                            if (mControlWidget->getCalibCoordDimension() == 0) // 3D
                                painter->drawText(rect, Qt::AlignHCenter, QString("%1\n%2").arg(height, 6, 'f', 1).arg(-mControlWidget->getCalibExtrTrans3()-tp.sp().z(), 6, 'f', 1));
                            else
                                painter->drawText(rect, Qt::AlignHCenter, QString("%1\n%2").arg(height, 6, 'f', 1).arg(mControlWidget->coordAltitude->value()-tp.sp().z(), 6, 'f', 1));
                        }
                    }
                    else
                    {
                        painter->setPen(numberPen);
                        painter->setBrush(Qt::NoBrush);
                        rect.setRect(tp.x()+(pSP+pSC)*0.6*n.x()-pSC/2., tp.y()+(pSP+pSC)*0.6*n.y()-pSC/2., 3*pSC, 2*pSC); // 11
                        painter->drawText(rect, Qt::AlignHCenter, QString("%1").arg(height, 6, 'f', 1));
                    }
                    painter->setFont(font);
                }
                if (mControlWidget->trackShowNumber->checkState() == Qt::Checked)
                {
                    // listennummer
                    painter->setPen(numberPen);
                    painter->setBrush(Qt::NoBrush);
                    rect.setRect(tp.x()-(pSP+pSN)*0.6*n.x()-pSN, tp.y()-(pSP+pSN)*0.6*n.y()-pSN/2., 2.*pSN, pSN); // 11
                    painter->drawText(rect, Qt::AlignHCenter, QString("%1").arg(i+1));
                }
                if (mControlWidget->trackShowGroundPosition->checkState() == Qt::Checked)
                {
                    // ground position
                    painter->setPen(groundPositionPen);
                    painter->setBrush(Qt::NoBrush);
                    if( mControlWidget->getCalibCoordDimension() == 0) // 3D
                    {
                        double cross_size = 15+pSG*0.25;
                        cv::Point3f p3d_height;
d.kilic's avatar
d.kilic committed
                        if (height < MIN_HEIGHT+1)
                        {
                            p3d_height = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(tp.x(),tp.y()),mControlWidget->getColorPlot()->map(mTracker->at(i).color()));
d.kilic's avatar
d.kilic committed
                        }else
                        {
                            if ( tp.sp().z() > 0 )
                                p3d_height = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(tp.x(),tp.y()),-mControlWidget->getCalibExtrTrans3()-tp.sp().z());
d.kilic's avatar
d.kilic committed
                            else
                                p3d_height = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(tp.x(),tp.y()),height/*mControlWidget->mapDefaultHeight->value()*/);
d.kilic's avatar
d.kilic committed
                        }
                        p3d_height.z = 0;
                        cv::Point2f p2d_ground = mMainWindow->getExtrCalibration()->getImagePoint(p3d_height);
d.kilic's avatar
d.kilic committed
                        QPointF axis = mMainWindow->getImageItem()->getCmPerPixel(p2d_ground.x, p2d_ground.y, 0);
                        painter->drawLine(QLineF(p2d_ground.x-cross_size*0.5*pow(axis.x(),-1),p2d_ground.y-cross_size*0.5*pow(axis.y(),-1),p2d_ground.x+cross_size*0.5*pow(axis.x(),-1),p2d_ground.y+cross_size*0.5*pow(axis.y(),-1)));
                        painter->drawLine(QLineF(p2d_ground.x-cross_size*0.5*pow(axis.x(),-1),p2d_ground.y+cross_size*0.5*pow(axis.y(),-1),p2d_ground.x+cross_size*0.5*pow(axis.x(),-1),p2d_ground.y-cross_size*0.5*pow(axis.y(),-1)));
                        painter->drawLine(QLineF(p2d_ground.x,p2d_ground.y,tp.x(),tp.y()));



                    }else // 2D
                    {


                    }

                }
                if( mControlWidget->showVoronoiCells->checkState() == Qt::Checked)
                {
                    if( mControlWidget->getCalibCoordDimension() == 0 ) // 3D
                    {
                        cv::Point3f p3d_height;
d.kilic's avatar
d.kilic committed
                        if (height < MIN_HEIGHT+1)
                        {
                            p3d_height = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(tp.x(),tp.y()),mControlWidget->getColorPlot()->map(mTracker->at(i).color()));
d.kilic's avatar
d.kilic committed
                        }else
                        {
                            if ( tp.sp().z() > 0 )
                                p3d_height = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(tp.x(),tp.y()),-mControlWidget->getCalibExtrTrans3()-tp.sp().z());
d.kilic's avatar
d.kilic committed
                            else
                                p3d_height = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(tp.x(),tp.y()),height/*mControlWidget->mapDefaultHeight->value()*/);
d.kilic's avatar
d.kilic committed
                        }

                        debout << "insert P(" << p3d_height.x+x_offset << ", " << p3d_height.y+y_offset << ") to subdiv" << std::endl;
d.kilic's avatar
d.kilic committed

                        subdiv.insert(cv::Point2f(x_switch>0 ? x_switch-p3d_height.x+x_offset : p3d_height.x+x_offset, y_switch>0 ? y_switch-p3d_height.y+y_offset : p3d_height.y+y_offset));// p2d_ground);
d.kilic's avatar
d.kilic committed

                    }
                }
            }
        
            if (((mControlWidget->trackShowPoints->checkState() == Qt::Checked) || (mControlWidget->trackShowPath->checkState() == Qt::Checked) || (mControlWidget->trackShowGroundPath->checkState() == Qt::Checked)) && ((mTracker->at(i).trackPointExist(curFrame)) || (mControlWidget->trackShowOnlyVisible->checkState() == Qt::Unchecked)))
            {
                if (mControlWidget->trackShowBefore->value() == -1)
                    from = 0;
                else
                {
                    from = curFrame-mTracker->at(i).firstFrame()-mControlWidget->trackShowBefore->value();
d.kilic's avatar
d.kilic committed
                    if (from < 0)
                        from = 0;
                }
                if (mControlWidget->trackShowAfter->value() == -1)
                    to = mTracker->at(i).size();
                else
                {
                    to = curFrame-mTracker->at(i).firstFrame()+mControlWidget->trackShowAfter->value()+1;
d.kilic's avatar
d.kilic committed
                    if (to > mTracker->at(i).size())
                        to = mTracker->at(i).size();
                }
                for (j = from; j < to; ++j) // ueber TrackPoint
                {
                    // path
                    if (mControlWidget->trackShowPath->checkState() == Qt::Checked)
                    {
                        if (j != from) // autom. > 0
                        {
                            painter->setPen(linePen);
                            painter->setBrush(Qt::NoBrush);
d.kilic's avatar
d.kilic committed
                            // nur Linie zeichnen, wenn x oder y sich unterscheidet, sonst Punkt
                            // die Unterscheidung ist noetig, da Qt sonst grosses quadrat beim ranzoomen zeichnet
                            if ((mTracker->at(i).at(j-1).toQPointF().x() != mTracker->at(i).at(j).toQPointF().x()) ||
                                (mTracker->at(i).at(j-1).toQPointF().y() != mTracker->at(i).at(j).toQPointF().y()))
                                painter->drawLine(mTracker->at(i).at(j-1).toQPointF(), mTracker->at(i).at(j).toQPointF());
                            else
                                painter->drawPoint(mTracker->at(i).at(j-1).toQPointF());
                        }
                    }
                    // path on ground
                    if (mControlWidget->trackShowGroundPath->checkState() == Qt::Checked)
                    {
                        if (j != from)
                        {

                            // ground position
                            painter->setPen(groundPathPen);
                            painter->setBrush(Qt::NoBrush);
                            if( mControlWidget->getCalibCoordDimension() == 0) // 3D
                            {
                                cv::Point3f p3d_height_p1, p3d_height_p2;
d.kilic's avatar
d.kilic committed
                                if (mTracker->at(i).height() < MIN_HEIGHT+1)
                                {
                                    p3d_height_p1 = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(mTracker->at(i).at(j-1).x(),mTracker->at(i).at(j-1).y()),mControlWidget->getColorPlot()->map(mTracker->at(i).color()));
                                    p3d_height_p2 = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(mTracker->at(i).at(j).x(),mTracker->at(i).at(j).y()),mControlWidget->getColorPlot()->map(mTracker->at(i).color()));
d.kilic's avatar
d.kilic committed
                                }else
                                {
                                    if ( mTracker->at(i).at(j-1).sp().z() > 0 && mTracker->at(i).at(j).sp().z() > 0 )
                                    {
                                        p3d_height_p1 = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(mTracker->at(i).at(j-1).x(),mTracker->at(i).at(j-1).y()),-mControlWidget->getCalibExtrTrans3()-mTracker->at(i).at(j-1).sp().z());
                                        p3d_height_p2 = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(mTracker->at(i).at(j).x(),mTracker->at(i).at(j).y()),-mControlWidget->getCalibExtrTrans3()-mTracker->at(i).at(j).sp().z());
d.kilic's avatar
d.kilic committed
                                    }else
                                    {
                                        p3d_height_p1 = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(mTracker->at(i).at(j-1).x(),mTracker->at(i).at(j-1).y()),mTracker->at(i).height());
                                        p3d_height_p2 = mMainWindow->getExtrCalibration()->get3DPoint(cv::Point2f(mTracker->at(i).at(j).x(),mTracker->at(i).at(j).y()),mTracker->at(i).height());
d.kilic's avatar
d.kilic committed
                                    }
                                }
                                p3d_height_p1.z = 0;
                                p3d_height_p2.z = 0;
                                cv::Point2f p2d_ground_p1 = mMainWindow->getExtrCalibration()->getImagePoint(p3d_height_p1);
                                cv::Point2f p2d_ground_p2 = mMainWindow->getExtrCalibration()->getImagePoint(p3d_height_p2);
d.kilic's avatar
d.kilic committed
                                // nur Linie zeichnen, wenn x oder y sich unterscheidet, sonst Punkt
                                // die Unterscheidung ist noetig, da Qt sonst grosses quadrat beim ranzoomen zeichnet
                                if (p2d_ground_p1.x != p2d_ground_p2.x || p2d_ground_p1.y != p2d_ground_p2.y )
                                    painter->drawLine(QLineF(p2d_ground_p1.x,p2d_ground_p1.y,p2d_ground_p2.x,p2d_ground_p2.y));
                                else
                                    painter->drawPoint(p2d_ground_p1.x,p2d_ground_p1.y);
                            }else // 2D
                            {

                            }
                        }
                    }

                    // points before and after
                    if (mControlWidget->trackShowPoints->checkState() == Qt::Checked)
                    {
                        if (mTracker->at(i).firstFrame()+j != curFrame)
                        {
                            if ((mControlWidget->trackShowPointsColored->checkState() == Qt::Checked) && (mTracker->at(i).at(j).color().isValid()))
                            {
                                painter->setPen(Qt::NoPen);
                                painter->setBrush(QBrush(mTracker->at(i).at(j).color()));
                                rect.setRect(mTracker->at(i).at(j).x()-pS/2., mTracker->at(i).at(j).y()-pS/2., pS, pS); // 7
                            }
                            else
                            {
                                painter->setPen(Qt::red);
                                painter->setBrush(Qt::NoBrush);
                                // war noetig fuer alte qt-version: rect.setRect(mTracker->at(i).at(j).x()-(pS-1.)/2., mTracker->at(i).at(j).y()-(pS-1.)/2., pS-1., pS-1.); // 6
                                rect.setRect(mTracker->at(i).at(j).x()-pS/2., mTracker->at(i).at(j).y()-pS/2., pS, pS);
                            }
                            painter->drawEllipse(rect);
                        }
                    }
                }
            }
        }
    }

    // Mat& img, Subdiv2D& subdiv )
    if( mControlWidget->showVoronoiCells->checkState() == Qt::Checked && !mTracker->isEmpty() )
    {

        std::vector<std::vector<cv::Point2f> > facets3D;
        std::vector<cv::Point2f> centers3D;
d.kilic's avatar
d.kilic committed

        // get Voronoi cell info from subDiv in 3D coordinates on ground (z=0)
        subdiv.getVoronoiFacetList(std::vector<int>(), facets3D, centers3D);
d.kilic's avatar
d.kilic committed

        painter->setClipRect(mMainWindow->getRecoRoiItem()->rect());//0,0,mMainWindow->getImage()->width(),mMainWindow->getImage()->height());

        // cell by cell
        for( size_t i = 0; i < facets3D.size(); i++ )
        {
            centers3D.at(i).x = x_switch>0 ? x_switch-centers3D.at(i).x-x_offset : centers3D.at(i).x-x_offset;
            centers3D.at(i).y = y_switch>0 ? y_switch-centers3D.at(i).y-y_offset : centers3D.at(i).y-y_offset;
            // voronoi cell center in 2D
            cv::Point2f center2D = mMainWindow->getExtrCalibration()->getImagePoint(cv::Point3f(centers3D.at(i).x,
d.kilic's avatar
d.kilic committed
                                                                                        centers3D.at(i).y,0));

            std::vector<QPointF> ifacet2D;
d.kilic's avatar
d.kilic committed
            QPointF circleStart, circleEnd;
            float area = 0;
            float r = 50, m = 0, n = 0, s1_x = 0, s2_x = 0, s1_y = 0, s2_y = 0;
d.kilic's avatar
d.kilic committed
            for( size_t j = 0; j < facets3D[i].size(); j++ )
            {
                facets3D.at(i).at(j).x = x_switch>0 ? x_switch-facets3D.at(i).at(j).x-x_offset : facets3D.at(i).at(j).x-x_offset;
                facets3D.at(i).at(j).y = y_switch>0 ? y_switch-facets3D.at(i).at(j).y-y_offset : facets3D.at(i).at(j).y-y_offset;

                cv::Point2f point2D = mMainWindow->getExtrCalibration()->getImagePoint(cv::Point3f(facets3D.at(i).at(j).x,facets3D.at(i).at(j).y,0));
d.kilic's avatar
d.kilic committed

                debout << "facets3D.at(" << i << ").at(" << j << ").x = " << facets3D.at(i).at(j).x << ", .y = " << facets3D.at(i).at(j).y << std::endl;
                debout << "point2D.x = " << point2D.x << " , .y = " << point2D.y << std::endl;
d.kilic's avatar
d.kilic committed

                if ( false && sqrt(pow((facets3D.at(i).at(j).x - centers3D.at(i).x),2) +
                                   pow((facets3D.at(i).at(j).y - centers3D.at(i).y),2)) > r )
                {
                    if (circleStarted)
                    {

                        m = (facets3D.at(i).at(j).y - facets3D.at(i).at((j-1)%facets3D.at(i).size()).y) /
                                (facets3D.at(i).at(j).x - facets3D.at(i).at((j-1)%facets3D.at(i).size()).x);

                        // End punkt berechnen (Schnittpunkt Gerade-Kreis)
                        // Steigung der Geraden
                        m = (facets3D.at(i).at(j).y - facets3D.at(i).at((j+1)%facets3D.at(i).size()).y) /
                                (facets3D.at(i).at(j).x - facets3D.at(i).at((j+1)%facets3D.at(i).size()).x);
                        // Achsenabschnitt der Geraden
                        n = facets3D.at(i).at(j).y - m * facets3D.at(i).at(j).x;

                        float p = -( (m*n - m*centers3D.at(i).y - centers3D.at(i).x)/(1+pow(m,2)) );
                        float q = sqrt((pow(r,2)-pow(centers3D.at(i).x,2)-pow(centers3D.at(i).y,2)-pow(n,2)-2*n*centers3D.at(i).y) / (1+pow(m,2)) +
                                       pow((m*n-m*centers3D.at(i).y-centers3D.at(i).x)/(1+pow(m,2)),2));
                        // Schnittpunkte mit Kreis
                        s1_x = p + q;
                        s1_y = m*s1_x+n;

                        s2_x = p - q;
                        s2_y = m*s2_x+n;

                        facets3D[i][j] = cv::Point2f(s1_x,s1_y);
d.kilic's avatar
d.kilic committed

                        point2D = mMainWindow->getExtrCalibration()->getImagePoint(cv::Point3f(s1_x,s1_y,0));
d.kilic's avatar
d.kilic committed
                        circleEnd = QPointF(point2D.x,point2D.y);

                        ifacet2D.push_back(QPointF(center2D.x,center2D.y));
                        ifacet2D.push_back(QPointF(point2D.x,point2D.y));

                        debout << "End point: (" << s1_x << ", " << s1_y << ")" << std::endl;
d.kilic's avatar
d.kilic committed
                    }else
                    {
                        // start punkt berechnen

                        m = (facets3D.at(i).at(j).y - facets3D.at(i).at((j-1)%facets3D.at(i).size()).y) /
                                (facets3D.at(i).at(j).x - facets3D.at(i).at((j-1)%facets3D.at(i).size()).x);

                        n = facets3D.at(i).at(j).y - m * facets3D.at(i).at(j).x;

                        float p = -( (m*n - m*centers3D.at(i).y - centers3D.at(i).x)/(1+pow(m,2)) );
                        float q = sqrt((pow(r,2)-pow(centers3D.at(i).x,2)-pow(centers3D.at(i).y,2)-pow(n,2)-2*n*centers3D.at(i).y) / (1+pow(m,2)) +
                                       pow((m*n-m*centers3D.at(i).y-centers3D.at(i).x)/(1+pow(m,2)),2));

                        // Schnittpunkte mit Kreis
                        s1_x = p + q;
                        s1_y = m*s1_x+n;

                        s2_x = p - q;
                        s2_y = m*s2_x+n;

                        debout << "x=" << s1_x << " G(x)=" << (m*s1_x+n) << " K(x)=" << pow(s1_x-centers3D.at(i).x,2)+pow(s1_y-centers3D.at(i).y,2) << " = " << pow(r,2) << std::endl;
                        debout << "x=" << s2_x << " G(x)=" << (m*s2_x+n) << " K(x)=" << pow(s2_x-centers3D.at(i).x,2)+pow(s2_y-centers3D.at(i).y,2) << " = " << pow(r,2) << std::endl;
d.kilic's avatar
d.kilic committed

                        facets3D[i][j] = cv::Point2f(s1_x,s1_y);
d.kilic's avatar
d.kilic committed

                        point2D = mMainWindow->getExtrCalibration()->getImagePoint(cv::Point3f(s1_x,s1_y,0));
d.kilic's avatar
d.kilic committed
                        ifacet2D.push_back(QPointF(point2D.x,point2D.y));
                        circleStart = QPointF(point2D.x,point2D.y);
                        circleStarted = true;

                        debout << "Start point: (" << s1_x << ", " << s1_y << ")" << std::endl;
d.kilic's avatar
d.kilic committed
                    }

                }else
                {
                    ifacet2D.push_back(QPointF(point2D.x,point2D.y));
                    area += (facets3D.at(i).at(j).x*facets3D.at(i).at((j+1)%facets3D[i].size()).y);
                    area -= (facets3D.at(i).at((j+1)%facets3D[i].size()).x*facets3D.at(i).at(j).y);
                }
            }
            area *= 0.5;
            area = 1.0/area;
d.kilic's avatar
d.kilic committed
            area *= 10000;

            QColor color;

            color.setHsv((255-area*25.5)<0?0:(255-area*25.5),255,255,128);
d.kilic's avatar
d.kilic committed

            QVector<QPointF> ifacet_vec;
            for(size_t i=0; i<ifacet2D.size(); i++)
d.kilic's avatar
d.kilic committed
            {
                ifacet_vec.append(ifacet2D.at(i));
            }

            painter->setBrush(color);
            painter->setPen(Qt::black);
d.kilic's avatar
d.kilic committed
            if( ifacet2D.size() == 0 )
                painter->drawEllipse(QPointF(center2D.x,center2D.y),100,100);
            painter->drawConvexPolygon(QPolygonF(ifacet_vec));

            // voronoi cell point
            painter->setBrush(Qt::black);
            painter->setPen(Qt::red);
            painter->drawEllipse(QPointF(center2D.x,center2D.y),5,5);
        }
    }
}