diff --git a/Pastie.pro b/Pastie.pro index 16cc86a..f881315 100644 --- a/Pastie.pro +++ b/Pastie.pro @@ -4,7 +4,7 @@ # #------------------------------------------------- -QT += core gui opengl multimedia +QT += core gui opengl multimedia serialport greaterThan(QT_MAJOR_VERSION, 4): QT += widgets @@ -31,11 +31,20 @@ SOURCES += main.cpp\ painter.cpp \ filters/maxchannel.cpp \ filters/normalize.cpp \ - filters/shapedetect.cpp \ filters/setting.cpp \ - filters/result.cpp \ filters/blur.cpp \ - filters/watershed.cpp + filters/watershed.cpp \ + filters/derivative.cpp \ + robot.cpp \ + tabrobot.cpp \ + filters/pathplanner.cpp \ + filters/paddetect.cpp \ + pad.cpp \ + filters/resize.cpp \ + filters/padfilter.cpp \ + rangeslider.cpp \ + filters/rectify.cpp \ + filters/rotate.cpp HEADERS += mainwindow.h \ camera.h \ @@ -56,11 +65,22 @@ HEADERS += mainwindow.h \ filters.h \ filters/maxchannel.h \ filters/normalize.h \ - filters/shapedetect.h \ filters/setting.h \ filters/result.h \ filters/blur.h \ - filters/watershed.h + filters/watershed.h \ + filters/derivative.h \ + robot.h \ + tabrobot.h \ + filters/pathplanner.h \ + filters/paddetect.h \ + pad.h \ + filters/resize.h \ + qspanslider.h \ + rangeslider.h \ + range.h \ + filters/rectify.h \ + filters/rotate.h SOURCES += filters/filter.cpp \ filters/undistort.cpp \ @@ -70,7 +90,6 @@ SOURCES += filters/filter.cpp \ filters/morph.cpp \ filters/convert.cpp \ filters/pattern.cpp \ - filters/padfilter.cpp \ filters/edgedetect.cpp \ filters/channel.cpp \ filters/perspective.cpp @@ -95,7 +114,8 @@ FORMS += mainwindow.ui \ tabimages.ui \ tabcamera.ui \ tabfilters.ui \ - tabpads.ui + tabpads.ui \ + tabrobot.ui # OpenCV INCLUDEPATH += /usr/local/include diff --git a/Pastie.pro.user b/Pastie.pro.user index 0163442..c28e402 100644 --- a/Pastie.pro.user +++ b/Pastie.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -59,7 +59,7 @@ 0 0 - /Users/stv0g/workspace/rwth-dbv/code/build-Pastie-Desktop_Qt_5_4_0_clang_64bit-Debug + /Users/stv0g/workspace/rwth/dbv/code/build-Pastie-Desktop_Qt_5_4_0_clang_64bit-Debug true @@ -210,7 +210,7 @@ true false true - valgrind + /usr/local/bin/valgrind 0 1 @@ -231,13 +231,13 @@ 2 Pastie - - Qt4ProjectManager.Qt4RunConfiguration:/Users/stv0g/workspace/rwth-dbv/code/pastie/Pastie.pro - google/* + Pastie2 + Qt4ProjectManager.Qt4RunConfiguration:/Users/stv0g/workspace/rwth/dbv/code/pastie/Pastie.pro + ~/workspace/rwth/dbv/data/omd3/* Pastie.pro false false - /Users/stv0g/workspace/rwth-dbv/data + 3768 false true diff --git a/camera.cpp b/camera.cpp index 2555aca..b951354 100644 --- a/camera.cpp +++ b/camera.cpp @@ -21,7 +21,7 @@ void Camera::reset() matrix = Mat::eye(3, 3, CV_32F); } -bool Camera::calibrate(list imgs, Pattern *pattern) +bool Camera::calibrate(QList imgs, Pattern *pattern) { vector> imagePoints; vector> objectPoints; diff --git a/camera.h b/camera.h index 82039c2..efdfbe4 100644 --- a/camera.h +++ b/camera.h @@ -18,7 +18,7 @@ class Camera public: Camera(Source *s); - bool calibrate(list imgs, Pattern *pattern); + bool calibrate(QList imgs, Pattern *pattern); /* Getters */ const Mat & getDistCoeffs() { return distCoeffs; } diff --git a/cast.h b/cast.h index 986c800..374349f 100644 --- a/cast.h +++ b/cast.h @@ -18,41 +18,48 @@ inline QImage toQImage(const Mat &mat) { Mat *conv = new Mat; - - switch (mat.channels()) { case 3: cvtColor(mat, *conv, COLOR_RGB2RGBA); break; case 1: cvtColor(mat, *conv, COLOR_GRAY2RGBA); break; } return QImage((const unsigned char *) conv->data, conv->cols, conv->rows, conv->step, - QImage::Format_RGB32, [] (void * data) { ((Mat *) data)->release(); }, conv); + QImage::Format_RGB32, [](void * data) { ((Mat *) data)->release(); }, conv); } inline QTransform toQTransform(const Mat &m) { - return QTransform( - m.at(0,0), m.at(0,1), m.at(0,2), - m.at(1,0), m.at(1,1), m.at(1,2), - m.at(2,0), m.at(2,1), m.at(2,2)); + if (m.size() == Size(3, 3)) + return QTransform( m.at(0,0), m.at(0,1), m.at(0,2), + m.at(1,0), m.at(1,1), m.at(1,2), + m.at(2,0), m.at(2,1), m.at(2,2) ); + else if (m.size() == Size(2, 3)) + return QTransform( m.at(0,0), m.at(0,1), + m.at(1,0), m.at(1,1), + m.at(0,2), m.at(1,2) ); + else if (m.size() == Size(2, 2)) + return QTransform( m.at(0,0), m.at(0,1), + m.at(1,0), m.at(1,1), 0, 0 ); + else + return QTransform(); } -inline QSize toQt(const Size2i &s) { return QSize (s.width, s.height); } -inline QSizeF toQt(const Size2d &s) { return QSizeF(s.width, s.height); } +inline QSize toQt(const Size2i &s) { return QSize (s.width, s.height); } +inline QSizeF toQt(const Size2f &s) { return QSizeF(s.width, s.height); } -inline QPoint toQt(const Point2i &p) { return QPoint (p.x, p.y); } -inline QPointF toQt(const Point2d &p) { return QPointF(p.x, p.y); } +inline QPoint toQt(const Point2i &p) { return QPoint (p.x, p.y); } +inline QPointF toQt(const Point2f &p) { return QPointF(p.x, p.y); } -inline QRect toQt(const Rect2i &r) { return QRect (r.x, r.y, r.width, r.height); } -inline QRectF toQt(const Rect2d &r) { return QRectF(r.x, r.y, r.width, r.height); } +inline QRect toQt(const Rect2i &r) { return QRect (r.x, r.y, r.width, r.height); } +inline QRectF toQt(const Rect2f &r) { return QRectF(r.x, r.y, r.width, r.height); } -inline Size2i toCv(const QSize &s) { return Size2i(s.width(), s.height()); } -inline Size2d toCv(const QSizeF &s) { return Size2d(s.width(), s.height()); } +inline Size2i toCv(const QSize &s) { return Size2i(s.width(), s.height()); } +inline Size2d toCv(const QSizeF &s) { return Size2d(s.width(), s.height()); } -inline Point2i toCv(const QPoint &p) { return Point2i(p.x(), p.y()); } -inline Point2d toCv(const QPointF &p) { return Point2d(p.x(), p.y()); } +inline Point2i toCv(const QPoint &p) { return Point2i(p.x(), p.y()); } +inline Point2d toCv(const QPointF &p) { return Point2d(p.x(), p.y()); } -inline Rect2i toCv(const QRect &r) { return Rect2i(r.x(), r.y(), r.width(), r.height()); } -inline Rect2d toCv(const QRectF &r) { return Rect2d(r.x(), r.y(), r.width(), r.height()); } +inline Rect2i toCv(const QRect &r) { return Rect2i(r.x(), r.y(), r.width(), r.height()); } +inline Rect2d toCv(const QRectF &r) { return Rect2d(r.x(), r.y(), r.width(), r.height()); } #endif // CAST_H diff --git a/filterlist.cpp b/filterlist.cpp index 159ca3e..1ecaee9 100644 --- a/filterlist.cpp +++ b/filterlist.cpp @@ -6,8 +6,8 @@ FilterList::FilterList(QObject *parent) : QAbstractTableModel(parent), selection(this) { - connect(&selection, &QItemSelectionModel::currentChanged, [&] (QModelIndex i, QModelIndex) { - emit filterSelected(at(i.row())); + connect(&selection, &QItemSelectionModel::currentChanged, [&] (QModelIndex current, QModelIndex) { + emit filterSelected(at(current.row())); }); } @@ -41,6 +41,7 @@ QVariant FilterList::data(const QModelIndex &index, int role) const case 0: return (filter->isEnabled()) ? Qt::Checked: Qt::Unchecked; case 1: return (filter->isShown()) ? Qt::Checked: Qt::Unchecked; } + break; } return QVariant(); @@ -56,11 +57,11 @@ bool FilterList::setData(const QModelIndex &index, const QVariant &value, int ro case 0: filter->setEnabled(value == Qt::Checked); case 1: filter->setShow(value == Qt::Checked); break; } + + emit filtersChanged(); break; } - emit filtersChanged(); - return true; } @@ -107,12 +108,11 @@ void FilterList::add(Filter *filter) void FilterList::execute(Image *img) { - img->filtered = img->original.clone(); + img->getMat().release(); try { - for (auto filter : *this) { + for (auto filter : *this) img->applyFilter(filter); - } } catch (Exception e) { qCritical("%s", e.msg.c_str()); } @@ -126,6 +126,14 @@ void FilterList::execute(Image *img) void FilterList::reset() { + qDebug() << "Reset filters"; for (Filter *filter : *this) filter->reset(); + + emit filtersChanged(); +} + +Filter * FilterList::getCurrent() +{ + return value(selection.currentIndex().row()); } diff --git a/filterlist.h b/filterlist.h index a148934..a9dbee7 100644 --- a/filterlist.h +++ b/filterlist.h @@ -26,6 +26,8 @@ class FilterList : void add(Filter *filt); void execute(Image *img); + Filter * getCurrent(); + QItemSelectionModel selection; public slots: diff --git a/filters.h b/filters.h index c64064f..28b3f77 100644 --- a/filters.h +++ b/filters.h @@ -13,10 +13,16 @@ #include "filters/normalize.h" #include "filters/pattern.h" #include "filters/perspective.h" -#include "filters/shapedetect.h" +#include "filters/paddetect.h" +#include "filters/padfilter.h" #include "filters/threshold.h" #include "filters/undistort.h" #include "filters/watershed.h" +#include "filters/derivative.h" +#include "filters/rectify.h" +#include "filters/pathplanner.h" +#include "filters/resize.h" +#include "filters/rotate.h" #endif // FILTERS_H diff --git a/image.cpp b/image.cpp index 41a4f93..2dd91c5 100644 --- a/image.cpp +++ b/image.cpp @@ -7,17 +7,16 @@ using namespace cv; Image::Image(Mat m, QString p) : path(p), - original(m.clone()), - loaded(false), + source(m), + loaded(true), saved(false) { } Image::Image(QString p) : path(p), + loaded(false), saved(false) -{ - load(); -} +{ } Image::~Image() { @@ -30,8 +29,8 @@ void Image::load(QString p) if (p != "") path = p; - original = cv::imread(path.toStdString()); - loaded = (bool) original.data; + source = cv::imread(path.toStdString()); + loaded = (bool) source.data; } void Image::save(QString p) @@ -39,16 +38,33 @@ void Image::save(QString p) if (p != "") path = p; - saved = imwrite(path.toStdString(), original); + saved = imwrite(path.toStdString(), getMat()); } void Image::applyFilter(Filter *filter) { -// FIXME! -// if (results.contains(filter)) -// delete results[filter]; - Result *result = filter->apply(this); if (result) results[filter] = result; } + +Mat & Image::getMat() +{ + if (!filtered.data) + filtered = getSourceMat().clone(); + + return filtered; +} + +const Mat & Image::getSourceMat() +{ + if (!loaded) + load(); + + return source; +} + +void Image::setSourceMat(const Mat &m) +{ + source = m; +} diff --git a/image.h b/image.h index 322b086..4221bd7 100644 --- a/image.h +++ b/image.h @@ -15,29 +15,36 @@ class Result; class Image { -public: - Image(Mat mat = Mat(), QString path = ""); - Image(QString p); - ~Image(); + public: + Image(Mat mat = Mat(), QString path = QString()); + Image(QString p); + ~Image(); - void save(QString path = ""); - void load(QString path = ""); + void save(QString path = QString()); + void load(QString path = QString()); - QString path; + void applyFilter(Filter *filter); - Mat original; - Mat filtered; + /* Getter */ + bool isLoaded() const { return loaded; } + bool isSaved() const { return saved; } - void applyFilter(Filter *filter); + Result * getResult(Filter *f) { return results[f]; } + QString getPath() { return path; } + Mat & getMat(); - /* Getter */ - Result * getResult(Filter *f) { return results[f]; } + const Mat & getSourceMat(); + void setSourceMat(const Mat &m); -protected: - QMap results; + protected: + QMap results; - bool loaded; - bool saved; + QString path; + Mat source; + Mat filtered; + + bool loaded; + bool saved; }; #endif // IMAGE_H diff --git a/imagelist.cpp b/imagelist.cpp index d41ef49..e92db05 100644 --- a/imagelist.cpp +++ b/imagelist.cpp @@ -10,7 +10,9 @@ ImageList::ImageList(QObject *parent) : QAbstractTableModel(parent), selection(this) { - connect(&selection, &QItemSelectionModel::currentChanged, this, &ImageList::currentImage); + connect(&selection, &QItemSelectionModel::currentChanged, [&](QModelIndex current, QModelIndex) { + emit newImage(at(current.row())); + }); } ImageList::~ImageList() @@ -20,26 +22,32 @@ ImageList::~ImageList() int ImageList::rowCount(const QModelIndex &) const { return count(); -}; +} int ImageList::columnCount(const QModelIndex &) const { return 6; -}; +} QVariant ImageList::data(const QModelIndex &index, int role) const { Image *img = at(index.row()); - QFileInfo fi = QFileInfo(img->path); + QFileInfo fi = QFileInfo(img->getPath()); if (role == Qt::DisplayRole) { - switch (index.column()) { - case 0: return fi.baseName(); - case 1: return fi.suffix(); - case 2: return fi.size(); - case 3: return img->original.cols; - case 4: return img->original.rows; - case 5: return img->original.channels(); - } + switch (index.column()) { + case 0: return fi.baseName(); + case 1: return fi.suffix().toLower(); + case 2: return QString("%1 kB").arg(fi.size() / 1024.0, 0, 'f', 2); + case 3: if (img->isLoaded()) return img->getSourceMat().channels(); + case 4: if (img->isLoaded()) return img->getSourceMat().cols; + case 5: if (img->isLoaded()) return img->getSourceMat().rows; + } + } + else if (role ==Qt::TextAlignmentRole) { + switch (index.column()) { + case 4: return Qt::AlignRight; + default: return Qt::AlignLeft; + } } return QVariant(); @@ -51,11 +59,11 @@ QVariant ImageList::headerData(int section, Qt::Orientation orientation, int rol if (orientation == Qt::Horizontal) { switch (section) { case 0: return QString(tr("Name")); - case 1: return QString(tr("Typ")); + case 1: return QString(tr("Type")); case 2: return QString(tr("Size")); - case 3: return QString(tr("Width")); - case 4: return QString(tr("Height")); - case 5: return QString(tr("Channels")); + case 3: return QString(tr("Channels")); + case 4: return QString(tr("Width")); + case 5: return QString(tr("Height")); } } } @@ -71,69 +79,60 @@ void ImageList::clear() { delete img; removeOne(img); } - endResetModel(); } -QList ImageList::selectedImages() +QList ImageList::getSelected() { QList sel; - for (QModelIndex index : selection.selectedRows()) sel.append(at(index.row())); return sel; } -Image * ImageList::currentImage() +Image * ImageList::getCurrent() { - current = at(selection.currentIndex().row()); - emit newImage(current); - return current; + if (!selection.currentIndex().isValid()) + selection.select(createIndex(0, 0), QItemSelectionModel::Current); + + return value(selection.currentIndex().row()); } -Image * ImageList::nextImage() +void ImageList::nextImage() { QModelIndex oldIdx = selection.currentIndex(); QModelIndex newIdx = index(oldIdx.row()-1, oldIdx.column()); - if (newIdx.isValid()) { + if (newIdx.isValid()) selection.setCurrentIndex(newIdx, QItemSelectionModel::Current); - - current = at(newIdx.row()); - emit newImage(current); - } - - return current; } -Image * ImageList::prevImage() +void ImageList::prevImage() { QModelIndex oldIdx = selection.currentIndex(); QModelIndex newIdx = index(oldIdx.row()+1, oldIdx.column()); - if (newIdx.isValid()) { + if (newIdx.isValid()) selection.setCurrentIndex(newIdx, QItemSelectionModel::Current); - - current = at(newIdx.row()); - emit newImage(current); - } - - return current; } void ImageList::load(QStringList files) { - for (QString file : files) - add(new Image(file)); + QStringList valid = { "png", "jpg", "png" }; - current = first(); - emit newImage(current); + for (QString file : files) { + QFileInfo checkFile(file); + if (checkFile.exists() && checkFile.isFile() && + valid.contains(checkFile.suffix().toLower())) { + add(new Image(file)); + } + } } void ImageList::save(QString path) -{ - currentImage()->save(path); +{ + getCurrent()->save(path); } void ImageList::loadFilePicker() @@ -145,8 +144,9 @@ void ImageList::loadFilePicker() void ImageList::saveFilePicker() { - QString path = QFileDialog::getSaveFileName(mwindow, tr("Save Image"), current->path, - tr("Image Files (*.png *.jpg *.bmp)")); + QString path = QFileDialog::getSaveFileName(mwindow, + tr("Save Image"), getCurrent()->getPath(), + tr("Image Files (*.png *.jpg *.bmp)")); save(path); } diff --git a/imagelist.h b/imagelist.h index f47e2a8..9eec5f5 100644 --- a/imagelist.h +++ b/imagelist.h @@ -27,6 +27,9 @@ class ImageList : QItemSelectionModel selection; + QList getSelected(); + Image * getCurrent(); + signals: void newImage(Image *img); @@ -37,13 +40,8 @@ class ImageList : void saveFilePicker(); void clear(); - QList selectedImages(); - Image * currentImage(); - Image * prevImage(); - Image * nextImage(); - - protected: - Image *current; + void prevImage(); + void nextImage(); }; #endif // IMAGELIST_H diff --git a/main.cpp b/main.cpp index 6bfa458..24787e8 100644 --- a/main.cpp +++ b/main.cpp @@ -23,38 +23,34 @@ int main(int argc, char *argv[]) foreach (const QCameraInfo &cameraInfo, cameras) qDebug() << "Found Qt camera: " << cameraInfo.deviceName() << ": " << cameraInfo.description(); - filters = new FilterList; - images = new ImageList; source = new Source; cam = new Camera(source); + filters = new FilterList; + images = new ImageList; mwindow = new MainWindow; QStringList imgs = QCoreApplication::arguments(); imgs.removeFirst(); imgs.removeDuplicates(); - imgs.sort(); images->load(imgs); /* Setup pipeline */ -#if 1 + Pattern *pat = new Pattern(Size(2, 2), Size(60, 60), Pattern::QUADRILINEAR_MARKERS); + filters->add(pat); + filters->add(new Perspective(cam, pat)); + filters->add(new Resize(Range(400, 1000))); + filters->add(new Blur(Blur::GAUSSIAN, Size(3, 3))); filters->add(new KMeans(4)); - filters->add(new Convert(COLOR_BGR2HSV)); - filters->add(new Channel(1)); - //filters->add(new Convert(COLOR_BGR2GRAY)); - //filters->add(new HistEqualize()); + filters->add(new Convert(COLOR_BGR2GRAY)); filters->add(new Threshold(Threshold::OTSU)); - //filters->add(new EdgeDetect(80, 3)); - //filters->add(new Watershed()); - filters->add(new Morph(MORPH_CLOSE, MORPH_RECT)); - filters->add(new ShapeDetect()); - //filters->add(new MaxChannel()); - //filters->add(new Normalize()); -#else - filters->add(new Undistort(cam)); - filters->add(new Pattern(Size(13, 9), 60)); - filters->add(new Perspective(cam, (Pattern *) filters->last())); -#endif + + PadDetect *pads = new PadDetect(); + PadFilter *filter = new PadFilter(pads); + + filters->add(pads); + filters->add(filter); + filters->add(new PathPlanner(filter, PathPlanner::NEAREST_NEIGHBOUR)); mwindow->show(); diff --git a/mainwindow.cpp b/mainwindow.cpp index 40c4196..68bf818 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -24,12 +24,17 @@ MainWindow::MainWindow(QWidget *parent) : static_cast(0.8 * ui->splitterH->width()), static_cast(0.2 * ui->splitterH->width()) }); + ui->splitterV->setSizes({ + static_cast(0.75 * ui->viewer->width()), + static_cast(0.25 * ui->viewer->width()) + }); /* Connect actions */ connect(images, &ImageList::newImage, ui->viewer, &Viewer::showImage); connect(source, &Source::newImage, ui->viewer, &Viewer::showImage); connect(filters, &FilterList::filtersChanged,ui->viewer, &Viewer::updateImage); connect(ui->actionRedraw, &QAction::triggered, ui->viewer, &Viewer::updateImage); + connect(ui->actionReset, &QAction::triggered, ui->viewer, &Viewer::reset); connect(ui->actionCalibrate, &QAction::triggered, ui->tabCalibration, &TabCalibration::doCalibration); connect(ui->actionSnapshot, &QAction::triggered, ui->tabCamera, &TabCamera::doSnapshot); connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::showAbout); @@ -39,6 +44,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->actionSave, &QAction::triggered, images, &ImageList::saveFilePicker); connect(ui->actionNextImage, &QAction::triggered, images, &ImageList::nextImage); connect(ui->actionPrevImage, &QAction::triggered, images, &ImageList::prevImage); + connect(ui->actionReset, &QAction::triggered, filters, &FilterList::reset); connect(ui->actionPlay, &QAction::triggered, source, &Source::play); connect(ui->actionTabImages, &QAction::triggered, [=]() { ui->tabWidget->setCurrentWidget(ui->tabImages); }); connect(ui->actionTabFilters, &QAction::triggered, [=]() { ui->tabWidget->setCurrentWidget(ui->tabFilters); }); @@ -49,6 +55,11 @@ MainWindow::MainWindow(QWidget *parent) : showMaximized(); } +void MainWindow::showEvent(QShowEvent *) +{ + ui->viewer->showImage(images->getCurrent()); +} + MainWindow::~MainWindow() { delete ui; diff --git a/mainwindow.h b/mainwindow.h index 01c8fd6..080c665 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -36,6 +36,8 @@ class MainWindow : public QMainWindow protected: Ui::MainWindow *ui; + void showEvent(QShowEvent *se); + signals: void newImage(Image *img); }; diff --git a/mainwindow.ui b/mainwindow.ui index bca46ee..7ce9993 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -29,27 +29,27 @@ QTabWidget::Triangular - + - + 0 0 - - Qt::Vertical + + + 320 + 0 + - - - - 0 - 0 - - + + Qt::Horizontal + + - Qt::Horizontal + Qt::Vertical @@ -68,57 +68,43 @@ Qt::DefaultContextMenu - - - true - + - + 0 0 - 200 - 400 + 0 + 150 - - - 16777215 - 16777215 - + + Qt::ScrollBarAlwaysOn - - QTabWidget::Rounded + + false - - 0 + + QPlainTextEdit::WidgetWidth + + + true + + + + + + true - - - Images - - - - - Filters - - - - - Camera - - - - - Calibration - - - + + + true + 0 @@ -127,22 +113,47 @@ - 0 - 100 + 200 + 400 - - false + + + 16777215 + 16777215 + - - true + + QTabWidget::Rounded - - - - - true + + 0 + + + Images + + + + + Filters + + + + + Camera + + + + + Calibration + + + + + Robot + + @@ -479,6 +490,12 @@
tabcalibration.h
1 + + TabRobot + QWidget +
tabrobot.h
+ 1 +
diff --git a/painter.cpp b/painter.cpp index e91e59e..56bec51 100644 --- a/painter.cpp +++ b/painter.cpp @@ -1,15 +1,38 @@ #include "painter.h" -Painter::Painter(QPaintDevice *device, double r) : - QPainter(device), - ratio(r) -{ } - - void Painter::drawMarker(const QPoint ¢er, int r) { + QBrush br(Qt::NoBrush); + setBrush(br); + + r /= getRatio(); + drawEllipse(center, r, r); drawLine(center + QPoint(+r, +r), center - QPoint(+r, +r)); drawLine(center + QPoint(+r, -r), center - QPoint(+r, -r)); } +void Painter::drawPad(const Pad &pad) +{ + const Point2f *v = pad.getVertexes(); + QPointF vq[4]; + + for (int i = 0; i < 4; i++) + vq[i] = toQt(v[i]); + + drawPolygon(vq, 4); +} + +void Painter::setPen(const QPen &pen) +{ + QPen p(pen); + + p.setWidthF((double) p.widthF() / getRatio()); + + QPainter::setPen(p); +} + +double Painter::getRatio() +{ + return (transform().m11() + transform().m22()) / 2; +} diff --git a/painter.h b/painter.h index 6d91e8d..c164c8d 100644 --- a/painter.h +++ b/painter.h @@ -3,16 +3,23 @@ #include +#include "cast.h" +#include "pad.h" + class Painter : public QPainter { public: - Painter(QPaintDevice *device, double ratio = 1); + Painter(QPaintDevice *dev) : + QPainter(dev) + { } void drawMarker(const QPoint ¢er, int radius = 8); + void drawPad(const Pad &pad); - protected: - double ratio; + /* Proxy to adjust width */ + void setPen(const QPen &pen); + double getRatio(); }; #endif // PAINTER_H diff --git a/source.cpp b/source.cpp index e0bbda6..86af502 100644 --- a/source.cpp +++ b/source.cpp @@ -71,16 +71,11 @@ void Source::play(bool run) void Source::tick() { - static bool running; + Mat m; - if (running) - return; - - running = true; - - if (read(last.original)) + if (read(m)) { + last.setSourceMat(m); emit newImage(&last); - - running = false; + } } diff --git a/tabcalibration.cpp b/tabcalibration.cpp index 2c29a1e..a131490 100644 --- a/tabcalibration.cpp +++ b/tabcalibration.cpp @@ -42,7 +42,7 @@ void TabCalibration::doCalibration() filters->add(pattern); - if (cam->calibrate(images->selectedImages().toStdList(), pattern)) + if (cam->calibrate(images->getSelected(), pattern)) showResults(); } diff --git a/tabfilters.cpp b/tabfilters.cpp index 133bd68..13f6451 100644 --- a/tabfilters.cpp +++ b/tabfilters.cpp @@ -14,7 +14,7 @@ TabFilters::TabFilters(QWidget *parent) : ui->tblFilters->setModel(filters); ui->tblFilters->setSelectionModel(&filters->selection); - connect(ui->tblFilters->verticalHeader(), &QHeaderView::sectionCountChanged, [&] () { + connect(ui->tblFilters->verticalHeader(), &QHeaderView::sectionCountChanged, [&]() { ui->tblFilters->resizeColumnsToContents(); ui->tblFilters->resizeRowsToContents(); }); diff --git a/tabimages.cpp b/tabimages.cpp index e6375c4..508dbd0 100644 --- a/tabimages.cpp +++ b/tabimages.cpp @@ -13,10 +13,12 @@ TabImages::TabImages(QWidget *parent) : ui->tblImages->setModel(images); ui->tblImages->setSelectionModel(&images->selection); - ui->tblImages->resizeColumnsToContents(); - ui->tblImages->setColumnWidth(0, 400); + ui->tblImages->setColumnWidth(0, 200); - connect(ui->tblImages->verticalHeader(), SIGNAL(sectionCountChanged(int,int)), this, SLOT(resizeTable(int,int))); + connect(ui->tblImages->verticalHeader(), &QHeaderView::sectionCountChanged, [&]() { + ui->tblImages->resizeColumnsToContents(); + ui->tblImages->resizeRowsToContents(); + }); connect(ui->btnClear, &QPushButton::clicked, images, &ImageList::clear); connect(ui->btnLoad, &QPushButton::clicked, images, &ImageList::loadFilePicker); connect(ui->btnSave, &QPushButton::clicked, images, &ImageList::saveFilePicker); @@ -26,9 +28,3 @@ TabImages::~TabImages() { delete ui; } - -void TabImages::resizeTable(int, int) -{ - ui->tblImages->resizeColumnsToContents(); - ui->tblImages->resizeRowsToContents(); -} diff --git a/tabimages.h b/tabimages.h index a512d06..c5c9992 100644 --- a/tabimages.h +++ b/tabimages.h @@ -17,9 +17,6 @@ class TabImages : public QWidget explicit TabImages(QWidget *parent = 0); ~TabImages(); - protected slots: - void resizeTable(int, int); - private: Ui::TabImages *ui; }; diff --git a/viewer.cpp b/viewer.cpp index d621770..99a8105 100644 --- a/viewer.cpp +++ b/viewer.cpp @@ -20,109 +20,204 @@ Viewer::Viewer(QWidget *parent) : img(NULL) { } +void Viewer::reset() +{ + Mat &m = img->getMat(); + updateWindow(QRect(0, 0, m.cols, m.rows)); +} + void Viewer::resizeEvent(QResizeEvent *) { - updateViewport(); + updateTransform(); } void Viewer::paintEvent(QPaintEvent *) { - Painter p(this, 1 / ratio); + Painter p(this); + QPen pe; + p.setRenderHint(QPainter::Antialiasing); p.fillRect(rect(), Qt::black); + p.setClipRect(viewport); + p.setTransform(transform); - if (!img) - return; + pe.setStyle(Qt::SolidLine); + pe.setWidth(2); + p.setPen(pe); - p.setViewport(viewport); - p.setWindow(qimg.rect()); + if (img) { + p.drawImage(window, qimg, window); - p.drawImage(p.window(), qimg); + for (auto it = filters->begin(); it != filters->end(); it++) { + Result *result = img->getResult(*it); + if (result && (*it)->isShown()) { + p.save(); - QPen pen = p.pen(); - pen.setColor(Qt::green); - pen.setWidth(2 / ratio); - p.setPen(pen); + /*QTransform t; + for (auto it2 = it+1; it2 != filters->end(); it2++) { + Result *result2 = img->getResult(*it2); + if (result2 && (*it2)->isShown()) + t *= result2->getTransform(); + } + p.setWorldTransform(t * transform);*/ - for (auto filter : *filters) { - Result *result = img->getResult(filter); - - if (filter->isShown() && result) - result->draw(&p); + result->drawResult(&p); + p.restore(); + } + } } + + if (!first.isNull() && !last.isNull()) { + QRect sel(unmap(first), unmap(last)); + + pe.setWidth(2); + pe.setStyle(Qt::SolidLine); + pe.setColor(Qt::black); + p.setPen(pe); + p.drawRect(sel.normalized()); + + pe.setStyle(Qt::DotLine); + pe.setBrush(Qt::white); + p.setPen(pe); + p.drawRect(sel.normalized()); + } +} + +void Viewer::wheelEvent(QWheelEvent * we) +{ + QPoint numPixels = we->pixelDelta(); + QPoint numDegrees = we->angleDelta() / 8; + + int d = 0; + + if (!numPixels.isNull()) + d = numPixels.y(); + else if (!numDegrees.isNull()) + d = numDegrees.y(); + + double ratio = (double) window.width() / window.height(); + + if (d > 0 || (d < 0 && window.height() + 2*d > 32)) { + updateWindow(window.adjusted( + -d * ratio, -d, + d * ratio, d + )); + + update(); + we->accept(); + } + else + we->ignore(); +} + +void Viewer::mousePressEvent(QMouseEvent *me) +{ + if (viewport.contains(me->pos())) { + if (me->modifiers() & Qt::AltModifier) + first = me->pos(); + else + last = me->pos(); + } +} + +void Viewer::mouseMoveEvent(QMouseEvent *me) +{ + if (viewport.contains(me->pos())) { + if (me->modifiers() & Qt::AltModifier) { + update(); + } + else { + QPoint delta = (me->pos() - last) / transform.m11(); + window.moveCenter(window.center() - delta); + + updateWindow(window); + update(); + } + } + + last = me->pos(); } void Viewer::mouseReleaseEvent(QMouseEvent *me) { if (viewport.contains(me->pos())) { - QPoint pos = transformInv(me->pos()); + if (me->modifiers() & Qt::AltModifier) { + if (!first.isNull() && !last.isNull()) + updateWindow(QRect(unmap(first), unmap(last)).normalized()); + } + else if (last.isNull()) { + QPoint pos = unmap(me->pos()); + Filter *f = filters->getCurrent(); - qDebug() << "Clicked at: " << pos.x() << "," << pos.y(); + qDebug() << "Clicked at: " << pos << "(" << me->pos() << ")"; - clicks.push_back(Point(pos.x(), pos.y())); - emit clicked(pos); + if (f) { + if (f->clicked(toCv(pos), me)) + updateImage(); + } + } } -} -QPoint Viewer::transform(QPoint pos) -{ - return pos * ratio + viewport.topLeft(); -} - -QPoint Viewer::transformInv(QPoint pos) -{ - return (pos - viewport.topLeft()) / ratio; -} - -void Viewer::showImage(Image *next) -{ - if (!next) - return; - - if (next != img) - filters->reset(); - - img = next; - updateImage(); -} - -void Viewer::updateImage() -{ - if (!img) - return; - - filters->execute(img); - - qimg = toQImage(img->filtered); - - if (size != img->filtered.size()) { - size = img->filtered.size(); - updateViewport(); - } + first = last = QPoint(); update(); } -void Viewer::updateViewport() +void Viewer::showImage(Image *next) { - double viewRatio = (double) size.width / size.height; + if (next) { + if (next != img) + filters->reset(); - int viewHeight = width() / viewRatio; - int viewWidth = width(); - - if (viewHeight > height()) { - viewWidth = height() * viewRatio; - viewHeight = height(); + img = next; + updateImage(); } - - viewport = QRect( - (width() - viewWidth) / 2, - (height() - viewHeight) / 2, - viewWidth, - viewHeight - ); - - qDebug() << "New viewport" << viewport << " in widget " << rect() << " for frame " << toQt(size); - - ratio = (double) viewport.width() / size.width; +} + +void Viewer::updateImage() +{ + if (img) { + filters->execute(img); + + Mat &m = img->getMat(); + qimg = toQImage(m); + + if (window.size() != toQt(m.size())) + updateWindow(QRect(0, 0, m.cols, m.rows)); + + update(); + } +} + +void Viewer::updateWindow(const QRect &win) +{ + window = win; + updateTransform(); +} + +void Viewer::updateTransform() +{ + QSizeF s = window.size(); + s.scale(size(), Qt::KeepAspectRatio); + + viewport.setRect((double) (width() - s.width()) / 2, + (double) (height() - s.height()) / 2, + s.width(), s.height() ); + + double sc = (double) viewport.width() / window.width(); + + transform.reset(); + transform.translate(viewport.x(), viewport.y()); + transform.scale(sc, sc); + transform.translate( -window.x(), -window.y()); +} + +QPoint Viewer::map(const QPoint &p) const +{ + return transform.map(p); +} + +QPoint Viewer::unmap(const QPoint &p) const +{ + return transform.inverted().map(p); } diff --git a/viewer.h b/viewer.h index 7b7b238..c8ef341 100644 --- a/viewer.h +++ b/viewer.h @@ -17,31 +17,33 @@ class Viewer : public QGLWidget public: explicit Viewer(QWidget *parent = 0); - Image *img; - - QVector clicks; - protected: - QPoint transform(QPoint pos); - QPoint transformInv(QPoint pos); - void paintEvent(QPaintEvent *pe); void resizeEvent(QResizeEvent *re); + + void wheelEvent(QWheelEvent *we); + void mousePressEvent(QMouseEvent *me); + void mouseMoveEvent(QMouseEvent *me); void mouseReleaseEvent(QMouseEvent *me); + QPoint map(const QPoint &p) const; + QPoint unmap(const QPoint &p) const; + + void updateTransform(); + void updateWindow(const QRect &r); + + Image *img; QImage qimg; QRect viewport; - - Size size; - double ratio; - - signals: - void clicked(QPoint pos); + QRect window; + QPoint first, last; + QTransform transform; public slots: void showImage(Image *img); void updateImage(); - void updateViewport(); + + void reset(); }; #endif // VIEWER_H