diff --git a/SimpleLabel.pro b/SimpleLabel.pro
new file mode 100644
index 0000000..a6f165d
--- /dev/null
+++ b/SimpleLabel.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS += SimpleLabel
+SUBDIRS += SimpleLabelTests
\ No newline at end of file
diff --git a/SimpleLabel/About.cpp b/SimpleLabel/About.cpp
new file mode 100644
index 0000000..81e0705
--- /dev/null
+++ b/SimpleLabel/About.cpp
@@ -0,0 +1,37 @@
+/* SimpleLabel - a simple and light program for semi automatic labeling of regions
+ of interest on images or image sequences.
+ Developed at Laboratory for Active and Attentive Vision, York University, Toronto.
+ http://www.cse.yorku.ca/LAAV/home/ headed by John K. Tsotsos.
+
+ Copyright (C) 2010 Eugene Simine.
+
+ 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
+ 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 .
+
+ Contact: Eugene Simine or
+ John K. Tsotsos
+*/
+#include "About.h"
+
+
+About::About(QWidget *parent, Qt::WindowFlags flags)
+ : QDialog(parent, flags)
+{
+ ui.setupUi(this);
+
+ this->setWindowTitle(this->windowTitle() + " v" + QCoreApplication::applicationVersion());
+}
+
+About::~About(void)
+{
+}
diff --git a/SimpleLabel/About.h b/SimpleLabel/About.h
new file mode 100644
index 0000000..6f44425
--- /dev/null
+++ b/SimpleLabel/About.h
@@ -0,0 +1,44 @@
+/* SimpleLabel - a simple and light program for semi automatic labeling of regions
+ of interest on images or image sequences.
+ Developed at Laboratory for Active and Attentive Vision, York University, Toronto.
+ http://www.cse.yorku.ca/LAAV/home/ headed by John K. Tsotsos.
+
+ Copyright (C) 2010 Eugene Simine.
+
+ 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
+ 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 .
+
+ Contact: Eugene Simine or
+ John K. Tsotsos
+*/
+#ifndef ABOUT_H
+#define ABOUT_H
+
+#include
+#include "ui_AboutDlg.h"
+
+
+class About :
+ public QDialog
+{
+ Q_OBJECT
+
+public:
+ About(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ virtual ~About(void);
+
+private:
+ Ui::AboutDlg ui;
+};
+
+#endif
diff --git a/SimpleLabel/AboutDlg.ui b/SimpleLabel/AboutDlg.ui
new file mode 100644
index 0000000..afff289
--- /dev/null
+++ b/SimpleLabel/AboutDlg.ui
@@ -0,0 +1,133 @@
+
+
+ AboutDlg
+
+
+
+ 0
+ 0
+ 430
+ 380
+
+
+
+
+ 430
+ 380
+
+
+
+
+ 430
+ 380
+
+
+
+ SimpleLabel
+
+
+ true
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 108
+ 31
+
+
+
+
+ -
+
+
+ OK
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 101
+ 31
+
+
+
+
+ -
+
+
+ false
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Plain
+
+
+ QPlainTextEdit::WidgetWidth
+
+
+ true
+
+
+ SimpleLabel - a simple and light program for semi automatic labeling of regions of interest on images or image sequences.
+Developed at Laboratory for Active and Attentive Vision, York University, Toronto.
+ http://www.cse.yorku.ca/LAAV/home/
+
+ Copyright (C) 2010 Eugene Simine.
+
+ 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
+ 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 <http://www.gnu.org/licenses/>.
+
+ Contact: eugene@cse.yorku.ca
+
+
+ false
+
+
+ true
+
+
+
+
+
+
+
+
+ okButton
+ clicked()
+ AboutDlg
+ accept()
+
+
+ 278
+ 253
+
+
+ 96
+ 254
+
+
+
+
+
diff --git a/SimpleLabel/Constants.h b/SimpleLabel/Constants.h
new file mode 100644
index 0000000..19c4497
--- /dev/null
+++ b/SimpleLabel/Constants.h
@@ -0,0 +1,371 @@
+/* SimpleLabel - a simple and light program for semi automatic labeling of regions
+ of interest on images or image sequences.
+ Developed at Laboratory for Active and Attentive Vision, York University, Toronto.
+ http://www.cse.yorku.ca/LAAV/home/ headed by John K. Tsotsos.
+
+ Copyright (C) 2010 Eugene Simine.
+
+ 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
+ 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 .
+
+ Contact: Eugene Simine or
+ John K. Tsotsos
+*/
+
+#ifndef CONSTANTS_H
+#define CONSTANTS_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define W_DISPLAYIMAGE 800
+#define H_DISPLAYIMAGE 600
+
+#define WINDOW_OFFSET_X 5
+#define WINDOW_OFFSET_Y 25
+#define CORNER_CIRCLE_RAD 5
+#define LENGTH_OF_ROTATION_LINE 20
+
+#define INVALID_ANGLE 0xffffffff
+
+#define ROUND(X) (abs(X -floor(X))<0.5?floor(X):floor(X)+1)
+#define sqr(X) ((X)*(X))
+
+//#define APP_VERSION "1.0.1"
+enum InputType
+{
+ AviFile,
+ ImageSequence,
+ None
+};
+
+enum LabelShape
+{
+ Rect,
+ Polyg,
+ Other
+};
+
+enum InterpolationMethod
+{
+ LinearIntr,
+ Motion
+};
+
+struct ViaPoint
+{
+public:
+ ViaPoint()
+ {
+ Init(0, 0.0, QRect(0,0,0,0));
+ }
+
+ ViaPoint(int frame , float angle, QRect rc)
+ {
+ Init(frame, angle, rc);
+ }
+
+ float angle;
+ int frame;
+ QRect rc;
+
+ bool operator == (const ViaPoint& b)
+ {
+ return this->angle == b.angle &&
+ this->frame == b.frame &&
+ this->rc == b.rc;
+ }
+
+ bool operator != (const ViaPoint& b)
+ {
+ return !(*this == b);
+ }
+
+ ViaPoint& operator=(const ViaPoint& b)
+ {
+ if(this != &b)
+ {
+ this->angle = b.angle;
+ this->frame = b.frame;
+ this->rc = b.rc;
+ }
+ return *this;
+ }
+
+private:
+ void Init(int fr , float a, QRect r)
+ {
+ frame = fr;
+ angle = a;
+ rc = r;
+ }
+};
+
+struct ViaPointPolygon
+{
+ int frame;
+ QPolygon pl;
+};
+
+struct Label
+{
+ int number;
+ QString name;
+ QString desc;
+ LabelShape shape;
+ QList boxes;
+ QList viaPoints;
+ QList polygons;
+ QList viaPointsPoly;
+
+ ViaPoint* findBoxByFrame(int frame)
+ {
+ ViaPoint *res = NULL;
+ int fr;
+ if(boxes.count() > 0)
+ {
+ fr = frame - boxes[0].frame;
+ if(fr >= 0 && fr < boxes.count())
+ res = &(boxes[fr]);
+ }
+
+ return res;
+ }
+
+ ViaPointPolygon* findPolygonByFrame(int frame)
+ {
+ ViaPointPolygon *res = NULL;
+ int fr;
+ if(polygons.count() > 0)
+ {
+ fr = frame - polygons[0].frame;
+ if(fr >= 0 && fr < polygons.count())
+ res = &(polygons[fr]);
+ }
+
+ return res;
+ }
+};
+
+class CommonFunctions
+{
+public:
+ static const QPoint NULL_POINT;
+ static const ViaPoint NULL_RECT;
+ static const QPolygon NULL_POLYGON;
+
+ static void splitPath(QString fullpath, QString &path, QString &filename, QString &fnamePrefix, uint n, int &index, QString &ext)
+ {
+ bool ok;
+ QString fpath = fullpath;
+ fpath.replace("\\", "/");
+ int dot = fpath.lastIndexOf(".");
+ int slash = fpath.lastIndexOf("/");
+
+ path = fullpath.left(slash + 1);
+ ext = fullpath.right(fullpath.length() - dot);
+ filename = fullpath.mid(slash + 1, dot - slash - 1);
+ fnamePrefix = filename.left(filename.length() - n);
+ index = filename.right(n).toInt(&ok);
+ if(!ok)
+ index = -1;
+ }
+
+ static void splitPath(QString fullpath, QString &path, QString &filename, QString &ext)
+ {
+ QString fpath = fullpath;
+ fpath.replace("\\", "/");
+ int dot = fpath.lastIndexOf(".");
+ int slash = fpath.lastIndexOf("/");
+
+ path = fullpath.left(slash + 1);
+ ext = fullpath.right(fullpath.length() - dot);
+ filename = fullpath.mid(slash + 1, dot - slash - 1);
+ }
+
+ static int checkForVertices(QPoint p, QRect rc)
+ {
+ int res = -1;
+ if(isCloseToEachOther(rc.topLeft(), p))
+ res = 0;
+ else if(isCloseToEachOther(rc.topRight(), p))
+ res = 1;
+ else if(isCloseToEachOther(rc.bottomRight(), p))
+ res = 2;
+ else if(isCloseToEachOther(rc.bottomLeft(), p))
+ res = 3;
+
+ return res;
+ }
+
+
+ static int checkForVerticesWithRotation(QPoint p, ViaPoint vp)
+ {
+ QPoint np = rotatePointAboutPoint(p, vp.angle, vp.rc.center());
+ QRect rc = vp.rc;
+
+ int res = -1;
+ if(isCloseToEachOther(rc.topLeft(), np))
+ res = 0;
+ else if(isCloseToEachOther(rc.topRight(), np))
+ res = 1;
+ else if(isCloseToEachOther(rc.bottomRight(), np))
+ res = 2;
+ else if(isCloseToEachOther(rc.bottomLeft(), np))
+ res = 3;
+
+ return res;
+ }
+
+ static bool checkForRotation(QPoint p, ViaPoint vp)
+ {
+ QPoint c = vp.rc.center();
+ QPoint pt(vp.rc.center().x(), vp.rc.top() - LENGTH_OF_ROTATION_LINE);
+
+ QPoint new_pt = rotatePointAboutPoint(p, vp.angle, c);
+
+ return isCloseToEachOther(pt, new_pt);
+ }
+
+ static QPoint rotatePointAboutPoint(QPoint p, double ang, QPoint o)
+ {
+ QTransform tr;
+ QPointF p1(p);
+ QPointF o1(o);
+
+ tr.translate(o1.x(), o1.y());
+ tr.rotate(ang);
+ tr.translate(-o1.x(), -o1.y());
+
+ QPointF res = tr.map(p1);
+
+ double l1 = vectorLength(p1 - o1);
+ double l2 = vectorLength(res - o1);
+ if(l1 - l2 > 0.00001)
+ qDebug() << "Something is off";
+
+ return QPoint(qRound(res.x()), qRound(res.y()));
+ }
+
+ static int checkForVertices(QPoint p, QPolygon pl)
+ {
+ int res = -1;
+ for(int i = 0; i < pl.count(); i++)
+ {
+ if(isCloseToEachOther(pl.point(i), p))
+ {
+ res = i;
+ break;
+ }
+ }
+
+ return res;
+ }
+
+ static double vectorLength(QPoint p)
+ {
+ return vectorLength(QPointF(p));
+ }
+
+ static double vectorLength(QPointF p)
+ {
+ if(p.manhattanLength() == 0) return 0.0;
+
+ return qSqrt( sqr(p.x()) + sqr(p.y()) );
+ }
+
+ static double findAngleBetweenVectors2(QPoint v1, QPoint v2)
+ {
+ double ang = qAtan2(v1.x(), v1.y()) - qAtan2(v2.x(), v2.y());
+
+ //converting to degrees
+ return 180*ang/M_PI;
+ }
+
+ static QPoint getVertex(QRect rc, int index)
+ {
+ QPoint pt = NULL_POINT;
+
+ switch(index)
+ {
+ case 0:
+ pt = rc.topLeft();
+ break;
+ case 1:
+ pt = rc.topRight();
+ break;
+ case 2:
+ pt = rc.bottomRight();
+ break;
+ case 3:
+ pt = rc.bottomLeft();
+ break;
+ default:
+ break;
+ }
+
+ return pt;
+ }
+
+ static QPoint getOpposingVertex(QRect rc, int index)
+ {
+ QPoint pt = NULL_POINT;
+
+ switch(index)
+ {
+ case 0:
+ pt = rc.bottomRight();
+ break;
+ case 1:
+ pt = rc.bottomLeft();
+ break;
+ case 2:
+ pt = rc.topLeft();
+ break;
+ case 3:
+ pt = rc.topRight();
+ break;
+ default:
+ break;
+ }
+
+ return pt;
+ }
+
+ private:
+ static bool isCloseToEachOther(QPoint pl, QPoint p2)
+ {
+ bool res = false;
+ int rad = CORNER_CIRCLE_RAD;
+ QPoint rt = pl - p2;
+ float dist = sqr(rt.x()) + sqr(rt.y());
+
+ if(dist == 0)
+ {
+ res = true;
+ }
+ else
+ {
+ res = sqrt(dist) < rad;
+ }
+
+ return res;
+ }
+};
+
+
+#endif
diff --git a/SimpleLabel/Monitor.cpp b/SimpleLabel/Monitor.cpp
new file mode 100644
index 0000000..880440d
--- /dev/null
+++ b/SimpleLabel/Monitor.cpp
@@ -0,0 +1,300 @@
+/* SimpleLabel - a simple and light program for semi automatic labeling of regions
+ of interest on images or image sequences.
+ Developed at Laboratory for Active and Attentive Vision, York University, Toronto.
+ http://www.cse.yorku.ca/LAAV/home/ headed by John K. Tsotsos.
+
+ Copyright (C) 2010 Eugene Simine.
+
+ 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
+ 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 .
+
+ Contact: Eugene Simine or
+ John K. Tsotsos
+*/
+#include "Monitor.h"
+#include
+#include
+
+Monitor::Monitor(QObject *parent)
+ : QThread(parent)
+{
+ mCurrImage = NULL;
+ mCvCapture = NULL;
+ mCurrentFrameNumber = 0;
+ stopExec = false;
+ mInputType = None;
+ mInitialized = false;
+}
+
+Monitor::~Monitor()
+{
+ reset();
+}
+
+void Monitor::reset()
+{
+ stopExec = false;
+ mInputType = None;
+ mFileNamePrefix = "";
+ mFileName = "";
+ mPath = "";
+ mExtention = "";
+ mFirstFrameNumber = -1;
+ mCurrentFrameNumber = -1;
+ mLastFrameNumber = -1;
+ mInitialized = false;
+
+ if(mCurrImage)
+ {
+ delete mCurrImage;
+ mCurrImage = NULL;
+ }
+}
+
+void Monitor::run()
+{
+ stopExec = false;
+ int fps = getFPS();
+ if(fps < 1)
+ fps = 30;
+
+ int delay = 1000/fps;
+ while(mInitialized && !stopExec && mCurrentFrameNumber < mLastFrameNumber)
+ {
+ moveToFrame(mCurrentFrameNumber + 1);
+ emit imageChanged();
+ msleep(delay);
+ }
+ stopExec = true;
+}
+
+void Monitor::stop()
+{
+ stopExec = true;
+}
+
+void Monitor::lockImages()
+{
+ mImMutex.lock();
+}
+
+void Monitor::releaseImages()
+{
+ mImMutex.unlock();
+}
+
+
+void Monitor::setCvCapture(CvCapture* c)
+{
+ int w, h, bpp;
+
+ if(c)
+ reset();
+
+ mCvCapture = c;
+
+ if(c)
+ {
+
+ cvSetCaptureProperty(mCvCapture, CV_CAP_PROP_POS_FRAMES, mCurrentFrameNumber);
+ IplImage *im = cvQueryFrame(mCvCapture);
+ w = im->width;
+ h = im->height;
+ bpp = im->nChannels;
+
+ lockImages();
+ mCurrImage = new QImage(w, h, QImage::Format_ARGB32);
+ convertRGB2ARGB(im, mCurrImage);
+ releaseImages();
+ mInputType = AviFile;
+
+ mFirstFrameNumber = 0;
+ mLastFrameNumber = cvGetCaptureProperty(mCvCapture, CV_CAP_PROP_FRAME_COUNT) - 1;
+ mInitialized = true;
+ emit imageChanged();
+ }
+}
+
+int Monitor::getFPS()
+{
+ int res = 0;
+ if(mInitialized)
+ {
+ if(mInputType == AviFile)
+ res = cvGetCaptureProperty(mCvCapture, CV_CAP_PROP_FPS);
+ }
+
+ return res;
+}
+
+void Monitor::setFisrtFilenameOfSequence(QString fname)
+{
+ int dot = fname.lastIndexOf(".");
+ int slash = fname.lastIndexOf("/");
+ bool ok;
+
+
+ QImage im(fname);
+
+ if(!im.isNull())
+ {
+ if(mCurrImage != NULL)
+ reset();
+
+ mPath = fname.left(slash + 1);
+ mExtention = fname.right(fname.length() - dot);
+ mFileName = fname.mid(slash + 1, dot - slash - 1);
+ mFileNamePrefix = mFileName.left(mFileName.length() - 5);
+ mFirstFrameNumber = mFileName.right(5).toInt(&ok);
+ mCurrentFrameNumber = mFirstFrameNumber;
+ mInputType = ImageSequence;
+
+ mCurrImage = new QImage(im);
+
+ if(ok)
+ {
+ findLastImageSequenceFrameNumber();
+ moveToFrame(mFirstFrameNumber);
+ }
+ else
+ {
+ mFirstFrameNumber = -1;
+ mLastFrameNumber = -1;
+ }
+
+
+ mInitialized = true;
+ emit imageChanged();
+
+ }
+ else
+ {
+ QMessageBox::information(NULL, "Image Error", "File " + fname + " is not an image or cannot be read.");
+ }
+}
+
+
+int Monitor::getFrameCount()
+{
+ int f = -1;
+ if(mInputType == AviFile)
+ {
+ if(mCvCapture)
+ f = (int)cvGetCaptureProperty(mCvCapture, CV_CAP_PROP_FRAME_COUNT);
+ }
+ else if(mInputType == ImageSequence)
+ {
+ f = mLastFrameNumber - mFirstFrameNumber + 1;
+ }
+
+ return f;
+}
+
+void Monitor::findLastImageSequenceFrameNumber()
+{
+ int i = 0;
+ if(mInputType == ImageSequence)
+ {
+ i = mFirstFrameNumber;
+ //QString s = mPath + mFileNamePrefix + QString("%1").arg(i,5,10,QChar('0')) + mExtention;
+
+ while(QFile::exists(mPath + mFileNamePrefix + QString("%1").arg(i,5,10,QChar('0')) + mExtention))
+ {
+ i++;
+ }
+ }
+
+ mLastFrameNumber = i - 1; //-1 because current image does not exist
+}
+
+void Monitor::moveToFrame(int f)
+{
+ if(mInputType == AviFile)
+ {
+ if(mCvCapture)
+ {
+ cvSetCaptureProperty(mCvCapture, CV_CAP_PROP_POS_FRAMES, f);
+ IplImage *im = cvQueryFrame(mCvCapture);
+ mCurrentFrameNumber = f;
+ lockImages();
+ convertRGB2ARGB(im, mCurrImage);
+ releaseImages();
+ }
+ }
+ else if( mInputType == ImageSequence)
+ {
+ if(f >= mFirstFrameNumber && f <= mLastFrameNumber)
+ {
+ QString fname = mPath + mFileNamePrefix + QString("%1").arg(f, 5, 10, QChar('0')) + mExtention;
+
+ lockImages();
+ mCurrImage->load(fname);
+ mCurrentFrameNumber = f;
+ releaseImages();
+ }
+ }
+}
+
+void Monitor::convertRGB2ARGB(IplImage *dataIn, QImage *dataOut)
+{
+ int w = dataIn->width;
+ int h = dataIn->height;
+// int step = dataIn->widthStep;
+ int c = dataIn->nChannels;
+ uchar* data = (unsigned char*)dataIn->imageData;
+ uchar* res = dataOut->bits();
+
+ int i;
+ for(i = 0; i < w*h; i++)
+ {
+ memcpy(res, data, 3*sizeof(uchar));
+ res[3] = 255;
+
+ data += c; //next line in the IplImage
+ res += 4;
+ }
+}
+
+void Monitor::convertARGB2RGB(QImage *dataIn, IplImage *dataOut)
+{
+ int w = dataIn->width();
+ int h = dataIn->height();
+// int step = dataIn->widthStep;
+ int c = dataOut->nChannels;
+ uchar* res = (unsigned char*)dataOut->imageData;
+ uchar* data = dataIn->bits();
+
+ int i;
+ for(i = 0; i < w*h; i++)
+ {
+ memcpy(res, data, 3*sizeof(uchar));
+
+ data += 4;
+ res += c; //next line in the IplImage
+ }
+}
+
+
+IplImage* Monitor::getFrame(int f)
+{
+ cvSetCaptureProperty(mCvCapture, CV_CAP_PROP_POS_FRAMES, f);
+ return cvQueryFrame(mCvCapture);
+}
+
+QSize Monitor::getImageSize()
+{
+ if(mInitialized)
+ return mCurrImage->size();
+ else
+ return QSize(0,0);
+}
\ No newline at end of file
diff --git a/SimpleLabel/Monitor.h b/SimpleLabel/Monitor.h
new file mode 100644
index 0000000..9ea7fa2
--- /dev/null
+++ b/SimpleLabel/Monitor.h
@@ -0,0 +1,91 @@
+/* SimpleLabel - a simple and light program for semi automatic labeling of regions
+ of interest on images or image sequences.
+ Developed at Laboratory for Active and Attentive Vision, York University, Toronto.
+ http://www.cse.yorku.ca/LAAV/home/ headed by John K. Tsotsos.
+
+ Copyright (C) 2010 Eugene Simine.
+
+ 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
+ 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 .
+
+ Contact: Eugene Simine or
+ John K. Tsotsos
+*/
+#ifndef MONITOR_H
+#define MONITOR_H
+
+#include
+#include
+#include
+#include
+#include
+#include "Constants.h"
+
+class Monitor : public QThread
+{
+ Q_OBJECT
+
+public:
+ Monitor(QObject *parent = NULL);
+ virtual ~Monitor();
+
+ void setCvCapture(CvCapture* c);
+ CvCapture* getCvCapture(){return mCvCapture;}
+ void setFisrtFilenameOfSequence(QString fname);
+
+ int getFrameCount();
+ IplImage* getFrame(int f);
+ int getCurrentFrameNumber() { return mCurrentFrameNumber; };
+ QImage* getImage() { return mCurrImage;}
+ QSize getImageSize();
+ int getFPS();
+
+ void lockImages();
+ void releaseImages();
+
+ void stop();
+ void moveToFrame(int f);
+
+ void convertARGB2RGB(QImage *dataIn, IplImage *dataOut);
+
+ bool isInitialized() {return mInitialized;}
+
+protected:
+ virtual void run();
+
+private:
+ void reset();
+ void convertRGB2ARGB(IplImage *dataIn, QImage *dataOut);
+ void findLastImageSequenceFrameNumber();
+
+private:
+ bool mInitialized;
+ bool stopExec;
+ QMutex mImMutex;
+ CvCapture *mCvCapture;
+ QString mFileNamePrefix;
+ QString mFileName;
+ QString mPath;
+ QString mExtention;
+ int mFirstFrameNumber;
+ int mCurrentFrameNumber;
+ int mLastFrameNumber;
+ InputType mInputType;
+ QImage *mCurrImage;
+
+signals:
+ void imageChanged();
+};
+
+
+#endif // MONITOR_H
\ No newline at end of file
diff --git a/SimpleLabel/README.txt b/SimpleLabel/README.txt
new file mode 100644
index 0000000..0f3d22a
--- /dev/null
+++ b/SimpleLabel/README.txt
@@ -0,0 +1,54 @@
+SimpleLabel is a image labelling tool designed to simplify the task of labelling
+targets (or regions of interest) on image sequences while providing simple and
+intuitive user interface. At the moment SimpleLabel supports only rectangular regions
+and uses linear interpolation to create intermediate marked regions.
+
+Developed by Eugene Simine at York University, Toronto in Laboratory for Active and
+Attentive Vision (http://www.cse.yorku.ca/LAAV/home/) headed by John K. Tsotsos.
+
+Contact: Eugene Simine or
+ John K. Tsotsos
+
+Requirements for development:
+Qt4.*
+OpenCV2.4.2
+
+OS Support:
+Windows (XP, Vista, 7)
+Linux (Ubuntu 10.04)
+MacOS (in theory)
+Main development is done on Windows 7, MS VisualStudio 2010 major releases are tested on Ubuntu.
+
+Installation:
+Windows binaries can be obtained from svn server:
+https://samson.cse.yorku.ca/svn/SimpleLabel_bin
+
+Login/Pass: guest/guest
+
+It requires Microsoft Visual C++ 2010 SP1 Redistributable Package (x86) to be installed
+http://www.microsoft.com/download/en/details.aspx?id=8328
+
+
+Source code is available from:
+https://samson.cse.yorku.ca/svn/SimpleLabel
+
+Login/Pass: guest/guest
+
+
+Windows:
+run win_config.bat
+That will create MSVS project .
+Warning: A minor Qt bug prevents the project from compiling correctly.
+To fix it follow these instruction:
+1. Open the SimpleLabel project
+2. Go to: Project->Properties->Configuration Properties->General->Target Name
+3. There will be a number appended to value, should look something like this "SimpleLabel1"
+4. Delete that number. The Target Name should have value "SimpleLabel"
+5. Click OK
+6. Compile the project
+Linux:
+>qmake SimpleLabel.pro
+>make
+>./SimpleLabel
+
+
diff --git a/SimpleLabel/Resources/cursor_crosshair.bmp b/SimpleLabel/Resources/cursor_crosshair.bmp
new file mode 100644
index 0000000..555e9f8
Binary files /dev/null and b/SimpleLabel/Resources/cursor_crosshair.bmp differ
diff --git a/SimpleLabel/Resources/cursor_crosshair_mask.bmp b/SimpleLabel/Resources/cursor_crosshair_mask.bmp
new file mode 100644
index 0000000..a7befc1
Binary files /dev/null and b/SimpleLabel/Resources/cursor_crosshair_mask.bmp differ
diff --git a/SimpleLabel/SaveDialog.cpp b/SimpleLabel/SaveDialog.cpp
new file mode 100644
index 0000000..92ebb22
--- /dev/null
+++ b/SimpleLabel/SaveDialog.cpp
@@ -0,0 +1,141 @@
+/* SimpleLabel - a simple and light program for semi automatic labeling of regions
+ of interest on images or image sequences.
+ Developed at Laboratory for Active and Attentive Vision, York University, Toronto.
+ http://www.cse.yorku.ca/LAAV/home/ headed by John K. Tsotsos.
+
+ Copyright (C) 2010 Eugene Simine.
+
+ 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
+ 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 .
+
+ Contact: Eugene Simine or
+ John K. Tsotsos
+*/
+#include "SaveDialog.h"
+#include
+#include
+
+
+SaveDialog::SaveDialog(QWidget *parent, Qt::WindowFlags flags)
+ : QDialog(parent, flags)
+{
+ ui.setupUi(this);
+ connect(ui.rbtnBlackBgrd, SIGNAL(toggled(bool)), this, SLOT(rbtnFormat_toggled(bool)));
+ connect(ui.rbtnOrigImage, SIGNAL(toggled(bool)), this, SLOT(rbtnFormat_toggled(bool)));
+ connect(ui.rbtnMatlabStruct, SIGNAL(toggled(bool)), this, SLOT(rbtnFormat_toggled(bool)));
+ connect(ui.rbtnSimpleLabelXML, SIGNAL(toggled(bool)), this, SLOT(rbtnFormat_toggled(bool)));
+ connect(ui.rbtLabelMeXML, SIGNAL(toggled(bool)), this, SLOT(rbtnFormat_toggled(bool)));
+ connect(ui.rbtnSaveAsAVI, SIGNAL(toggled(bool)), this, SLOT(rbtnFormat_toggled(bool)));
+ connect(ui.rbtnSaveImgSeq, SIGNAL(toggled(bool)), this, SLOT(rbtnFormat_toggled(bool)));
+ connect(ui.edtFirstImageIndex, SIGNAL(textChanged(const QString &)), this, SLOT(on_edtFileNamePrefix_textChanged(const QString &)));
+
+ QValidator *v = new QIntValidator(0, 99999, this);
+ ui.edtFirstImageIndex->setValidator(v);
+ ui.edtLastImageIndex->setValidator(v);
+ rbtnFormat_toggled(true);
+}
+
+SaveDialog::~SaveDialog(void)
+{
+}
+
+
+void SaveDialog::rbtnFormat_toggled(bool b)
+{
+ if(b)
+ {
+ if(ui.rbtnBlackBgrd->isChecked() || ui.rbtnOrigImage->isChecked())
+ {
+ ui.rbtnSaveAsAVI->setEnabled(true);
+ ui.rbtnSaveImgSeq->setEnabled(true);
+ }
+ else
+ {
+ ui.rbtnSaveAsAVI->setDisabled(true);
+ ui.rbtnSaveImgSeq->setDisabled(true);
+ }
+
+ if(ui.rbtnBlackBgrd->isChecked() || ui.rbtnOrigImage->isChecked())
+ {
+ if(ui.rbtnSaveAsAVI->isChecked())
+ {
+ mBrowseSettings.title = tr("Save As avi");
+ mBrowseSettings.ext = tr(".avi");
+ mBrowseSettings.filter = tr("AVI Files (*.avi)");
+ mBrowseSettings.index = "";
+ }
+ else
+ {
+ mBrowseSettings.title = tr("Save As Image Sequense");
+ mBrowseSettings.ext = tr(".png");
+ mBrowseSettings.filter = tr("Image Files (*.png)");
+ mBrowseSettings.index = mBrowseSettings.index.sprintf("%05d",ui.edtFirstImageIndex->text().toInt());
+
+ }
+
+ }
+ else if(ui.rbtnMatlabStruct->isChecked())
+ {
+ mBrowseSettings.title = tr("Save As Matlab structure");
+ mBrowseSettings.ext = tr(".m");
+ mBrowseSettings.filter = tr("Matlab Files (*.m)");
+ mBrowseSettings.index = "";
+
+ }
+ else if(ui.rbtnSimpleLabelXML->isChecked())
+ {
+ mBrowseSettings.title = tr("Save As SimpleLabel XML");
+ mBrowseSettings.ext = tr(".xml");
+ mBrowseSettings.filter = tr("XML Files (*.xml)");
+ mBrowseSettings.index = "";
+ }
+ else if(ui.rbtLabelMeXML->isChecked())
+ {
+ mBrowseSettings.title = tr("Save As LabelMe XML");
+ mBrowseSettings.ext = tr(".xml");
+ mBrowseSettings.filter = tr("XML Files (*.xml)");
+ mBrowseSettings.index = mBrowseSettings.index.sprintf("%05d",ui.edtFirstImageIndex->text().toInt());
+ }
+
+ ui.edtSavePath->setText(mPath + ui.edtFileNamePrefix->text() + mBrowseSettings.index + mBrowseSettings.ext);
+ }
+}
+
+
+void SaveDialog::on_btnBrowse_clicked()
+{
+ QString saveFile = QFileDialog::getExistingDirectory(this, mBrowseSettings.title,
+ mPath,
+ QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
+
+
+ if(saveFile != "")
+ {
+ mPath = saveFile + "/";
+ }
+
+ rbtnFormat_toggled(true);
+}
+
+void SaveDialog::on_edtFileNamePrefix_textChanged(const QString &text)
+{
+ ui.edtSavePath->setText(mPath + text + mBrowseSettings.index + mBrowseSettings.ext);
+ //rbtnFormat_toggled(true);
+}
+
+QString SaveDialog::fixFileNameForMatlab(QString str)
+{
+ QString tmp = str.replace("-", "_");
+ tmp = tmp.replace("+", "_");
+ return tmp;
+}
\ No newline at end of file
diff --git a/SimpleLabel/SaveDialog.h b/SimpleLabel/SaveDialog.h
new file mode 100644
index 0000000..bcd2947
--- /dev/null
+++ b/SimpleLabel/SaveDialog.h
@@ -0,0 +1,62 @@
+/* SimpleLabel - a simple and light program for semi automatic labeling of regions
+ of interest on images or image sequences.
+ Developed at Laboratory for Active and Attentive Vision, York University, Toronto.
+ http://www.cse.yorku.ca/LAAV/home/ headed by John K. Tsotsos.
+
+ Copyright (C) 2010 Eugene Simine.
+
+ 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
+ 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 .
+
+ Contact: Eugene Simine or
+ John K. Tsotsos
+*/
+#ifndef SAVEDIALOG_H
+#define SAVEDIALOG_H
+
+#include
+#include "ui_SaveDialog.h"
+
+class SaveDialog :
+ public QDialog
+{
+Q_OBJECT
+
+public:
+ SaveDialog(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ virtual ~SaveDialog(void);
+
+protected slots:
+ virtual void rbtnFormat_toggled(bool b);
+ virtual void on_btnBrowse_clicked();
+ virtual void on_edtFileNamePrefix_textChanged(const QString &text);
+
+public:
+ QString mPath;
+ QString mPrefix;
+ Ui::SaveDialogUi ui;
+
+private:
+ QString fixFileNameForMatlab(QString str);
+
+private:
+ struct BrowseSettings
+ {
+ QString title;
+ QString ext;
+ QString filter;
+ QString index;
+ }mBrowseSettings;
+};
+
+#endif
\ No newline at end of file
diff --git a/SimpleLabel/SaveDialog.ui b/SimpleLabel/SaveDialog.ui
new file mode 100644
index 0000000..889bc16
--- /dev/null
+++ b/SimpleLabel/SaveDialog.ui
@@ -0,0 +1,261 @@
+
+
+ SaveDialogUi
+
+
+
+ 0
+ 0
+ 551
+ 353
+
+
+
+
+ 0
+ 0
+
+
+
+ Export Dialog
+
+
+ true
+
+
+ -
+
+
+ OK
+
+
+
+ -
+
+
+ Cancel
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 131
+ 31
+
+
+
+
+ -
+
+
+ Export Format
+
+
+
-
+
+
+ Labeled regions superimposed on the black background
+
+
+ true
+
+
+
+ -
+
+
+ Labeled regions superimposed on original images
+
+
+
+ -
+
+
+ Labled regions exported into Matlab structure
+
+
+
+ -
+
+
+ Labeled regions exported into SimpleLabel XML file
+
+
+
+ -
+
+
+ Labeled regions exported into LabelMe XML file
+
+
+
+
+
+
+ -
+
+
+ Save Format
+
+
+
-
+
+
+ Save As avi
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 140
+ 20
+
+
+
+
+ -
+
+
+ Save As Image Sequence
+
+
+ true
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Browse...
+
+
+
+ -
+
+
+ -
+
+
+ File Name
+
+
+
+ -
+
+
+ Starting image Index:
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+
+
+
+ 0
+
+
+ 5
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ 0
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Last image index
+
+
+
+
+
+
+
+
+
+
+
+ okButton
+ clicked()
+ SaveDialogUi
+ accept()
+
+
+ 278
+ 253
+
+
+ 96
+ 254
+
+
+
+
+ cancelButton
+ clicked()
+ SaveDialogUi
+ reject()
+
+
+ 369
+ 253
+
+
+ 179
+ 282
+
+
+
+
+
diff --git a/SimpleLabel/SimpleLabel.cpp b/SimpleLabel/SimpleLabel.cpp
new file mode 100644
index 0000000..fdea5e5
--- /dev/null
+++ b/SimpleLabel/SimpleLabel.cpp
@@ -0,0 +1,2814 @@
+/* SimpleLabel - a simple and light program for semi automatic labeling of regions
+ of interest on images or image sequences.
+ Developed at Laboratory for Active and Attentive Vision, York University, Toronto.
+ http://www.cse.yorku.ca/LAAV/home/ headed by John K. Tsotsos.
+
+ Copyright (C) 2010 Eugene Simine.
+
+ 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
+ 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 .
+
+ Contact: Eugene Simine or
+ John K. Tsotsos
+*/
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "SimpleLabel.h"
+#include "Constants.h"
+#include "Monitor.h"
+#include "About.h"
+#include "SaveDialog.h"
+
+const QPoint CommonFunctions::NULL_POINT = QPoint(-1,-1);
+const ViaPoint CommonFunctions::NULL_RECT = ViaPoint(-1, 0.0, QRect(0,0,0,0));
+const QPolygon CommonFunctions::NULL_POLYGON = QPolygon();
+
+void test_trans()
+{
+ QRect tmp(10, 10, 21, 21);
+ tmp.translate(-tmp.center());
+ QTransform tr;
+ tr.rotate(30);
+ QPointF p = tr.map(QPointF(tmp.topLeft()));
+ qDebug() << tmp;
+
+
+}
+
+
+SimpleLabel::SimpleLabel(QWidget *parent, Qt::WFlags flags)
+ : QMainWindow(parent, flags)
+{
+ //test_trans();
+
+ ui.setupUi(this);
+ setMouseTracking(true);
+ ui.centralWidget->setMouseTracking(true);
+ this->setWindowTitle(this->windowTitle() + " v" + QCoreApplication::applicationVersion());
+ mSaveDgl = new SaveDialog(this);
+ mAboutDlg = new About(this);
+ mDisplayImage = new QImage(W_DISPLAYIMAGE, H_DISPLAYIMAGE, QImage::Format_ARGB32);
+// mDisplayImage= NULL;
+ mMonitor= new Monitor();
+
+ connect(mMonitor, SIGNAL(imageChanged()), this, SLOT(showImage()), Qt::QueuedConnection);
+ connect(mSaveDgl, SIGNAL(accepted()), this, SLOT(on_SaveDialog_accept()));
+
+
+ mDrawPoint = CommonFunctions::NULL_POINT;
+ mDrawRect = CommonFunctions::NULL_RECT;
+ mMoveRect = false;
+ mRotateRect = false;
+ mSomethingChanged = false;
+ mResizeVertex = -1;
+ mIntrMethod = LinearIntr;
+ mNewPolygon = false;
+
+ ui.actionLoad_XML->setDisabled(true);
+ ui.actionLoad_LabelMe_XML->setDisabled(true);
+ ui.actionExport->setDisabled(true);
+ ui.hSliderFrames->setDisabled(true);
+ ui.actionNewPolygon->setDisabled(true);
+ ui.actionSave_Dialog->setEnabled(true);
+
+ mSaveDgl->ui.edtFirstImageIndex->setText("-1");
+
+ statusBar()->addPermanentWidget(&mStatus_Mode);
+ on_cmbBoxLabelShape_currentIndexChanged(Rect);
+
+ //setting up the popup menu
+ mPopupMenu = new QMenu(this);
+ QAction *item = new QAction("Add New Vertex", this);
+ item->setObjectName("AddVertex");
+ mPopupMenu->addAction(item);
+ item = new QAction("Remove This Vertex", this);
+ item->setObjectName("RemoveVertex");
+ mPopupMenu->addAction(item);
+
+ //create custom cursor
+ QBitmap cr(":/cursor_crosshair.bmp");
+#ifdef WIN32
+ QBitmap mask(":/cursor_crosshair_mask.bmp");
+#else
+ QBitmap mask(":/cursor_crosshair.bmp");
+#endif
+ mCrossHairCursor = new QCursor(cr, mask, 15, 15);
+}
+
+SimpleLabel::~SimpleLabel()
+{
+ releaseCapture();
+ resetLabels();
+ mMonitor->stop();
+ mMonitor->wait();
+ releaseCapture();
+ delete mMonitor;
+
+ delete mDisplayImage;
+
+ delete mCrossHairCursor;
+}
+
+void SimpleLabel::resetFilenames()
+{
+ mFileName = "";
+ mFileNamePrefix = "";
+ mPath = "";
+ mExtention = "";
+ mFirstFrameNumber = -1;
+}
+
+void SimpleLabel::resetLabels()
+{
+ mDrawPoint = CommonFunctions::NULL_POINT;
+ mDrawRect = CommonFunctions::NULL_RECT;
+ mDrawPolygon = CommonFunctions::NULL_POLYGON;
+ mMoveRect = false;
+ mMovePolygon = false;
+ mSomethingChanged = false;
+
+ for(int i = 0; i < mLabels.count(); i++)
+ {
+ mLabels[i].boxes.clear();
+ mLabels[i].viaPoints.clear();
+ mLabels[i].polygons.clear();
+ mLabels[i].viaPointsPoly.clear();
+ }
+ mLabels.clear();
+
+ ui.listLabels->clear();
+ mSaveDgl->ui.edtFirstImageIndex->setText("-1");
+}
+
+void SimpleLabel::on_actionAbout_triggered()
+{
+ mAboutDlg->show();
+}
+
+void SimpleLabel::releaseCapture()
+{
+ CvCapture *cap = mMonitor->getCvCapture();
+ if(cap)
+ {
+ cvReleaseCapture(&cap);
+ mMonitor->setCvCapture(NULL);
+ }
+}
+
+void SimpleLabel::on_actionOpen_triggered()
+{
+ int frames = 0;
+ int firstframe = 0;
+ QString s = QFileDialog::getOpenFileName(this, tr("Open Video"), ".", tr("Image Files (*.png *.tif *.tiff *.jpg);;Video Files (*.avi)"));
+ if(!s.isEmpty())
+ {
+ resetFilenames();
+ resetLabels();
+ releaseCapture();
+
+ //splitting the full path into parts
+ CommonFunctions::splitPath(s, mPath, mFileName, mFileNamePrefix, (uint)5, mFirstFrameNumber, mExtention);
+
+ if(mExtention == ".avi")
+ {
+ mFileNamePrefix = mFileName;
+ //before opening file we make sure that previously opened file if closed
+ releaseCapture();
+
+ // m_Monitor->setLoadBackground(ui.chkBox_Adapt2Bkgd->isChecked());
+ //opencv can't open capture from a child thread so we do it here
+ CvCapture* cap = cvCaptureFromFile(s.toAscii());
+ mMonitor->setCvCapture(cap);
+ frames = mMonitor->getFrameCount();
+
+ }
+ else if(mExtention == ".tif" || mExtention == ".tiff" || mExtention == ".png" || mExtention == ".jpg")
+ {
+ if(mFirstFrameNumber >= 0)
+ {
+ firstframe = mFirstFrameNumber;
+ mMonitor->setFisrtFilenameOfSequence(s);
+ frames = mMonitor->getFrameCount();
+ }
+ else if(mFirstFrameNumber == -1)
+ {
+ firstframe = mFirstFrameNumber;
+ mMonitor->setFisrtFilenameOfSequence(s);
+ frames = 1;
+ }
+ else
+ {
+ QMessageBox::information(this, "Error", s + ": incorrect numbering format. Expected: fname00000, fname00001, etc...");
+ }
+ }
+
+ if(frames > 0)
+ {
+ ui.hSliderFrames->setEnabled(true);
+ ui.hSliderFrames->setRange(firstframe, firstframe + frames - 1);
+ ui.actionLoad_XML->setEnabled(true);
+ ui.actionLoad_LabelMe_XML->setEnabled(true);
+ ui.actionExport->setEnabled(true);
+ }
+ else
+ ui.hSliderFrames->setDisabled(true);
+
+ }
+}
+
+void SimpleLabel::showImage()
+{
+ mMonitor->lockImages();
+ *mDisplayImage = mMonitor->getImage()->scaled(W_DISPLAYIMAGE, H_DISPLAYIMAGE, Qt::KeepAspectRatio);
+ mMonitor->releaseImages();
+
+ if(mMonitor->isRunning())
+ {
+ ui.hSliderFrames->setSliderPosition(mMonitor->getCurrentFrameNumber());
+ update();
+ }
+ else
+ repaint();
+}
+
+void SimpleLabel::drawCirclesAtVertices(QPainter *pt, QRect rc)
+{
+ int rad = CORNER_CIRCLE_RAD;
+ pt->setPen(Qt::black);
+// pt->setPen(Qt::PenStyle::SolidLine);
+
+ pt->drawEllipse(rc.topLeft(), rad, rad);
+ pt->drawEllipse(rc.topRight(), rad, rad);
+ pt->drawEllipse(rc.bottomRight(), rad, rad);
+ pt->drawEllipse(rc.bottomLeft(), rad, rad);
+
+ //draw line for rotation
+ int x = rc.center().x();
+ QLine ln(x, rc.top(), x, rc.top() - LENGTH_OF_ROTATION_LINE);
+ pt->drawLine(ln);
+ pt->drawEllipse(ln.p2(), rad, rad);
+}
+
+void SimpleLabel::drawCirclesAtVertices(QPainter *pt, QPolygon &pl)
+{
+ int rad = CORNER_CIRCLE_RAD;
+ pt->setPen(Qt::black);
+// pt->setPen(Qt::PenStyle::SolidLine);
+
+ for(int i = 0; i < pl.count(); i++)
+ {
+ pt->drawEllipse(pl[i], rad, rad);
+ }
+}
+
+
+void SimpleLabel::paintEvent (QPaintEvent*)
+{
+ QPainter pt(this);
+ int fr = mMonitor->getCurrentFrameNumber();
+ if(mDisplayImage)
+ {
+ pt.drawImage(WINDOW_OFFSET_X, WINDOW_OFFSET_Y, *mDisplayImage);
+ }
+
+ if(ui.chkBoxShowAllLabels->isChecked())
+ {
+ QBrush br(QColor(255,255,255, 100));
+ int row = ui.listLabels->currentRow();
+ int n, k;
+ QRect rc;
+
+ for(n = 0; n < mLabels.count(); n++)
+ {
+ if(row == n)
+ br.setColor(QColor(0,255,0, 100));
+ else
+ br.setColor(QColor(255,255,255, 100));
+
+ if(mLabels[n].boxes.count() > 0 &&
+ fr >= mLabels[n].boxes.first().frame &&
+ fr <= mLabels[n].boxes.last().frame)
+ {
+ k = fr - mLabels[n].boxes.first().frame;
+ rc = imageToScreen(mLabels[n].boxes[k].rc);
+
+ pt.fillRect(rc, br);
+ pt.setPen( Qt::black );
+ pt.drawRect(rc);
+ }
+ }
+ }
+ else
+ {
+ switch(mShapeMode)
+ {
+ case Rect:
+ drawModeRect(&pt, fr);
+ break;
+ case Polyg:
+ drawModePoly(&pt, fr);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void SimpleLabel::drawModeRect(QPainter *pt, int frame)
+{
+ if(mDrawRect != CommonFunctions::NULL_RECT)
+ {
+ QBrush br(QColor(255,255,255, 100));
+ int row = ui.listLabels->currentRow();
+ if(row >= 0)
+ {
+ if(mLabels[row].viaPoints.count() > 0 &&
+ (frame < mLabels[row].viaPoints.first().frame || frame > mLabels[row].viaPoints.last().frame))
+ {
+ br.setColor(QColor(255,0,0, 100));
+ }
+ else
+ {
+ for(int i = 0; i < mLabels[row].viaPoints.count(); i++)
+ {
+ if(mLabels[row].viaPoints[i].frame == frame)
+ {
+ br.setColor(QColor(0,255,0, 100));
+ break;
+ }
+ }
+ }
+ }
+
+ QRect drc = imageToScreen(mDrawRect.rc);
+ //rotation
+ pt->translate(drc.center());
+ pt->rotate(-mDrawRect.angle);
+ pt->translate(-drc.center());
+
+ pt->fillRect(drc, br);
+ pt->setPen( Qt::black );
+ pt->drawRect(drc);
+
+ drawCirclesAtVertices(pt, drc);
+ pt->rotate(mDrawRect.angle);
+ }
+}
+
+//QRect SimpleLabel::rotateRect(QRect rc, float a)
+//{
+// qDebug() << "Original rect " << rc;
+// QRect tmp;
+// QTransform tr;
+// tr.translate(rc.top(), rc.left());
+// tmp = tr.mapRect(rc);
+// qDebug() << "Translated rect " << tmp;
+// rc.translate(10,10);
+// tr.rotate(30);
+// tmp = tr.mapRect(tmp);
+// qDebug() << "Translated and rotated rect " << tmp;
+//
+// return tmp;
+//}
+
+void SimpleLabel::drawModePoly(QPainter *pt, int frame)
+{
+ int row = ui.listLabels->currentRow();
+ if(mNewPolygon)
+ {
+ if(row >= 0)
+ {
+ QPolygon p = imageToScreen(mFirstPolygon);
+ pt->drawPolyline(p);
+ drawCirclesAtVertices(pt, p);
+ }
+ }
+ else if(mDrawPolygon != CommonFunctions::NULL_POLYGON)
+ {
+ QBrush br(QColor(255,255,255, 100));
+ if(row >= 0)
+ {
+ if(mLabels[row].viaPointsPoly.count() > 0 &&
+ (frame < mLabels[row].viaPointsPoly.first().frame || frame > mLabels[row].viaPointsPoly.last().frame))
+ {
+ br.setColor(QColor(255,0,0, 100));
+ }
+ else
+ {
+ for(int i = 0; i < mLabels[row].viaPointsPoly.count(); i++)
+ {
+ if(mLabels[row].viaPointsPoly[i].frame == frame)
+ {
+ br.setColor(QColor(0,255,0, 100));
+ break;
+ }
+ }
+ }
+ }
+
+ QPolygon dpl = imageToScreen(mDrawPolygon);
+ pt->setBrush(br);
+ pt->setPen( Qt::black );
+ pt->drawPolygon(dpl);
+
+// pt->drawRect(drc);
+
+ drawCirclesAtVertices(pt, dpl);
+ }
+}
+
+
+void SimpleLabel::on_chkBoxShowAllLabels_toggled(bool b)
+{
+ ui.btnAddLabel->setDisabled(b);
+ update();
+}
+
+void SimpleLabel::on_hSliderFrames_valueChanged(int v)
+{
+ ui.lblCurrentFrame->setText(QString::number(v));
+
+ if(mMonitor->isRunning())
+ {
+ if(mShapeMode == Rect)
+ setDrawRectToFrame(v);
+ else if(mShapeMode == Polyg)
+ setDrawPolygonToFrame(v);
+ }
+ else
+ {
+ mMonitor->moveToFrame(v);
+ if(mShapeMode == Rect)
+ setDrawRectToFrame(v);
+ else if(mShapeMode == Polyg)
+ setDrawPolygonToFrame(v);
+ showImage();
+ }
+}
+
+void SimpleLabel::setDrawRectToFrame(int v)
+{
+ int row = ui.listLabels->currentRow();
+ if(row >= 0)
+ {
+ if(mLabels[row].boxes.count() > 0)
+ {
+ int fr = v - mLabels[row].viaPoints[0].frame;
+ if(fr >= 0 && mLabels[row].boxes.count() > fr)
+ {
+ if(mLabels[row].boxes[fr].frame != v)
+ {
+ QString s = QString("Frames are out of sync: box = ") + mLabels[row].boxes[fr].frame + "; v = " + v;
+ qDebug() << s;
+ }
+ //mDrawRect.rc = mLabels[row].boxes[fr].rc;
+ mDrawRect = mLabels[row].boxes[fr];
+ }
+ }
+ }
+}
+
+void SimpleLabel::setDrawPolygonToFrame(int v)
+{
+ int row = ui.listLabels->currentRow();
+ if(row >= 0)
+ {
+ if(mLabels[row].polygons.count() > 0)
+ {
+ int fr = v - mLabels[row].viaPointsPoly[0].frame;
+ if(fr >= 0 && mLabels[row].polygons.count() > fr)
+ {
+ if(mLabels[row].polygons[fr].frame != v)
+ {
+ QString s = QString("Frames are out of sync: polygon = ") + mLabels[row].polygons[fr].frame + "; v = " + v;
+ qDebug() << s;
+ }
+ mDrawPolygon = mLabels[row].polygons[fr].pl;
+ }
+ }
+ }
+}
+
+void SimpleLabel::mousePressEvent( QMouseEvent * e )
+{
+ QPoint pt = screenToImage(e->pos());
+
+ if(e->button() == Qt::RightButton)
+ {
+ int row = ui.listLabels->currentRow();
+ int vertex = CommonFunctions::checkForVertices(pt, mDrawPolygon);
+ if(vertex >= 0 && row >= 0)
+ {
+ QAction *tmp = mPopupMenu->exec(QCursor::pos());
+ if(tmp == NULL)
+ {
+ }
+ else if(tmp->objectName() == "AddVertex")
+ {
+ QPoint p1, p2, p;
+ int v2 = (vertex + 1)%mLabels[row].viaPointsPoly[0].pl.count();
+
+ //add new vertex to each via point and recalculate polygons
+ QList::iterator i;
+ for(i = mLabels[row].viaPointsPoly.begin(); i != mLabels[row].viaPointsPoly.end(); ++i)
+ {
+ p1 = i->pl.point(vertex);
+ p2 = i->pl.point(v2);
+ p = (p1 + p2)/2;
+
+ i->pl.insert(v2, p);
+ }
+ rebuildLabelPolygons();
+ mDrawPolygon = mLabels[row].findPolygonByFrame(mMonitor->getCurrentFrameNumber())->pl;
+ update();
+ }
+ else if(tmp->objectName() == "RemoveVertex")
+ {
+ //add new vertex to each via point and recalculate polygons
+ QList::iterator i;
+ for(i = mLabels[row].viaPointsPoly.begin(); i != mLabels[row].viaPointsPoly.end(); ++i)
+ {
+ i->pl.remove(vertex);
+ }
+ rebuildLabelPolygons();
+ mDrawPolygon = mLabels[row].findPolygonByFrame(mMonitor->getCurrentFrameNumber())->pl;
+ update();
+ }
+ }
+ }
+ else if(e->button() == Qt::LeftButton && mMonitor->isInitialized() && !ui.chkBoxShowAllLabels->isChecked())
+ {
+ //check if mouse was clicked inside the image
+ if(mDisplayImage->rect().contains(pt))
+ {
+ switch(mShapeMode)
+ {
+ case Rect:
+ //check if we should resize
+ //mResizeVertex = CommonFunctions::checkForVertices(pt, mDrawRect.rc);
+ mResizeVertex = CommonFunctions::checkForVerticesWithRotation(pt, mDrawRect);
+ if( mResizeVertex >= 0)
+ {
+ qDebug() << "Found vertex " << mResizeVertex;
+ pt = CommonFunctions::getOpposingVertex(mDrawRect.rc, mResizeVertex);
+
+ //bring pt to screen frame of reference by rotating it in opposite direction
+ pt = CommonFunctions::rotatePointAboutPoint(pt, -mDrawRect.angle, mDrawRect.rc.center());
+ qDebug() << "Rect: " << mDrawRect.rc;
+ qDebug() << "Opposing vertex: " << pt << "\n";
+ }
+ //check if we need to rotate the rectangle
+ else if(CommonFunctions::checkForRotation(pt, mDrawRect))
+ {
+ mRotateRect = true;
+ }
+ //ckeck if the click is withing the rectangle
+ else if(mDrawRect.rc.contains(CommonFunctions::rotatePointAboutPoint(pt, mDrawRect.angle, mDrawRect.rc.center())))
+ {
+ mMoveRect = true;
+ }
+ break;
+ case Polyg:
+ mResizeVertex = CommonFunctions::checkForVertices(pt, mDrawPolygon);
+ //drawing new polygon
+ if(mNewPolygon)
+ {
+ int row = ui.listLabels->currentRow();
+ if(row >= 0)
+ {
+
+ mFirstPolygon << pt;
+ }
+ update();
+ }
+ //resizing
+ else if(mResizeVertex >= 0)
+ { //this is intentional
+ }
+ //moving
+ else if(mDrawPolygon.containsPoint(pt, Qt::OddEvenFill))
+ {
+ mMovePolygon = true;
+ }
+ break;
+ default:
+ break;
+ }
+ mDrawPoint = pt;
+ }
+ }
+}
+
+
+void SimpleLabel::mouseReleaseEvent( QMouseEvent* )
+{
+ if(mMonitor->isInitialized() && !ui.chkBoxShowAllLabels->isChecked())
+ {
+ mDrawPoint = CommonFunctions::NULL_POINT;
+ mMoveRect = false;
+ mRotateRect = false;
+ mMovePolygon = false;
+ mResizeVertex = -1;
+
+ //reculculate boxes if something changed
+ if(mSomethingChanged)
+ {
+ if(mShapeMode == Rect)
+ {
+ addViaPoint(ui.hSliderFrames->value(), mDrawRect);
+ }
+ else if(mShapeMode == Polyg)
+ {
+ addViaPointPoly(ui.hSliderFrames->value(), mDrawPolygon);
+ }
+ mSomethingChanged = false;
+ update();
+ }
+ }
+}
+
+void SimpleLabel::mouseMoveEvent( QMouseEvent * e )
+{
+ //working in image coordinates
+ QPoint pt = screenToImage(e->pos());
+
+ //changing mouse cursor
+ if(mMonitor->isInitialized())
+ {
+ if(mDisplayImage->rect().contains(pt))
+ {
+ if(this->cursor().shape() != Qt::CrossCursor)
+ {
+ this->setCursor(*mCrossHairCursor);
+ }
+ }
+ else
+ {
+ if(this->cursor().shape() != Qt::ArrowCursor)
+ {
+ QCursor cr(Qt::ArrowCursor);
+ this->setCursor(cr);
+ }
+ }
+ }
+
+ if(e->buttons() & Qt::LeftButton &&
+ mMonitor->isInitialized() &&
+ mDrawPoint != CommonFunctions::NULL_POINT &&
+ !ui.chkBoxShowAllLabels->isChecked() &&
+ !mNewPolygon)
+ {
+ switch(mShapeMode)
+ {
+ case Rect:
+ //move existing rectangle
+ if(mMoveRect)
+ {
+ QPoint dp = pt - mDrawPoint;
+
+ mDrawRect.rc.translate(dp);
+ mDrawPoint = pt;
+ }
+ //resize the shape
+ else if(mResizeVertex >= 0)
+ {
+ //original
+ /*mDrawRect.rc.setCoords(mDrawPoint.x(), mDrawPoint.y(), pt.x(), pt.y());
+ mDrawRect.rc = mDrawRect.rc.normalized();*/
+
+ //mouse position in rect frame
+ QPoint tpt = CommonFunctions::rotatePointAboutPoint(pt, mDrawRect.angle, mDrawRect.rc.center());
+ // reference point that should alwasy remain in the same point on the image
+ QPoint ref_pt = CommonFunctions::rotatePointAboutPoint(mDrawPoint, mDrawRect.angle, mDrawRect.rc.center());
+ //true size of the new rect
+ QSize sz(tpt.x() - ref_pt.x(), tpt.y() - ref_pt.y());
+
+ //not rotated rect in screen coords rect
+ QRect tmp(mDrawPoint, sz);
+ tmp = tmp.normalized();
+
+ //rotate center of this rect about the ref point by -angle
+ //to find the proper position of the new center
+ QPoint new_center = CommonFunctions::rotatePointAboutPoint(tmp.center(), -mDrawRect.angle, mDrawPoint);
+ //translate rect so that it's center is the new position
+ tmp.translate(new_center - tmp.center());
+
+ mDrawRect.rc = tmp;
+
+ }
+ //rotate rectangle
+ else if(mRotateRect)
+ {
+ QPoint o = mDrawRect.rc.center();
+ QPoint v1 = pt - o;
+ QPoint v2 = mDrawPoint - o;
+ int row = ui.listLabels->currentRow();
+ double ang = CommonFunctions::findAngleBetweenVectors2(v1, v2);
+ if(row >= 0)
+ {
+ mDrawRect.angle = mLabels[row].findBoxByFrame(mDrawRect.frame)->angle + ang;
+ }
+ }
+ //draw new rectangle
+ else
+ {
+ mDrawRect.rc.setCoords(mDrawPoint.x(), mDrawPoint.y(), pt.x(), pt.y());
+ mDrawRect.rc = mDrawRect.rc.normalized();
+ mDrawRect.angle = 0;
+ mDrawRect.frame = ui.lblCurrentFrame->text().toInt();
+ }
+
+ mDrawRect.rc = mDisplayImage->rect().intersect(mDrawRect.rc);
+ mSomethingChanged = true;
+ break;
+ case Polyg:
+ //move the polygon
+ if(mMovePolygon)
+ {
+ QPoint dp = pt - mDrawPoint;
+ mDrawPolygon.translate(dp);
+ mDrawPoint = pt;
+ mSomethingChanged = true;
+ }
+ else if(mResizeVertex >= 0)
+ {
+ mDrawPolygon.setPoint(mResizeVertex, pt);
+ mSomethingChanged = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ repaint();
+ }
+}
+
+QPoint SimpleLabel::screenToImage(QPoint scr)
+{
+ return QPoint(scr.x() - WINDOW_OFFSET_X, scr.y() - WINDOW_OFFSET_Y);
+}
+
+
+QPoint SimpleLabel::imageToScreen(QPoint im)
+{
+ return QPoint(im.x() + WINDOW_OFFSET_X, im.y() + WINDOW_OFFSET_Y);
+}
+
+QPoint SimpleLabel::imageToImage(int srcW, int srcH, QPoint srcP, int destW, int destH)
+{
+ QPoint res;
+ double kX, kY;
+
+ kX = (double)destW/(double)srcW;
+ kY = (double)destH/(double)srcH;
+
+ res.setX(ROUND(srcP.x() * kX));
+ res.setY(ROUND(srcP.y() * kY));
+
+ return res;
+}
+
+QRect SimpleLabel::imageToImage(int srcW, int srcH, QRect srcP, int destW, int destH)
+{
+ QRect res;
+ QPoint tl = imageToImage(srcW, srcH, srcP.topLeft(), destW, destH);
+ QPoint br = imageToImage(srcW, srcH, srcP.bottomRight(), destW, destH);
+
+ res.setTopLeft(tl);
+ res.setBottomRight(br);
+
+ return res;
+}
+
+
+QRect SimpleLabel::screenToImage(QRect scr)
+{
+ return scr.translated(-WINDOW_OFFSET_X, -WINDOW_OFFSET_Y);
+}
+
+
+QRect SimpleLabel::imageToScreen(QRect im)
+{
+ return im.translated(WINDOW_OFFSET_X, WINDOW_OFFSET_Y);
+}
+
+QPolygon SimpleLabel::screenToImage(QPolygon scr)
+{
+ return scr.translated(-WINDOW_OFFSET_X, -WINDOW_OFFSET_Y);
+}
+
+QPolygon SimpleLabel::imageToScreen(QPolygon im)
+{
+ return im.translated(WINDOW_OFFSET_X, WINDOW_OFFSET_Y);
+}
+
+QPolygon SimpleLabel::imageToImage(int srcW, int srcH, QPolygon srcP, int destW, int destH)
+{
+ QPolygon res;
+ QPoint p;
+ for(int i = 0; i < srcP.count(); i++)
+ {
+ p = imageToImage(srcW, srcH, srcP[i], destW, destH);
+ res << p;
+ }
+
+ return res;
+}
+
+void SimpleLabel::on_btnAddLabel_pressed()
+{
+ Label lb;
+ lb.number = mLabels.count();
+ lb.name = "New Label";
+ lb.shape = Polyg;
+ lb.desc = "";
+ mLabels.append(lb);
+
+ updateListView();
+}
+
+void SimpleLabel::on_btnDeleteLabel_pressed()
+{
+ int row = ui.listLabels->currentRow();
+
+ if(row >= 0 && row < mLabels.count())
+ {
+ mLabels.removeAt(row);
+ }
+
+ updateListView();
+}
+
+void SimpleLabel::updateListView()
+{
+ int i;
+ ui.listLabels->clear();
+
+ for(i = 0; i < mLabels.count(); i++)
+ {
+ QListWidgetItem *it = new QListWidgetItem();
+ it->setText(mLabels[i].name);
+ it->setFlags(it->flags() | Qt::ItemIsEditable);
+ ui.listLabels->addItem(it);
+ }
+}
+
+void SimpleLabel::on_listLabels_itemChanged(QListWidgetItem* item)
+{
+ int row = ui.listLabels->row(item);
+
+ mLabels[row].name = item->text();
+}
+
+void SimpleLabel::on_listLabels_currentItemChanged (QListWidgetItem * current, QListWidgetItem * previous)
+{
+ int row = ui.listLabels->row(previous);
+
+ if(row >= 0 && row < mLabels.count())
+ {
+ mLabels[row].desc = ui.textEditDescription->toPlainText();
+ mLabels[row].shape = mShapeMode;
+ }
+
+ row = ui.listLabels->row(current);
+ if(row >= 0 && row < mLabels.count())
+ {
+ mShapeMode = mLabels[row].shape;
+ ui.textEditDescription->setText(mLabels[row].desc);
+ ui.cmbBoxLabelShape->setCurrentIndex(mShapeMode);
+ switch(mShapeMode)
+ {
+ case Rect:
+ if(mLabels[row].boxes.count() > 0)
+ {
+ ViaPoint *p = mLabels[row].findBoxByFrame(mMonitor->getCurrentFrameNumber());
+ if(p != NULL)
+ mDrawRect = *p;
+ }
+ break;
+ case Polyg:
+ if(mLabels[row].polygons.count() > 0)
+ {
+ ViaPointPolygon *p = mLabels[row].findPolygonByFrame(mMonitor->getCurrentFrameNumber());
+ if(p != NULL)
+ mDrawPolygon = p->pl;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ update();
+}
+
+void SimpleLabel::on_textEditDescription_textChanged()
+{
+ int row = ui.listLabels->currentRow();
+ if(row >= 0)
+ {
+ mLabels[row].desc = ui.textEditDescription->toPlainText();
+ }
+}
+
+//add new polygon via point to the structure
+void SimpleLabel::addViaPointPoly(int frame, QPolygon pl, bool addRect)
+{
+ bool ok = true;
+ int row = ui.listLabels->currentRow();
+ if(row < 0)
+ {
+ QMessageBox::information(NULL,"Label", "Select a label.");
+ ok = false;
+ }
+
+ if(ok)
+ {
+ QList::iterator i;
+ //find the place where to put new polygon
+ for(i = mLabels[row].viaPointsPoly.begin(); i != mLabels[row].viaPointsPoly.end(); i++)
+ {
+ if(i->frame > frame || i->frame == frame)
+ {
+ break;
+ }
+ }
+
+ //if the frame is already a via point replace it
+ if(i != mLabels[row].viaPointsPoly.end() && i->frame == frame)
+ {
+ i->frame = frame;
+ i->pl = pl;
+ }
+ else
+ {
+ //insert new via point
+ ViaPointPolygon v;
+ v.frame = frame;
+ v.pl = pl;
+ mLabels[row].viaPointsPoly.insert(i, v);
+ }
+
+ rebuildLabelPolygons();
+
+ //last parameter is false bacause we don't want to add a polygon
+ //(we just added it)
+ if(addRect)
+ addViaPoint(frame, pl.boundingRect());
+ }
+}
+
+//add new point in the right place in the label structure
+void SimpleLabel::addViaPoint(int frame, QRect rc)
+{
+ bool ok = true;
+ int row = ui.listLabels->currentRow();
+ if(row < 0)
+ {
+ QMessageBox::information(NULL,"Label", "Select a label.");
+ ok = false;
+ }
+
+ if(ok)
+ {
+ QList::iterator i;
+ //find the place where to put new point
+ for(i = mLabels[row].viaPoints.begin(); i != mLabels[row].viaPoints.end(); i++)
+ {
+ if(i->frame > frame || i->frame == frame)
+ {
+ break;
+ }
+ }
+
+ ViaPoint v;
+ v.frame = frame;
+ v.rc = rc;
+ //if the frame is already a via point replace it
+ if(i != mLabels[row].viaPoints.end() && i->frame == frame)
+ {
+ i->frame = v.frame;
+ i->rc = v.rc;
+ }
+ else
+ {
+ //insert new via point
+ mLabels[row].viaPoints.insert(i, v);
+ }
+ rebuildLabelBoxes();
+ }
+}
+
+//add new point in the right place in the label structure
+void SimpleLabel::addViaPoint(int frame, ViaPoint v)
+{
+ bool ok = true;
+ int row = ui.listLabels->currentRow();
+ if(row < 0)
+ {
+ QMessageBox::information(NULL,"Label", "Select a label.");
+ ok = false;
+ }
+
+ if(ok)
+ {
+ QList::iterator i;
+ //find the place where to put new point
+ for(i = mLabels[row].viaPoints.begin(); i != mLabels[row].viaPoints.end(); i++)
+ {
+ if(i->frame > frame || i->frame == frame)
+ {
+ break;
+ }
+ }
+
+ //if the frame is already a via point replace it
+ if(i != mLabels[row].viaPoints.end() && i->frame == frame)
+ {
+ *i = v;
+ i->frame = frame;
+ }
+ else
+ {
+ //insert new via point
+ ViaPoint nv = v;
+ nv.frame = frame;
+ mLabels[row].viaPoints.insert(i, nv);
+ }
+ rebuildLabelBoxes();
+
+ //add polygon viaPoint too
+ int numVerticies = 4;
+ if( mLabels[row].viaPointsPoly.count() > 0)
+ {
+ numVerticies = mLabels[row].viaPointsPoly[0].pl.count();
+ }
+
+ QPolygon newPolyg;
+ newPolyg << v.rc.topLeft();
+ newPolyg << v.rc.topRight();
+ newPolyg << v.rc.bottomRight();
+
+ for(int ver = 3; ver < numVerticies; ver++)
+ {
+ newPolyg << v.rc.bottomLeft();
+ }
+
+ //we don't want to add new rectangle
+ //we just added it
+ addViaPointPoly(v.frame, newPolyg, false);
+
+ }
+}
+
+//recalculate the label polygons
+void SimpleLabel::rebuildLabelPolygons()
+{
+ int row = ui.listLabels->currentRow();
+ double df = 0.0;
+ QPointF dp;
+ ViaPointPolygon b1, b2;
+ ViaPointPolygon newPolyg;
+ QPoint np;
+ int t;
+
+ if(row >= 0)
+ {
+ QList::iterator i;
+ mLabels[row].polygons.clear();
+
+
+ if(mLabels[row].viaPointsPoly.count() == 1)
+ {
+ mLabels[row].polygons << mLabels[row].viaPointsPoly[0];
+ }
+
+ for(i = mLabels[row].viaPointsPoly.begin(); i != mLabels[row].viaPointsPoly.end() - 1; ++i)
+ {
+ b1 = *i;
+ b2 = *(i + 1);
+ if(mIntrMethod == LinearIntr)
+ {
+ df = b2.frame - b1.frame;
+ }
+
+ for(int k = b1.frame; k <= b2.frame; k++)
+ {
+ t = k - b1.frame;
+ newPolyg.frame = k;
+ newPolyg.pl = QPolygon();
+
+ for(int j = 0; j < b1.pl.count(); j++)
+ {
+ if(mIntrMethod == LinearIntr)
+ {
+ QPointF p1 = b2.pl.point(j) - b1.pl.point(j);
+ dp = p1/df;
+ np = linearInterpolation(b1.pl.point(j), dp, t);
+ }
+ newPolyg.pl << np;
+ }
+
+ //the first frame of the new segment is the same as the last frame of the
+ //previous segment, so we rewrite it
+ if(k == b1.frame && mLabels[row].polygons.count() > 0)
+ {
+ mLabels[row].polygons[mLabels[row].polygons.count() - 1] = newPolyg;
+ }
+ else
+ {
+ mLabels[row].polygons << newPolyg;
+ }
+ }
+ }
+ }
+}
+
+
+//recalculate the label boxes
+void SimpleLabel::rebuildLabelBoxes()
+{
+ int row = ui.listLabels->currentRow();
+
+ if(row >= 0)
+ {
+ QList::iterator i;
+ mLabels[row].boxes.clear();
+ ViaPoint b1, b2;
+ ViaPoint newbox;
+ double dx = 0, dy = 0;
+ double dw = 0, dh = 0;
+ double df;
+ double da = 0;
+ int t;
+
+ //special case
+ if(mLabels[row].viaPoints.count() == 1)
+ {
+ mLabels[row].boxes << mLabels[row].viaPoints[0];
+ }
+
+ for(i = mLabels[row].viaPoints.begin(); i != mLabels[row].viaPoints.end() - 1; ++i)
+ {
+ b1 = *i;
+ b2 = *(i+1);
+
+ if(mIntrMethod == LinearIntr)
+ {
+ df = b2.frame - b1.frame;
+ dx = (b2.rc.left() - b1.rc.left())/df;
+ dy = (b2.rc.top() - b1.rc.top())/df;
+ dw = (b2.rc.width() - b1.rc.width())/df;
+ dh = (b2.rc.height() - b1.rc.height())/df;
+ da = (b2.angle - b1.angle)/df;
+ }
+ for(int k = b1.frame; k <= b2.frame; k++)
+ {
+ t = k - b1.frame;
+ if(mIntrMethod == LinearIntr)
+ {
+ newbox.rc = linearInterpolation(b1.rc, dx, dy, dw, dh, t);
+ newbox.frame = k;
+ newbox.angle = b1.angle + da*t;
+ }
+ else if(mIntrMethod == Motion)
+ {
+ //DO THE MOTION ALGORITHM HERE
+ }
+
+ //the first frame of the new segment is the same as the last frame of the
+ //previous segment, so we rewrite it
+ if(k == b1.frame && mLabels[row].boxes.count() > 0)
+ {
+ mLabels[row].boxes[mLabels[row].boxes.count() - 1] = newbox;
+ }
+ else
+ {
+ mLabels[row].boxes.append(newbox);
+ }
+ }
+ }
+ }
+}
+
+QPoint SimpleLabel::linearInterpolation(QPoint src, QPointF dt, int t)
+{
+ return src + (t*dt).toPoint();
+}
+
+QRect SimpleLabel::linearInterpolation(QRect initPoint, double dx, double dy, double dw, double dh, int t)
+{
+ QRect res;
+ res.setLeft(ROUND(initPoint.left() + t*dx));
+ res.setTop(ROUND(initPoint.top() + t*dy));
+ res.setWidth(ROUND(initPoint.width() + t*dw));
+ res.setHeight(ROUND(initPoint.height() + t*dh));
+
+ return res;
+}
+
+void SimpleLabel::on_btnToBeginning_pressed()
+{
+ int row = ui.listLabels->currentRow();
+ if(mShapeMode == Rect)
+ {
+ if( row >= 0 && mLabels[row].viaPoints.count() > 0)
+ {
+ ui.hSliderFrames->setValue(mLabels[row].viaPoints[0].frame);
+ }
+ }
+ else if(mShapeMode == Polyg)
+ {
+ if( row >= 0 && mLabels[row].viaPointsPoly.count() > 0)
+ {
+ ui.hSliderFrames->setValue(mLabels[row].viaPointsPoly[0].frame);
+ }
+ }
+}
+
+void SimpleLabel::on_btnPrevViaPoint_pressed()
+{
+ int row = ui.listLabels->currentRow();
+ if(mShapeMode == Rect)
+ {
+ if( row >= 0 && mLabels[row].viaPoints.count() > 0)
+ {
+ int fr = ui.hSliderFrames->value();
+ int i = mLabels[row].viaPoints.count() - 1;
+ while(mLabels[row].viaPoints[i].frame >= fr && i > 0)
+ {
+ i--;
+ }
+
+ ui.hSliderFrames->setValue(mLabels[row].viaPoints[i].frame);
+ }
+ }
+ else if(mShapeMode == Polyg)
+ {
+ if( row >= 0 && mLabels[row].viaPointsPoly.count() > 0)
+ {
+ int fr = ui.hSliderFrames->value();
+ int i = mLabels[row].viaPointsPoly.count() - 1;
+ while(mLabels[row].viaPointsPoly[i].frame >= fr && i > 0)
+ {
+ i--;
+ }
+
+ ui.hSliderFrames->setValue(mLabels[row].viaPointsPoly[i].frame);
+ }
+ }
+}
+
+void SimpleLabel::on_btnStop_pressed()
+{
+ mMonitor->stop();
+}
+
+void SimpleLabel::on_btnRemoveViaPoint_pressed()
+{
+ int row = ui.listLabels->currentRow();
+ if(mShapeMode == Rect)
+ {
+ if( row >= 0 && mLabels[row].viaPoints.count() > 0)
+ {
+ int fr = ui.hSliderFrames->value();
+ for(int i = 0; i < mLabels[row].viaPoints.count(); i++)
+ {
+ if(mLabels[row].viaPoints[i].frame == fr)
+ {
+ mLabels[row].viaPoints.removeAt(i);
+ if(mLabels[row].viaPoints.count() > 0)
+ {
+ rebuildLabelBoxes();
+ }
+ break;
+ }
+ }
+ }
+ }
+ else if(mShapeMode == Polyg)
+ {
+ if( row >= 0 && mLabels[row].viaPointsPoly.count() > 0)
+ {
+ int fr = ui.hSliderFrames->value();
+ for(int i = 0; i < mLabels[row].viaPointsPoly.count(); i++)
+ {
+ if(mLabels[row].viaPointsPoly[i].frame == fr)
+ {
+ mLabels[row].viaPointsPoly.removeAt(i);
+ if(mLabels[row].viaPointsPoly.count() > 0)
+ {
+ rebuildLabelPolygons();
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+void SimpleLabel::on_btnPlay_pressed()
+{
+ mMonitor->start();
+}
+
+
+void SimpleLabel::on_btnNextViaPoint_pressed()
+{
+ int row = ui.listLabels->currentRow();
+ if(mShapeMode == Rect)
+ {
+ if( row >= 0 && mLabels[row].viaPoints.count() > 0)
+ {
+ int fr = ui.hSliderFrames->value();
+ int i = 0;
+ while(mLabels[row].viaPoints[i].frame <= fr && i < mLabels[row].viaPoints.count() - 1)
+ {
+ i++;
+ }
+
+ ui.hSliderFrames->setValue(mLabels[row].viaPoints[i].frame);
+ }
+ }
+ else if(mShapeMode == Polyg)
+ {
+ if( row >= 0 && mLabels[row].viaPointsPoly.count() > 0)
+ {
+ int fr = ui.hSliderFrames->value();
+ int i = 0;
+ while(mLabels[row].viaPointsPoly[i].frame <= fr && i < mLabels[row].viaPointsPoly.count() - 1)
+ {
+ i++;
+ }
+
+ ui.hSliderFrames->setValue(mLabels[row].viaPointsPoly[i].frame);
+ }
+ }
+}
+
+void SimpleLabel::on_btnToEnd_pressed()
+{
+ int row = ui.listLabels->currentRow();
+ if(mShapeMode == Rect)
+ {
+ if( row >= 0 && mLabels[row].viaPoints.count() > 0)
+ {
+ ui.hSliderFrames->setValue(mLabels[row].viaPoints.last().frame);
+ }
+ }
+ else if(mShapeMode == Polyg)
+ {
+ if( row >= 0 && mLabels[row].viaPointsPoly.count() > 0)
+ {
+ ui.hSliderFrames->setValue(mLabels[row].viaPointsPoly.last().frame);
+ }
+ }
+}
+
+void SimpleLabel::exportToMovie(bool origBkgrd)
+{
+ int nLbls = ui.listLabels->count();
+ int startF, endF;
+ int i, t;
+ QSize origSz = mMonitor->getImageSize();
+
+ if(nLbls > 0)
+ {
+ //find the earliest frame in all the labels
+ startF = qMax( mSaveDgl->ui.edtFirstImageIndex->text().toInt(), mFirstFrameNumber);
+ endF = qMin(mSaveDgl->ui.edtLastImageIndex->text().toInt(), mFirstFrameNumber + mMonitor->getFrameCount() - 1);
+ if(startF > mFirstFrameNumber + mMonitor->getFrameCount() - 1)
+ {
+ QMessageBox::information(this, "Index is out of bounds", "Starting frame number is larger than image sequence length.");
+ return;
+ }
+
+ CvVideoWriter* aviW;
+ QString saveFile = mSaveDgl->ui.edtSavePath->text();
+ QString path, prefix, fname, ext;
+ int index;
+
+ CommonFunctions::splitPath(saveFile, path, fname, prefix, (uint)5, index, ext);
+
+ if(mSaveDgl->ui.rbtnSaveAsAVI->isChecked())
+ {
+ int fps = mMonitor->getFPS();
+ if(fps < 1)
+ fps = 30;
+
+ try
+ {
+ //CV_FOURCC('M', 'P', '4', '2') CV_FOURCC('M','J','P','G')
+ aviW = cvCreateVideoWriter(saveFile.toAscii(), CV_FOURCC_PROMPT, fps, cvSize(origSz.width(), origSz.height()));
+ // CvVideoWriter* aviW = cvCreateAVIWriter((mFileName.left(mFileName.length()-4) + "_bm.avi").toAscii(), 0, fps, cvSize(origSz.width(), origSz.height()));
+ }
+ catch(...)
+ {
+ aviW = cvCreateVideoWriter(saveFile.toAscii(), CV_FOURCC_DEFAULT, fps, cvSize(origSz.width(), origSz.height()));
+ }
+ }
+
+ QPainter pt;
+ int h;
+ QColor cl;
+ QBrush br(QColor(0,0,0,255));
+ QImage *im = NULL;
+ if(!origBkgrd)
+ {
+ im = new QImage(origSz, QImage::Format_ARGB32);
+ }
+ ViaPoint *bx;
+ ViaPointPolygon *polyg;
+ IplImage* ipl = cvCreateImage(cvSize(origSz.width(), origSz.height()), IPL_DEPTH_8U, 3);
+ for(t = startF; t <= endF; t++)
+ {
+ if(origBkgrd)
+ {
+ mMonitor->moveToFrame(t);
+ im = mMonitor->getImage();
+ }
+
+ pt.begin(im);
+ if(!origBkgrd)
+ {
+ pt.fillRect(im->rect(), Qt::black);
+ }
+ for(i = 0; i < nLbls; i++)
+ {
+ if(mLabels[i].shape == Rect)
+ {
+ if(t >= mLabels[i].boxes[0].frame &&
+ t <= mLabels[i].boxes[mLabels[i].boxes.count() - 1].frame)
+ {
+ h = 200;//(int)(100 + (i + 1) * 155.0/nLbls);
+ cl = QColor::fromRgb(h,h,h,128);
+ br.setColor(cl);
+ bx = mLabels[i].findBoxByFrame(t);
+ QRect rt = imageToImage(mDisplayImage->width(), mDisplayImage->height(), bx->rc, origSz.width(), origSz.height());
+ pt.fillRect(rt, br);
+ }
+ }
+ else if(mLabels[i].shape == Polyg)
+ {
+ if(t >= mLabels[i].polygons[0].frame &&
+ t <= mLabels[i].polygons[mLabels[i].polygons.count() - 1].frame)
+ {
+ h = 200;//(int)(100 + (i + 1) * 155.0/nLbls);
+ cl = QColor::fromRgb(h,h,h,128);
+ br.setColor(cl);
+ pt.setBrush(br);
+ polyg = mLabels[i].findPolygonByFrame(t);
+ QPolygon pl = imageToImage(mDisplayImage->width(), mDisplayImage->height(), polyg->pl, origSz.width(), origSz.height());
+ pt.drawPolygon(pl);
+ }
+ }
+ }
+
+ if(mSaveDgl->ui.rbtnSaveAsAVI->isChecked())
+ {
+ mMonitor->convertARGB2RGB(im, ipl);
+ cvWriteFrame(aviW, ipl);
+ }
+ else
+ {
+ QString sv;
+ sv = path + prefix + sv.sprintf("%05d", t) + ext;
+ im->save(sv, "PNG");
+ }
+
+ pt.end();
+ }
+ if(mSaveDgl->ui.rbtnSaveAsAVI->isChecked())
+ {
+ cvReleaseVideoWriter(&aviW);
+ }
+
+ if(!origBkgrd)
+ {
+ delete im;
+ }
+ }
+}
+
+
+void SimpleLabel::exportToMatlabStruct()
+{
+ QSize origSz = mMonitor->getImageSize();
+ int i, k, j;
+ QString saveFile = mSaveDgl->ui.edtSavePath->text();
+ QString filename = mSaveDgl->ui.edtFileNamePrefix->text();
+
+ QFile fd(saveFile);
+ if(fd.open(QFile::WriteOnly | QFile::Truncate))
+ {
+ QTextStream out(&fd);
+ out << "function " << filename << " = " << filename + "_lbl" << endl;
+ for(i = 0; i < mLabels.count(); i++)
+ {
+ out << filename << "(" << i +1 << ").number = " << mLabels[i].number << ";" << endl;
+ out << filename << "(" << i +1 << ").desc = '" << mLabels[i].desc.replace("\n", "") << "';" << endl;
+ out << filename << "(" << i +1 << ").name = '" << mLabels[i].name << "';" << endl;
+ out << filename << "(" << i +1 << ").startFrame = " << mLabels[i].viaPoints[0].frame << ";" << endl;
+ out << filename << "(" << i +1 << ").endFrame = " << mLabels[i].viaPoints[mLabels[i].viaPoints.count() - 1].frame << ";" << endl;
+
+ out << filename << "(" << i +1 << ").boxes = [";
+ for(k = 0; k < mLabels[i].boxes.count(); k++)
+ {
+ QRect rc = imageToImage(mDisplayImage->width(), mDisplayImage->height(), mLabels[i].boxes[k].rc, origSz.width(), origSz.height());
+ out << rc.left()<< "," << rc.top() << "," << rc.width() << "," << rc.height();
+ if(k != mLabels[i].boxes.count() - 1)
+ out << ";";
+ }
+ out << "];" << endl;
+
+ for(k = 0; k < mLabels[i].viaPoints.count(); k++)
+ {
+ QRect rc = imageToImage(mDisplayImage->width(), mDisplayImage->height(), mLabels[i].viaPoints[k].rc, origSz.width(), origSz.height());
+
+ out << filename << "(" << i +1 << ").pivots(" << k + 1 << ").frame = " << mLabels[i].viaPoints[k].frame << ";" << endl;
+ out << filename << "(" << i +1 << ").pivots(" << k + 1 << ").box = [";
+ out << rc.left() << "," << rc.top() << "," << rc.width() << "," << rc.height() << "];" << endl;
+ }
+
+
+
+ for(k = 0; k < mLabels[i].polygons.count(); k++)
+ {
+ out << filename << "(" << i +1 << ").polygons(" << k + 1 << ").polygon=[";
+ QPolygon pl = imageToImage(mDisplayImage->width(), mDisplayImage->height(), mLabels[i].polygons[k].pl, origSz.width(), origSz.height());
+ for(j = 0; j < pl.count(); j++)
+ {
+ QPoint pt = pl.point(j);
+ out << pt.x() << "," << pt.y();
+ if(j != pl.count() - 1)
+ out << ";";
+ }
+ out << "];" << endl;
+ }
+
+ for(k = 0; k < mLabels[i].viaPointsPoly.count(); k++)
+ {
+ QPolygon pl = imageToImage(mDisplayImage->width(), mDisplayImage->height(), mLabels[i].viaPointsPoly[k].pl, origSz.width(), origSz.height());
+
+ out << filename << "(" << i +1 << ").pivotsPolyg(" << k + 1 << ").frame = " << mLabels[i].viaPoints[k].frame << ";" << endl;
+ out << filename << "(" << i +1 << ").pivotsPolyg(" << k + 1 << ").polygon = [";
+ for(j = 0; j < pl.count(); j++)
+ {
+ QPoint pt = pl.point(j);
+ out << pt.x() << "," << pt.y();
+ if(j != pl.count() - 1)
+ out << ";";
+ }
+ }
+ }
+ out << "];" << endl;
+ fd.close();
+ }
+}
+
+Label* SimpleLabel::findLabel(int number)
+{
+ for(int i = 0; i < mLabels.count(); i++)
+ {
+ if(mLabels[i].number == number)
+ {
+ return &mLabels[i];
+ }
+ }
+
+ return NULL;
+}
+
+
+
+void SimpleLabel::exportToLabelMeXML()
+{
+ QString saveFile = mSaveDgl->ui.edtSavePath->text();
+ QString path, fname, ext;
+ CommonFunctions::splitPath(saveFile, path, fname, ext);
+
+ int startF = qMax( mSaveDgl->ui.edtFirstImageIndex->text().toInt(), mFirstFrameNumber);
+ int endF = qMin(mSaveDgl->ui.edtLastImageIndex->text().toInt(), mFirstFrameNumber + mMonitor->getFrameCount() - 1);
+ if(startF > mFirstFrameNumber + mMonitor->getFrameCount() - 1)
+ {
+ QMessageBox::information(this, "Index is out of bounds", "Starting frame number is larger than image sequence length.");
+ return;
+ }
+
+ for(int i = startF; i <= endF; i++)
+ {
+ exportFrameToLabelMeXML(path, i);
+ }
+}
+
+
+void SimpleLabel::on_actionLoad_LabelMe_XML_triggered()
+{
+ int curframe = -1, totframes = 0;
+ int w = 0, h = 0;
+ bool err = false;
+ QString s = QFileDialog::getOpenFileName(this, tr("Open LabelMe XML"), ".", tr("XML Files (*.xml)"));
+ QSize sz = mMonitor->getImageSize();
+
+ if(!s.isEmpty())
+ {
+ try
+ {
+ //scanning first file for global settings
+ QFile f(s);
+ if(f.open(QIODevice::ReadOnly))
+ {
+ QDomDocument doc("");
+ if(doc.setContent(&f))
+ {
+ resetLabels();
+
+ QDomNode anot = doc.documentElement();
+
+ QDomNode n = anot.firstChild();
+ while(!n.isNull()) //going through all the elements
+ {
+ QDomElement e = n.toElement();
+ if(!e.isNull() && e.tagName() == "frame")
+ {
+ curframe = e.text().trimmed().toInt();
+ }
+ if(!e.isNull() && e.tagName() == "source")
+ {
+
+ QDomNode n1 = n.firstChild();
+ while(!n1.isNull()) //going through all the children
+ {
+ QDomElement e1 = n1.toElement();
+ if(!e1.isNull() && e1.tagName() == "numberFrames")
+ {
+ totframes = e1.text().trimmed().toInt();
+ }
+ n1 = n1.nextSibling();
+ }
+ }
+ if(!e.isNull() && e.tagName() == "imagesize")
+ {
+ QDomNode n1 = n.firstChild();
+ while(!n1.isNull()) //going through all the children
+ {
+ QDomElement e1 = n1.toElement();
+ if(!e1.isNull() && e1.tagName() == "rows")
+ {
+ h = e1.text().trimmed().toInt();
+ }
+ if(!e1.isNull() && e1.tagName() == "columns")
+ {
+ w = e1.text().trimmed().toInt();
+ }
+ n1 = n1.nextSibling();
+ }
+ }
+
+ n = n.nextSibling();
+ }
+
+ }
+ else
+ {
+ QMessageBox::information(this, "Invalid XML file", "Failed to parse XML file " + s);
+ }
+
+ f.close();
+ }
+
+ QRect rc;
+ int x, y, id;
+ QString idstr;
+ QString path;
+ QString ext;
+ QString filename;
+ QString prefix;
+ int firstframe;
+ QProgressBar pBar(statusBar());
+ pBar.setRange(curframe, totframes);
+ pBar.setVisible(true);
+
+ //splitting the full path into parts
+ CommonFunctions::splitPath(s, path, filename, prefix, (uint)5, firstframe, ext);
+
+ while(!err && curframe < totframes && QFile::exists(s))
+ {
+ pBar.setValue(curframe);
+ rc.setCoords(0,0,0,0);
+ QFile fd(s);
+ if(fd.open(QIODevice::ReadOnly))
+ {
+ QDomDocument doc("");
+ if(doc.setContent(&fd))
+ {
+ QDomNode anot = doc.documentElement();
+
+ curframe = anot.namedItem("frame").toElement().text().trimmed().toInt();
+
+ QDomNode n = anot.firstChild();
+ while(!n.isNull()) //going through all the elements
+ {
+ QDomElement e = n.toElement();
+ if(!e.isNull() && e.tagName() == "object")
+ {
+ idstr = e.namedItem("tgtID").toElement().text().trimmed();
+ if(idstr == "")
+ {
+ n = n.nextSibling();
+ continue;
+ }
+ id = idstr.toInt();
+ Label *lbl = findLabel(id);
+ if(lbl == NULL)
+ {
+ //create a new label and added it to the list
+ //need to retrieve it from the list in order to
+ //get a pointer to the to the actual object in the list
+ lbl = new Label();
+ lbl->number = id;
+ lbl->name = e.namedItem("name").toElement().text();
+ mLabels.append(*lbl);
+ delete lbl;
+ lbl = findLabel(id);
+
+ //adding ui item to the list
+ QListWidgetItem *it = new QListWidgetItem();
+ it->setText(lbl->name);
+ it->setFlags(it->flags() | Qt::ItemIsEditable);
+ ui.listLabels->addItem(it);
+ }
+
+
+ QDomNode bbox = e.namedItem("bbox");
+ if(!bbox.isNull())
+ {
+ QDomNode pt = bbox.namedItem("pt");
+ if(!pt.isNull())
+ {
+ x = qRound(pt.namedItem("x").toElement().text().trimmed().toFloat());
+ y = qRound(pt.namedItem("y").toElement().text().trimmed().toFloat());
+ rc.setTopLeft(QPoint(x,y));
+
+ pt = pt.nextSibling();
+ x = qRound(pt.namedItem("x").toElement().text().trimmed().toFloat());
+ y = qRound(pt.namedItem("y").toElement().text().trimmed().toFloat());
+ rc.setTopRight(QPoint(x,y));
+
+ pt = pt.nextSibling();
+ x = qRound(pt.namedItem("x").toElement().text().trimmed().toFloat());
+ y = qRound(pt.namedItem("y").toElement().text().trimmed().toFloat());
+ rc.setBottomRight(QPoint(x,y));
+
+ pt = pt.nextSibling();
+ x = qRound(pt.namedItem("x").toElement().text().trimmed().toFloat());
+ y = qRound(pt.namedItem("y").toElement().text().trimmed().toFloat());
+ rc.setBottomLeft(QPoint(x,y));
+
+ rc = imageToImage(w, h, rc, mDisplayImage->width(), mDisplayImage->height());
+
+ ViaPoint vp;
+ vp.frame = curframe;
+ vp.rc = rc;
+ lbl->boxes.append(vp);
+ lbl->viaPoints.append(vp);
+ }
+ }
+
+ QDomNode polygon = e.namedItem("polygon");
+ if(!polygon.isNull())
+ {
+ ViaPointPolygon polyg;
+ polyg.frame = curframe;
+ QDomNode pt = polygon.namedItem("pt");
+ while(!pt.isNull())
+ {
+ x = qRound(pt.namedItem("x").toElement().text().trimmed().toFloat());
+ y = qRound(pt.namedItem("y").toElement().text().trimmed().toFloat());
+
+ QPoint pl_pt(x,y);
+
+ pl_pt = imageToImage(w, h, pl_pt, mDisplayImage->width(), mDisplayImage->height());
+ polyg.pl << pl_pt;
+ pt = pt.nextSibling();
+ }
+ //only adding polygon if it is at least a triangle
+ if(polyg.pl.count() > 2)
+ {
+ lbl->shape = Polyg;
+ lbl->polygons << polyg;
+ lbl->viaPointsPoly << polyg;
+ }
+ }
+ }
+ n = n.nextSibling();
+ }
+ }
+ else
+ {
+ QMessageBox::information(this, "Invalid XML file", "Failed to parse XML file " + s);
+ err = true;
+ }
+
+ fd.close();
+ }
+
+ firstframe++;
+ QString num;
+ num.sprintf("%05d",firstframe);
+ s = path + prefix + num + ext;
+ }
+ pBar.setVisible(false);
+ }
+ catch(...)
+ {
+ QMessageBox::information(this, "Unrecoverable error", "Error while processing file: " + s);
+ }
+ }
+}
+
+void SimpleLabel::on_actionLoad_XML_triggered()
+{
+ int w, h;
+ QSize origSz = mMonitor->getImageSize();
+
+ w = origSz.width();
+ h = origSz.height();
+
+ QString s = QFileDialog::getOpenFileName(this, tr("Open Label XML"), ".", tr("XML Files (*.xml)"));
+ if(!s.isEmpty())
+ {
+ QFile fd(s);
+ if(fd.open(QIODevice::ReadOnly))
+ {
+ QDomDocument doc("Labels");
+ if(doc.setContent(&fd))
+ {
+ resetLabels();
+
+ QDomNode root = doc.documentElement();
+ QDomNode n = root.firstChild();
+ while(!n.isNull()) //going through all the labels
+ {
+ QDomElement e = n.toElement();
+ if(!e.isNull() && e.tagName() == "image")
+ {
+ w = e.attribute("width", "-1").toInt();
+ h = e.attribute("height", "-1").toInt();
+ }
+ else if(!e.isNull() && e.tagName() == "label")
+ {
+ Label lb;
+ lb.name = e.attribute("name", "-1");
+ lb.desc = e.attribute("desc", "-1");
+ lb.number = e.attribute("number", "-1").toInt();
+ lb.shape = (LabelShape)e.attribute("shape", "-1").toInt();
+
+ QDomNode t = e.firstChild();
+ while(!t.isNull())
+ {
+ QDomElement el = t.toElement();
+ qDebug() << el.tagName();
+ if(!el.isNull())
+ {
+ QDomNode p = el.firstChild();
+ while(!p.isNull())
+ {
+ QDomElement point = p.toElement();
+ qDebug() << point.tagName();
+ if(!point.isNull())
+ {
+ if(el.tagName() == "boxes" || el.tagName() == "pivots")
+ {
+ ViaPoint pt;
+
+ pt.frame = point.attribute("frame", "-1").toInt();
+ pt.rc.setLeft(point.attribute("left", "-1").toInt());
+ pt.rc.setTop(point.attribute("top", "-1").toInt());
+ pt.rc.setRight(point.attribute("right", "-1").toInt());
+ pt.rc.setBottom(point.attribute("bottom", "-1").toInt());
+ pt.angle = (point.attribute("angle", "0.0").toFloat());
+ if(point.tagName() == "box")
+ {
+ lb.boxes.append(pt);
+ }
+ else if(point.tagName() == "pivot")
+ {
+ lb.viaPoints.append(pt);
+ }
+ }
+ else if(el.tagName() == "polygons" || el.tagName() == "polygonPivots")
+ {
+ ViaPointPolygon pl;
+ pl.frame = point.attribute("frame", "-1").toInt();
+
+ QDomNode vertex = point.firstChild();
+ while(!vertex.isNull())
+ {
+ QDomElement ver = vertex.toElement();
+ QPoint v;
+ v.setX(ver.attribute("x", "-1").toInt());
+ v.setY(ver.attribute("y", "-1").toInt());
+
+ pl.pl << v;
+
+ vertex = vertex.nextSibling();
+ }
+
+ if(point.tagName() == "polygon")
+ {
+ lb.polygons.append(pl);
+ }
+ else if(point.tagName() == "polygonPivot")
+ {
+ lb.viaPointsPoly.append(pl);
+ }
+ }
+ }
+ p = p.nextSibling();
+ }
+ }
+ t = t.nextSibling();
+ }
+ mLabels.append(lb);
+ ui.listLabels->addItem(lb.name);
+ }
+ n = n.nextSibling();
+ }
+
+ //converting coordinates to the screen image size
+ QList