From 56e372f8d2b3f651764c9fd84a13c5811e4af32b Mon Sep 17 00:00:00 2001 From: matlabbe Date: Mon, 30 Mar 2015 10:47:38 -0400 Subject: [PATCH] Updated ImageView with GraphicsView mode disabled by default. Updated DataRecorder. --- guilib/include/rtabmap/gui/DataRecorder.h | 11 +- guilib/include/rtabmap/gui/ImageView.h | 45 +- guilib/include/rtabmap/gui/KeypointItem.h | 6 +- guilib/src/DataRecorder.cpp | 73 ++- guilib/src/DatabaseViewer.cpp | 57 +-- guilib/src/ImageView.cpp | 581 ++++++++++++++++------ guilib/src/KeypointItem.cpp | 14 +- guilib/src/MainWindow.cpp | 212 ++++---- guilib/src/PreferencesDialog.cpp | 21 + guilib/src/ui/DatabaseViewer.ui | 48 +- guilib/src/ui/mainWindow.ui | 39 +- tools/DataRecorder/main.cpp | 2 +- tools/EpipolarGeometry/main.cpp | 54 +- 13 files changed, 718 insertions(+), 445 deletions(-) diff --git a/guilib/include/rtabmap/gui/DataRecorder.h b/guilib/include/rtabmap/gui/DataRecorder.h index 60e98cf5..6b0a3d45 100644 --- a/guilib/include/rtabmap/gui/DataRecorder.h +++ b/guilib/include/rtabmap/gui/DataRecorder.h @@ -34,6 +34,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include + +class QLabel; namespace rtabmap { @@ -55,17 +58,21 @@ public: public slots: void addData(const rtabmap::SensorData & data); - void showImage(const rtabmap::SensorData & data); + void showImage(const cv::Mat & image, const cv::Mat & depth); protected: virtual void closeEvent(QCloseEvent* event); void handleEvent(UEvent * event); private: + UMutex memoryMutex_; Memory * memory_; ImageView* imageView_; + QLabel* label_; UTimer timer_; - int dataQueue_; QString path_; + bool processingImages_; + int count_; + int totalSizeKB_; }; } /* namespace rtabmap */ diff --git a/guilib/include/rtabmap/gui/ImageView.h b/guilib/include/rtabmap/gui/ImageView.h index eb5dbb36..d661bff8 100644 --- a/guilib/include/rtabmap/gui/ImageView.h +++ b/guilib/include/rtabmap/gui/ImageView.h @@ -44,7 +44,7 @@ namespace rtabmap { class KeypointItem; -class RTABMAPGUI_EXP ImageView : public QGraphicsView { +class RTABMAPGUI_EXP ImageView : public QWidget { Q_OBJECT @@ -55,48 +55,57 @@ public: void saveSettings(QSettings & settings, const QString & group = "") const; void loadSettings(QSettings & settings, const QString & group = ""); - void resetZoom(); - bool isImageShown() const; bool isImageDepthShown() const; bool isFeaturesShown() const; bool isLinesShown() const; int getAlpha() const {return _alpha;} + bool isGraphicsViewMode() const; + bool isGraphicsViewScaled() const; + + float viewScale() const; void setFeaturesShown(bool shown); void setImageShown(bool shown); void setImageDepthShown(bool shown); void setLinesShown(bool shown); + void setGraphicsViewMode(bool on); + void setGraphicsViewScaled(bool scaled); + void setBackgroundColor(const QColor & color); - void setFeatures(const std::multimap & refWords, const QColor & color = QColor(255, 255, 0, 70)); - void setFeatures(const std::vector & features, const QColor & color = QColor(255, 255, 0, 70)); + void setFeatures(const std::multimap & refWords, const QColor & color = Qt::yellow); + void setFeatures(const std::vector & features, const QColor & color = Qt::yellow); + void addFeature(int id, const cv::KeyPoint & kpt, QColor color); + void addLine(float x1, float y1, float x2, float y2, QColor color); void setImage(const QImage & image); void setImageDepth(const QImage & image); - void setFeatureColor(int id, const QColor & color); - void setFeaturesColor(const QColor & color); + void setFeatureColor(int id, QColor color); + void setFeaturesColor(QColor color); void setAlpha(int alpha); + void setSceneRect(const QRectF & rect); const QMultiMap & getFeatures() const {return _features;} void clearLines(); void clear(); + virtual QSize sizeHint() const; + signals: void configChanged(); protected: + virtual void paintEvent(QPaintEvent *event); + virtual void resizeEvent(QResizeEvent* event); virtual void contextMenuEvent(QContextMenuEvent * e); - virtual void wheelEvent(QWheelEvent * e); - -private slots: - void updateZoom(); private: void updateOpacity(); + void computeScaleOffsets(float & scale, float & offsetX, float & offsetY) const; + void drawFeatures(QPainter * painter); + void drawLines(QPainter * painter); private: - int _zoom; - int _minZoom; QString _savedFileName; int _alpha; @@ -107,10 +116,16 @@ private: QAction * _showLines; QAction * _saveImage; QAction * _setAlpha; + QAction * _graphicsViewMode; + QAction * _graphicsViewScaled; + QGraphicsView * _graphicsView; QMultiMap _features; - QGraphicsPixmapItem * _image; - QGraphicsPixmapItem * _imageDepth; + QList _lines; + QGraphicsPixmapItem * _imageItem; + QGraphicsPixmapItem * _imageDepthItem; + QPixmap _image; + QPixmap _imageDepth; }; } diff --git a/guilib/include/rtabmap/gui/KeypointItem.h b/guilib/include/rtabmap/gui/KeypointItem.h index 3daa8752..add89b37 100644 --- a/guilib/include/rtabmap/gui/KeypointItem.h +++ b/guilib/include/rtabmap/gui/KeypointItem.h @@ -34,13 +34,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include namespace rtabmap { class RTABMAPGUI_EXP KeypointItem : public QGraphicsEllipseItem { public: - KeypointItem(qreal x, qreal y, int r, const QString & info, const QColor & color = Qt::green, QGraphicsItem * parent = 0); + KeypointItem(int id, const cv::KeyPoint & kpt, const QColor & color = Qt::green, QGraphicsItem * parent = 0); virtual ~KeypointItem(); void setColor(const QColor & color); @@ -56,7 +57,8 @@ private: void hideDescription(); private: - QString _info; + int _id; + cv::KeyPoint _kpt; QGraphicsRectItem * _placeHolder; int _width; }; diff --git a/guilib/src/DataRecorder.cpp b/guilib/src/DataRecorder.cpp index 98efb4f3..9d13760a 100644 --- a/guilib/src/DataRecorder.cpp +++ b/guilib/src/DataRecorder.cpp @@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include #include @@ -37,7 +38,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include +#include +#include namespace rtabmap { @@ -46,18 +48,25 @@ DataRecorder::DataRecorder(QWidget * parent) : QWidget(parent), memory_(0), imageView_(new ImageView(this)), - dataQueue_(0) + label_(new QLabel(this)), + processingImages_(false), + count_(0), + totalSizeKB_(0) { - qRegisterMetaType("rtabmap::SensorData"); + qRegisterMetaType("cv::Mat"); imageView_->setImageDepthShown(true); - QHBoxLayout * layout = new QHBoxLayout(this); + imageView_->setMinimumSize(320, 240); + QVBoxLayout * layout = new QVBoxLayout(this); layout->setMargin(0); layout->addWidget(imageView_); + layout->addWidget(label_); + layout->setStretch(0,1); this->setLayout(layout); } bool DataRecorder::init(const QString & path, bool recordInRAM) { + UScopeMutex scope(memoryMutex_); if(!memory_) { ParametersMap customParameters; @@ -88,11 +97,16 @@ bool DataRecorder::init(const QString & path, bool recordInRAM) void DataRecorder::closeRecorder() { + memoryMutex_.lock(); if(memory_) { delete memory_; memory_ = 0; } + memoryMutex_.unlock(); + processingImages_ = false; + count_ = 0; + totalSizeKB_ = 0; UINFO("Data recorded to \"%s\".", this->path().toStdString().c_str()); if(this->isVisible()) { @@ -102,36 +116,39 @@ void DataRecorder::closeRecorder() DataRecorder::~DataRecorder() { + this->unregisterFromEventsManager(); this->closeRecorder(); } void DataRecorder::addData(const rtabmap::SensorData & data) { + memoryMutex_.lock(); if(memory_) { //save to database UTimer time; memory_->update(data); + const Signature * s = memory_->getLastWorkingSignature(); + totalSizeKB_ += s->getImageCompressed().total()/1000; + totalSizeKB_ += s->getDepthCompressed().total()/1000; memory_->cleanup(); - if(data.id() % 30) + if(++count_ % 30) { memory_->emptyTrash(); } - UDEBUG("Time to process a message = %f s", time.ticks()); } - --dataQueue_; + memoryMutex_.unlock(); } -void DataRecorder::showImage(const rtabmap::SensorData & data) +void DataRecorder::showImage(const cv::Mat & image, const cv::Mat & depth) { - if(this->isVisible() && data.isValid()) - { - imageView_->setImage(uCvMat2QImage(data.image())); - imageView_->setImageDepth(uCvMat2QImage(data.depth())); - imageView_->fitInView(imageView_->sceneRect(), Qt::KeepAspectRatio); - } + processingImages_ = true; + imageView_->setImage(uCvMat2QImage(image)); + imageView_->setImageDepth(uCvMat2QImage(depth)); + label_->setText(tr("Images=%1 (~%2 MB)").arg(count_).arg(totalSizeKB_/1000)); + processingImages_ = false; } void DataRecorder::closeEvent(QCloseEvent* event) @@ -142,24 +159,26 @@ void DataRecorder::closeEvent(QCloseEvent* event) void DataRecorder::handleEvent(UEvent * event) { - if(event->getClassName().compare("CameraEvent") == 0) + if(memory_) { - CameraEvent * camEvent = (CameraEvent*)event; - if(camEvent->getCode() == CameraEvent::kCodeImageDepth || - camEvent->getCode() == CameraEvent::kCodeImage) + if(event->getClassName().compare("CameraEvent") == 0) { - if(camEvent->data().isValid()) + CameraEvent * camEvent = (CameraEvent*)event; + if(camEvent->getCode() == CameraEvent::kCodeImageDepth || + camEvent->getCode() == CameraEvent::kCodeImage) { - UINFO("Receiving rate = %f Hz", 1.0f/timer_.ticks()); - if(memory_) + if(camEvent->data().isValid()) { - QMetaObject::invokeMethod(this, "addData", Q_ARG(rtabmap::SensorData, camEvent->data())); - ++dataQueue_; - } + UINFO("Receiving rate = %f Hz", 1.0f/timer_.ticks()); + this->addData(camEvent->data()); - if(dataQueue_ < 2 && this->isVisible()) - { - QMetaObject::invokeMethod(this, "showImage", Q_ARG(rtabmap::SensorData, camEvent->data())); + if(!processingImages_ && this->isVisible() && camEvent->data().isValid()) + { + processingImages_ = true; + QMetaObject::invokeMethod(this, "showImage", + Q_ARG(cv::Mat, camEvent->data().image()), + Q_ARG(cv::Mat, camEvent->data().depth())); + } } } } diff --git a/guilib/src/DatabaseViewer.cpp b/guilib/src/DatabaseViewer.cpp index fd2d289e..da8de194 100644 --- a/guilib/src/DatabaseViewer.cpp +++ b/guilib/src/DatabaseViewer.cpp @@ -612,11 +612,6 @@ void DatabaseViewer::closeEvent(QCloseEvent* event) void DatabaseViewer::showEvent(QShowEvent* anEvent) { - ui_->graphicsView_A->fitInView(ui_->graphicsView_A->sceneRect(), Qt::KeepAspectRatio); - ui_->graphicsView_B->fitInView(ui_->graphicsView_B->sceneRect(), Qt::KeepAspectRatio); - ui_->graphicsView_A->resetZoom(); - ui_->graphicsView_B->resetZoom(); - this->setWindowModified(false); } @@ -635,10 +630,6 @@ void DatabaseViewer::moveEvent(QMoveEvent* anEvent) void DatabaseViewer::resizeEvent(QResizeEvent* anEvent) { - ui_->graphicsView_A->fitInView(ui_->graphicsView_A->sceneRect(), Qt::KeepAspectRatio); - ui_->graphicsView_B->fitInView(ui_->graphicsView_B->sceneRect(), Qt::KeepAspectRatio); - ui_->graphicsView_A->resetZoom(); - ui_->graphicsView_B->resetZoom(); if(this->isVisible()) { this->configModified(); @@ -1362,7 +1353,6 @@ void DatabaseViewer::update(int value, if(value >= 0 && value < ids_.size()) { view->clear(); - view->resetTransform(); int id = ids_.at(value); int mapId = -1; labelId->setText(QString::number(id)); @@ -1557,11 +1547,6 @@ void DatabaseViewer::update(int value, { view->setSceneRect(rect); } - else - { - view->setSceneRect(view->scene()->itemsBoundingRect()); - } - view->fitInView(view->sceneRect(), Qt::KeepAspectRatio); } void DatabaseViewer::updateStereo(const Signature * data) @@ -1680,20 +1665,13 @@ void DatabaseViewer::updateStereo(const Signature * data) //ui_->graphicsView_stereo->setImage(uCvMat2QImage(imageMatches)); - ui_->graphicsView_stereo->scene()->clear(); - ui_->graphicsView_stereo->setSceneRect(0,0,(float)leftMono.cols, (float)leftMono.rows); + ui_->graphicsView_stereo->clear(); ui_->graphicsView_stereo->setLinesShown(true); ui_->graphicsView_stereo->setFeaturesShown(false); + ui_->graphicsView_stereo->setImageDepthShown(true); - QGraphicsPixmapItem * item1 = ui_->graphicsView_stereo->scene()->addPixmap(QPixmap::fromImage(uCvMat2QImage(data->getImageRaw()))); - QGraphicsPixmapItem * item2 = ui_->graphicsView_stereo->scene()->addPixmap(QPixmap::fromImage(uCvMat2QImage(data->getDepthRaw()))); - - QGraphicsOpacityEffect * effect1 = new QGraphicsOpacityEffect(); - QGraphicsOpacityEffect * effect2 = new QGraphicsOpacityEffect(); - effect1->setOpacity(0.5); - effect2->setOpacity(0.5); - item1->setGraphicsEffect(effect1); - item2->setGraphicsEffect(effect2); + ui_->graphicsView_stereo->setImage(uCvMat2QImage(data->getImageRaw())); + ui_->graphicsView_stereo->setImageDepth(uCvMat2QImage(data->getDepthRaw())); // Draw lines between corresponding features... for(unsigned int i=0; igraphicsView_stereo->scene()->addLine( + ui_->graphicsView_stereo->addLine( kpts[i].pt.x, kpts[i].pt.y, rightKpts[i].pt.x, rightKpts[i].pt.y, - QPen(c)); - item->setZValue(1); + c); } + ui_->graphicsView_stereo->update(); } } @@ -1748,35 +1726,34 @@ void DatabaseViewer::updateWordsMatching() if(wordsA.count(ids[i]) == 1 && wordsB.count(ids[i]) == 1) { // PINK features - ui_->graphicsView_A->setFeatureColor(ids[i], QColor(255, 0, 255, alpha)); - ui_->graphicsView_B->setFeatureColor(ids[i], QColor(255, 0, 255, alpha)); + ui_->graphicsView_A->setFeatureColor(ids[i], Qt::magenta); + ui_->graphicsView_B->setFeatureColor(ids[i], Qt::magenta); // Add lines // Draw lines between corresponding features... - float deltaX = ui_->graphicsView_A->sceneRect().width(); + float scaleX = ui_->graphicsView_A->viewScale(); + float deltaX = ui_->graphicsView_A->width()/scaleX; float deltaY = 0; const KeypointItem * kptA = wordsA.value(ids[i]); const KeypointItem * kptB = wordsB.value(ids[i]); - QGraphicsLineItem * item = ui_->graphicsView_A->scene()->addLine( + ui_->graphicsView_A->addLine( kptA->rect().x()+kptA->rect().width()/2, kptA->rect().y()+kptA->rect().height()/2, kptB->rect().x()+kptB->rect().width()/2+deltaX, kptB->rect().y()+kptB->rect().height()/2+deltaY, - QPen(QColor(0, 255, 255, alpha))); - item->setVisible(ui_->graphicsView_A->isLinesShown()); - item->setZValue(1); + Qt::cyan); - item = ui_->graphicsView_B->scene()->addLine( + ui_->graphicsView_B->addLine( kptA->rect().x()+kptA->rect().width()/2-deltaX, kptA->rect().y()+kptA->rect().height()/2-deltaY, kptB->rect().x()+kptB->rect().width()/2, kptB->rect().y()+kptB->rect().height()/2, - QPen(QColor(0, 255, 255, alpha))); - item->setVisible(ui_->graphicsView_B->isLinesShown()); - item->setZValue(1); + Qt::cyan); } } + ui_->graphicsView_A->update(); + ui_->graphicsView_B->update(); } } } diff --git a/guilib/src/ImageView.cpp b/guilib/src/ImageView.cpp index fc8df306..80e43e9f 100644 --- a/guilib/src/ImageView.cpp +++ b/guilib/src/ImageView.cpp @@ -35,23 +35,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "rtabmap/utilite/ULogger.h" #include "rtabmap/gui/KeypointItem.h" namespace rtabmap { ImageView::ImageView(QWidget * parent) : - QGraphicsView(parent), - _zoom(250), - _minZoom(250), + QWidget(parent), _savedFileName((QDir::homePath()+ "/") + "picture" + ".png"), _alpha(100), - _image(0), - _imageDepth(0) + _imageItem(0), + _imageDepthItem(0) { - this->setTransformationAnchor(QGraphicsView::AnchorUnderMouse); - this->setScene(new QGraphicsScene(this)); - connect(this->scene(), SIGNAL(sceneRectChanged(const QRectF &)), this, SLOT(updateZoom())); + _graphicsView = new QGraphicsView(this); + _graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse); + _graphicsView->setScene(new QGraphicsScene(this)); + _graphicsView->setVisible(false); + + this->setLayout(new QVBoxLayout(this)); + this->layout()->addWidget(_graphicsView); + this->layout()->setContentsMargins(0,0,0,0); _menu = new QMenu(tr(""), this); _showImage = _menu->addAction(tr("Show image")); @@ -66,6 +70,13 @@ ImageView::ImageView(QWidget * parent) : _showLines = _menu->addAction(tr("Show lines")); _showLines->setCheckable(true); _showLines->setChecked(true); + _graphicsViewMode = _menu->addAction(tr("Graphics view")); + _graphicsViewMode->setCheckable(true); + _graphicsViewMode->setChecked(false); + _graphicsViewScaled = _menu->addAction(tr("Scale image")); + _graphicsViewScaled->setCheckable(true); + _graphicsViewScaled->setChecked(true); + _graphicsViewScaled->setEnabled(false); _setAlpha = _menu->addAction(tr("Set alpha...")); _saveImage = _menu->addAction(tr("Save picture...")); } @@ -85,6 +96,8 @@ void ImageView::saveSettings(QSettings & settings, const QString & group) const settings.setValue("features_shown", this->isFeaturesShown()); settings.setValue("lines_shown", this->isLinesShown()); settings.setValue("alpha", this->getAlpha()); + settings.setValue("graphics_view", this->isGraphicsViewMode()); + settings.setValue("graphics_view_scale", this->isGraphicsViewScaled()); if(!group.isEmpty()) { settings.endGroup(); @@ -102,18 +115,14 @@ void ImageView::loadSettings(QSettings & settings, const QString & group) this->setFeaturesShown(settings.value("features_shown", this->isFeaturesShown()).toBool()); this->setLinesShown(settings.value("lines_shown", this->isLinesShown()).toBool()); this->setAlpha(settings.value("alpha", this->getAlpha()).toInt()); + this->setGraphicsViewMode(settings.value("graphics_view", this->isGraphicsViewMode()).toBool()); + this->setGraphicsViewScaled(settings.value("graphics_view_scale", this->isGraphicsViewScaled()).toBool()); if(!group.isEmpty()) { settings.endGroup(); } } -void ImageView::resetZoom() -{ - _zoom = _minZoom; - this->setDragMode(QGraphicsView::NoDrag); -} - bool ImageView::isImageShown() const { return _showImage->isChecked(); @@ -129,6 +138,16 @@ bool ImageView::isFeaturesShown() const return _showFeatures->isChecked(); } +bool ImageView::isGraphicsViewMode() const +{ + return _graphicsViewMode->isChecked(); +} + +bool ImageView::isGraphicsViewScaled() const +{ + return _graphicsViewScaled->isChecked(); +} + void ImageView::setFeaturesShown(bool shown) { _showFeatures->setChecked(shown); @@ -136,26 +155,41 @@ void ImageView::setFeaturesShown(bool shown) { iter.value()->setVisible(_showFeatures->isChecked()); } + + if(!_graphicsView->isVisible()) + { + this->update(); + } } void ImageView::setImageShown(bool shown) { _showImage->setChecked(shown); - if(_image) + if(_imageItem) { - _image->setVisible(_showImage->isChecked()); + _imageItem->setVisible(_showImage->isChecked()); this->updateOpacity(); } + + if(!_graphicsView->isVisible()) + { + this->update(); + } } void ImageView::setImageDepthShown(bool shown) { _showImageDepth->setChecked(shown); - if(_imageDepth) + if(_imageDepthItem) { - _imageDepth->setVisible(_showImageDepth->isChecked()); + _imageDepthItem->setVisible(_showImageDepth->isChecked()); this->updateOpacity(); } + + if(!_graphicsView->isVisible()) + { + this->update(); + } } bool ImageView::isLinesShown() const @@ -166,13 +200,233 @@ bool ImageView::isLinesShown() const void ImageView::setLinesShown(bool shown) { _showLines->setChecked(shown); - QList items = this->scene()->items(); - for(int i=0; i(items.at(i))) + _lines.at(i)->setVisible(_showLines->isChecked()); + } + + if(!_graphicsView->isVisible()) + { + this->update(); + } +} + +float ImageView::viewScale() const +{ + if(_graphicsView->isVisible()) + { + return _graphicsView->transform().m11(); + } + else + { + float scale, offsetX, offsetY; + computeScaleOffsets(scale, offsetX, offsetY); + return scale; + } +} + +void ImageView::setGraphicsViewMode(bool on) +{ + _graphicsViewMode->setChecked(on); + _graphicsView->setVisible(on); + _graphicsViewScaled->setEnabled(on); + + if(on) + { + for(QMultiMap::iterator iter=_features.begin(); iter!=_features.end(); ++iter) { - items.at(i)->setVisible(_showLines->isChecked()); + _graphicsView->scene()->addItem(iter.value()); } + + for(QList::iterator iter=_lines.begin(); iter!=_lines.end(); ++iter) + { + _graphicsView->scene()->addItem(*iter); + } + + //update images + if(_imageItem) + { + _imageItem->setPixmap(_image); + } + else + { + _imageItem = _graphicsView->scene()->addPixmap(_image); + _imageItem->setVisible(_showImage->isChecked()); + _showImage->setEnabled(true); + } + + if(_imageDepthItem) + { + _imageDepthItem->setPixmap(_imageDepth); + } + else + { + _imageDepthItem = _graphicsView->scene()->addPixmap(_imageDepth); + _imageDepthItem->setVisible(_showImageDepth->isChecked()); + _showImageDepth->setEnabled(true); + } + this->updateOpacity(); + + if(_graphicsViewScaled->isChecked()) + { + _graphicsView->fitInView(_graphicsView->sceneRect(), Qt::KeepAspectRatio); + } + else + { + _graphicsView->resetTransform(); + } + } + else + { + this->update(); + } +} + +void ImageView::setGraphicsViewScaled(bool scaled) +{ + _graphicsViewScaled->setChecked(scaled); + + if(scaled) + { + _graphicsView->fitInView(_graphicsView->sceneRect(), Qt::KeepAspectRatio); + } + else + { + _graphicsView->resetTransform(); + } + + if(!_graphicsView->isVisible()) + { + this->update(); + } +} + +void ImageView::setBackgroundColor(const QColor & color) +{ + _graphicsView->setBackgroundBrush(QBrush(color)); + + if(!_graphicsView->isVisible()) + { + this->update(); + } +} + +void ImageView::computeScaleOffsets(float & scale, float & offsetX, float & offsetY) const +{ + scale = 1.0f; + offsetX = 0.0f; + offsetY = 0.0f; + + if(!_graphicsView->scene()->sceneRect().isNull()) + { + float w = _graphicsView->scene()->width(); + float h = _graphicsView->scene()->height(); + float widthRatio = float(this->rect().width()) / w; + float heightRatio = float(this->rect().height()) / h; + + //printf("w=%f, h=%f, wR=%f, hR=%f, sW=%d, sH=%d\n", w, h, widthRatio, heightRatio, this->rect().width(), this->rect().height()); + if(widthRatio < heightRatio) + { + scale = widthRatio; + } + else + { + scale = heightRatio; + } + + //printf("ratio=%f\n",ratio); + + w *= scale; + h *= scale; + + if(w < this->rect().width()) + { + offsetX = (this->rect().width() - w)/2.0f; + } + if(h < this->rect().height()) + { + offsetY = (this->rect().height() - h)/2.0f; + } + //printf("offsetX=%f, offsetY=%f\n",offsetX, offsetY); + } +} + +void ImageView::paintEvent(QPaintEvent *event) +{ + if(_graphicsViewMode->isChecked()) + { + QWidget::paintEvent(event); + } + else + { + if(!_graphicsView->scene()->sceneRect().isNull()) + { + //Scale + float ratio, offsetX, offsetY; + this->computeScaleOffsets(ratio, offsetX, offsetY); + QPainter painter(this); + + //Background + painter.save(); + painter.setBrush(_graphicsView->backgroundBrush()); + painter.drawRect(this->rect()); + painter.restore(); + + painter.translate(offsetX, offsetY); + painter.scale(ratio, ratio); + + painter.save(); + if(_showImage->isChecked() && !_image.isNull() && + _showImageDepth->isChecked() && !_imageDepth.isNull()) + { + painter.setOpacity(0.5); + } + + if(_showImage->isChecked() && !_image.isNull()) + { + painter.drawPixmap(QPoint(0,0), _image); + } + + if(_showImageDepth->isChecked() && !_imageDepth.isNull()) + { + painter.drawPixmap(QPoint(0,0), _imageDepth); + } + painter.restore(); + + if(_showFeatures->isChecked()) + { + for(QMultiMap::iterator iter = _features.begin(); iter != _features.end(); ++iter) + { + QColor color = iter.value()->pen().color(); + painter.save(); + painter.setPen(color); + painter.setBrush(color); + painter.drawEllipse(iter.value()->rect()); + painter.restore(); + } + } + + if(_showLines->isChecked()) + { + for(QList::iterator iter = _lines.begin(); iter != _lines.end(); ++iter) + { + QColor color = (*iter)->pen().color(); + painter.save(); + painter.setPen(color); + painter.drawLine((*iter)->line()); + painter.restore(); + } + } + } + } +} + +void ImageView::resizeEvent(QResizeEvent* event) +{ + QWidget::resizeEvent(event); + if(_graphicsView->isVisible() && _graphicsViewScaled->isChecked()) + { + _graphicsView->fitInView(_graphicsView->sceneRect(), Qt::KeepAspectRatio); } } @@ -190,9 +444,9 @@ void ImageView::contextMenuEvent(QContextMenuEvent * e) if(!text.isEmpty()) { _savedFileName = text; - QImage img(this->sceneRect().width(), this->sceneRect().height(),QImage::Format_ARGB32_Premultiplied); + QImage img(_graphicsView->sceneRect().width(), _graphicsView->sceneRect().height(),QImage::Format_ARGB32_Premultiplied); QPainter p(&img); - this->scene()->render(&p, this->sceneRect(), this->sceneRect()); + _graphicsView->scene()->render(&p, _graphicsView->sceneRect(), _graphicsView->sceneRect()); img.save(text); } } @@ -216,6 +470,16 @@ void ImageView::contextMenuEvent(QContextMenuEvent * e) this->setLinesShown(_showLines->isChecked()); emit configChanged(); } + else if(action == _graphicsViewMode) + { + this->setGraphicsViewMode(_graphicsViewMode->isChecked()); + emit configChanged(); + } + else if(action == _graphicsViewScaled) + { + this->setGraphicsViewScaled(_graphicsViewScaled->isChecked()); + emit configChanged(); + } else if(action == _setAlpha) { bool ok = false; @@ -236,96 +500,46 @@ void ImageView::contextMenuEvent(QContextMenuEvent * e) void ImageView::updateOpacity() { - if(_image && _imageDepth) + if(_imageItem && _imageDepthItem) { - if(_image->isVisible() && _imageDepth->isVisible()) + if(_imageItem->isVisible() && _imageDepthItem->isVisible()) { QGraphicsOpacityEffect * effect = new QGraphicsOpacityEffect(); QGraphicsOpacityEffect * effect2 = new QGraphicsOpacityEffect(); effect->setOpacity(0.5); effect2->setOpacity(0.5); - _image->setGraphicsEffect(effect); - _imageDepth->setGraphicsEffect(effect2); + _imageItem->setGraphicsEffect(effect); + _imageDepthItem->setGraphicsEffect(effect2); } else { - _image->setGraphicsEffect(0); - _imageDepth->setGraphicsEffect(0); + _imageItem->setGraphicsEffect(0); + _imageDepthItem->setGraphicsEffect(0); } } - else if(_image) + else if(_imageItem) { - _image->setGraphicsEffect(0); + _imageItem->setGraphicsEffect(0); } - else if(_imageDepth) + else if(_imageDepthItem) { - _imageDepth->setGraphicsEffect(0); + _imageDepthItem->setGraphicsEffect(0); } } -void ImageView::updateZoom() -{ - qreal scaleRatio = 1; - if(this->scene()) - { - scaleRatio = this->geometry().width()/this->sceneRect().width(); - } - _minZoom = log(scaleRatio)/log(2.0)*50+250; -} - -void ImageView::wheelEvent(QWheelEvent * e) -{ - if(e->delta() > 0) - { - _zoom += 20; - this->setDragMode(QGraphicsView::ScrollHandDrag); - if(_zoom>=500) - { - _zoom = 500; - } - } - else - { - _zoom -= 20; - if(_zoom<=_minZoom) - { - this->setDragMode(QGraphicsView::NoDrag); - _zoom = _minZoom; - this->fitInView(this->sceneRect(), Qt::KeepAspectRatio); - return; - } - } - - qreal scale = qPow(qreal(2), (_zoom - 250) / qreal(50)); - QMatrix matrix; - matrix.scale(scale, scale); - this->setMatrix(matrix); -} - void ImageView::setFeatures(const std::multimap & refWords, const QColor & color) { qDeleteAll(_features); _features.clear(); - rtabmap::KeypointItem * item = 0; - for(std::multimap::const_iterator i = refWords.begin(); i != refWords.end(); ++i ) + for(std::multimap::const_iterator iter = refWords.begin(); iter != refWords.end(); ++iter ) { - const cv::KeyPoint & r = (*i).second; - int id = (*i).first; - QString info = QString( "WordRef = %1\n" - "Laplacian = %2\n" - "Dir = %3\n" - "Hessian = %4\n" - "X = %5\n" - "Y = %6\n" - "Size = %7").arg(id).arg(1).arg(r.angle).arg(r.response).arg(r.pt.x).arg(r.pt.y).arg(r.size); - float radius = r.size/2.0f; - item = new rtabmap::KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, color); + addFeature(iter->first, iter->second, color); + } - scene()->addItem(item); - _features.insert(id, item); - item->setVisible(_showFeatures->isChecked()); - item->setZValue(1); + if(!_graphicsView->isVisible()) + { + this->update(); } } @@ -334,60 +548,97 @@ void ImageView::setFeatures(const std::vector & features, const QC qDeleteAll(_features); _features.clear(); - rtabmap::KeypointItem * item = 0; for(unsigned int i = 0; i< features.size(); ++i ) { - const cv::KeyPoint & r = features[i]; - int id = i; - QString info = QString( "WordRef = %1\n" - "Laplacian = %2\n" - "Dir = %3\n" - "Hessian = %4\n" - "X = %5\n" - "Y = %6\n" - "Size = %7").arg(id).arg(1).arg(r.angle).arg(r.response).arg(r.pt.x).arg(r.pt.y).arg(r.size); - float radius = (r.size==0?3:r.size)/2.0f; - item = new rtabmap::KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, color); + addFeature(i, features[i], color); + } - scene()->addItem(item); - _features.insert(id, item); - item->setVisible(_showFeatures->isChecked()); - item->setZValue(1); + if(!_graphicsView->isVisible()) + { + this->update(); + } +} + +void ImageView::addFeature(int id, const cv::KeyPoint & kpt, QColor color) +{ + color.setAlpha(this->getAlpha()); + rtabmap::KeypointItem * item = new rtabmap::KeypointItem(id, kpt, color); + _features.insert(id, item); + item->setVisible(isFeaturesShown()); + item->setZValue(1); + + if(_graphicsView->isVisible()) + { + _graphicsView->scene()->addItem(item); + } +} + +void ImageView::addLine(float x1, float y1, float x2, float y2, QColor color) +{ + color.setAlpha(this->getAlpha()); + QGraphicsLineItem * item = new QGraphicsLineItem(x1, y1, x2, y2); + item->setPen(QPen(color)); + _lines.push_back(item); + item->setVisible(isLinesShown()); + item->setZValue(1); + + if(_graphicsView->isVisible()) + { + _graphicsView->scene()->addItem(item); } } void ImageView::setImage(const QImage & image) { - if(_image) + _image = QPixmap::fromImage(image); + if(_graphicsView->isVisible()) { - _image->setPixmap(QPixmap::fromImage(image)); + if(_imageItem) + { + _imageItem->setPixmap(_image); + } + else + { + _imageItem = _graphicsView->scene()->addPixmap(_image); + _imageItem->setVisible(_showImage->isChecked()); + _showImage->setEnabled(true); + this->updateOpacity(); + } } else { - _image = scene()->addPixmap(QPixmap::fromImage(image)); - _image->setVisible(_showImage->isChecked()); - _showImage->setEnabled(true); - this->updateOpacity(); + this->setSceneRect(image.rect()); + this->update(); } } void ImageView::setImageDepth(const QImage & imageDepth) { - if(_imageDepth) + _imageDepth = QPixmap::fromImage(imageDepth); + if(_graphicsView->isVisible()) { - _imageDepth->setPixmap(QPixmap::fromImage(imageDepth)); + if(_imageDepthItem) + { + _imageDepthItem->setPixmap(_imageDepth); + } + else + { + _imageDepthItem = _graphicsView->scene()->addPixmap(_imageDepth); + _imageDepthItem->setVisible(_showImageDepth->isChecked()); + _showImageDepth->setEnabled(true); + this->updateOpacity(); + } } else { - _imageDepth = scene()->addPixmap(QPixmap::fromImage(imageDepth)); - _imageDepth->setVisible(_showImageDepth->isChecked()); - _showImageDepth->setEnabled(true); - this->updateOpacity(); + this->setSceneRect(imageDepth.rect()); + this->update(); } } -void ImageView::setFeatureColor(int id, const QColor & color) +void ImageView::setFeatureColor(int id, QColor color) { + color.setAlpha(getAlpha()); QList items = _features.values(id); if(items.size()) { @@ -400,14 +651,24 @@ void ImageView::setFeatureColor(int id, const QColor & color) { UWARN("Not found feature %d", id); } + + if(!_graphicsView->isVisible()) + { + this->update(); + } } -void ImageView::setFeaturesColor(const QColor & color) +void ImageView::setFeaturesColor(QColor color) { + color.setAlpha(getAlpha()); for(QMultiMap::iterator iter=_features.begin(); iter!=_features.end(); ++iter) { - iter.value()->setPen(QPen(color)); - iter.value()->setBrush(QBrush(color)); + iter.value()->setColor(color); + } + + if(!_graphicsView->isVisible()) + { + this->update(); } } @@ -422,21 +683,47 @@ void ImageView::setAlpha(int alpha) iter.value()->setPen(QPen(c)); iter.value()->setBrush(QBrush(c)); } + + for(QList::iterator iter=_lines.begin(); iter!=_lines.end(); ++iter) + { + QColor c = (*iter)->pen().color(); + c.setAlpha(_alpha); + (*iter)->setPen(QPen(c)); + } + + if(!_graphicsView->isVisible()) + { + this->update(); + } +} + +void ImageView::setSceneRect(const QRectF & rect) +{ + _graphicsView->scene()->setSceneRect(rect); + + if(_graphicsViewScaled->isChecked()) + { + _graphicsView->fitInView(_graphicsView->sceneRect(), Qt::KeepAspectRatio); + } + else + { + _graphicsView->resetTransform(); + } + + if(!_graphicsView->isVisible()) + { + this->update(); + } } void ImageView::clearLines() { - if(this->scene()) + qDeleteAll(_lines); + _lines.clear(); + + if(!_graphicsView->isVisible()) { - QList items = this->scene()->items(); - for(int i=0; i(items[i]); - if(line) - { - delete line; - } - } + this->update(); } } @@ -445,22 +732,34 @@ void ImageView::clear() qDeleteAll(_features); _features.clear(); - if(_image) + qDeleteAll(_lines); + _lines.clear(); + + if(_imageItem) { - scene()->removeItem(_image); - delete _image; - _image = 0; + _graphicsView->scene()->removeItem(_imageItem); + delete _imageItem; + _imageItem = 0; _showImage->setEnabled(false); } - if(_imageDepth) + if(_imageDepthItem) { - scene()->removeItem(_imageDepth); - delete _imageDepth; - _imageDepth = 0; + _graphicsView->scene()->removeItem(_imageDepthItem); + delete _imageDepthItem; + _imageDepthItem = 0; _showImageDepth->setEnabled(false); } - scene()->clear(); + + if(!_graphicsView->isVisible()) + { + this->update(); + } +} + +QSize ImageView::sizeHint() const +{ + return _graphicsView->sizeHint(); } } diff --git a/guilib/src/KeypointItem.cpp b/guilib/src/KeypointItem.cpp index 42e616f1..3f5482cb 100644 --- a/guilib/src/KeypointItem.cpp +++ b/guilib/src/KeypointItem.cpp @@ -34,9 +34,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace rtabmap { -KeypointItem::KeypointItem(qreal x, qreal y, int r, const QString & info, const QColor & color, QGraphicsItem * parent) : - QGraphicsEllipseItem(x, y, r, r, parent), - _info(info), +KeypointItem::KeypointItem(int id, const cv::KeyPoint & kpt, const QColor & color, QGraphicsItem * parent) : + QGraphicsEllipseItem(kpt.pt.x-(kpt.size==0?3.0f:kpt.size)/2.0f, kpt.pt.y-(kpt.size==0?3.0f:kpt.size)/2.0f, kpt.size==0?3.0f:kpt.size, kpt.size==0?3.0f:kpt.size, parent), + _id(id), + _kpt(kpt), _placeHolder(0) { this->setColor(color); @@ -68,7 +69,12 @@ void KeypointItem::showDescription() _placeHolder->setBrush(QBrush(QColor ( 0, 0, 0, 170 ))); // Black transparent background QGraphicsTextItem * text = new QGraphicsTextItem(_placeHolder); text->setDefaultTextColor(this->pen().color().rgb()); - text->setPlainText(_info); + text->setPlainText(QString( "Id = %1\n" + "Dir = %3\n" + "Hessian = %4\n" + "X = %5\n" + "Y = %6\n" + "Size = %7").arg(_id).arg(_kpt.angle).arg(_kpt.response).arg(_kpt.pt.x).arg(_kpt.pt.y).arg(_kpt.size)); _placeHolder->setRect(text->boundingRect()); } diff --git a/guilib/src/MainWindow.cpp b/guilib/src/MainWindow.cpp index ca841574..b94fee53 100644 --- a/guilib/src/MainWindow.cpp +++ b/guilib/src/MainWindow.cpp @@ -209,9 +209,9 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) : _logEventTime->start(); //Graphics scenes - _ui->imageView_source->setBackgroundBrush(QBrush(Qt::black)); - _ui->imageView_loopClosure->setBackgroundBrush(QBrush(Qt::black)); - _ui->imageView_odometry->setBackgroundBrush(QBrush(Qt::black)); + _ui->imageView_source->setBackgroundColor(Qt::black); + _ui->imageView_loopClosure->setBackgroundColor(Qt::black); + _ui->imageView_odometry->setBackgroundColor(Qt::black); _ui->imageView_odometry->setAlpha(200); _preferencesDialog->loadWidgetState(_ui->imageView_source); _preferencesDialog->loadWidgetState(_ui->imageView_loopClosure); @@ -666,13 +666,13 @@ void MainWindow::processOdometry(const rtabmap::SensorData & data, const rtabmap Transform pose = data.pose(); bool lost = false; bool lostStateChanged = false; - _ui->imageView_odometry->resetTransform(); + if(pose.isNull()) { UDEBUG("odom lost"); // use last pose lostStateChanged = _ui->widget_cloudViewer->getBackgroundColor() != Qt::darkRed; _ui->widget_cloudViewer->setBackgroundColor(Qt::darkRed); - _ui->imageView_odometry->setBackgroundBrush(QBrush(Qt::darkRed)); + _ui->imageView_odometry->setBackgroundColor(Qt::darkRed); pose = _lastOdomPose; lost = true; @@ -684,15 +684,16 @@ void MainWindow::processOdometry(const rtabmap::SensorData & data, const rtabmap UDEBUG("odom warn, quality(inliers)=%d thr=%d", info.inliers, _preferencesDialog->getOdomQualityWarnThr()); lostStateChanged = _ui->widget_cloudViewer->getBackgroundColor() == Qt::darkRed; _ui->widget_cloudViewer->setBackgroundColor(Qt::darkYellow); - _ui->imageView_odometry->setBackgroundBrush(QBrush(Qt::darkYellow)); + _ui->imageView_odometry->setBackgroundColor(Qt::darkYellow); } else { UDEBUG("odom ok"); lostStateChanged = _ui->widget_cloudViewer->getBackgroundColor() == Qt::darkRed; _ui->widget_cloudViewer->setBackgroundColor(_ui->widget_cloudViewer->getDefaultBackgroundColor()); - _ui->imageView_odometry->setBackgroundBrush(QBrush(Qt::black)); + _ui->imageView_odometry->setBackgroundColor(Qt::black); } + if(info.inliers >= 0) { _ui->statsToolBox->updateStat("Odometry/Inliers/", (float)data.id(), (float)info.inliers); @@ -810,16 +811,16 @@ void MainWindow::processOdometry(const rtabmap::SensorData & data, const rtabmap { if(_ui->imageView_odometry->isFeaturesShown()) { - int alpha = _ui->imageView_odometry->getAlpha(); if(info.type == 0) { - _ui->imageView_odometry->setFeatures(info.words, QColor(255,255,0, alpha)); + _ui->imageView_odometry->setFeatures(info.words, Qt::yellow); } else if(info.type == 1) { - _ui->imageView_odometry->setFeatures(info.refCorners, QColor(255,0,0, alpha)); + _ui->imageView_odometry->setFeatures(info.refCorners, Qt::red); } } + _ui->imageView_odometry->clearLines(); if(lost) { @@ -852,14 +853,13 @@ void MainWindow::processOdometry(const rtabmap::SensorData & data, const rtabmap { if(_ui->imageView_odometry->isFeaturesShown()) { - int alpha = _ui->imageView_odometry->getAlpha(); for(unsigned int i=0; iimageView_odometry->setFeatureColor(info.wordMatches[i], QColor(255,0,0, alpha)); // outliers + _ui->imageView_odometry->setFeatureColor(info.wordMatches[i], Qt::red); // outliers } for(unsigned int i=0; iimageView_odometry->setFeatureColor(info.wordInliers[i], QColor(0,255,0, alpha)); // inliers + _ui->imageView_odometry->setFeatureColor(info.wordInliers[i], Qt::green); // inliers } } } @@ -868,33 +868,32 @@ void MainWindow::processOdometry(const rtabmap::SensorData & data, const rtabmap if(_ui->imageView_odometry->isFeaturesShown() || _ui->imageView_odometry->isLinesShown()) { //draw lines - int alpha = _ui->imageView_odometry->getAlpha(); UASSERT(info.refCorners.size() == info.newCorners.size()); for(unsigned int i=0; iimageView_odometry->isFeaturesShown()) { - _ui->imageView_odometry->setFeatureColor(info.cornerInliers[i], QColor(0,255,0, alpha)); // inliers + _ui->imageView_odometry->setFeatureColor(info.cornerInliers[i], Qt::green); // inliers } if(_ui->imageView_odometry->isLinesShown()) { - QGraphicsLineItem * item = _ui->imageView_odometry->scene()->addLine( + _ui->imageView_odometry->addLine( info.refCorners[info.cornerInliers[i]].pt.x, info.refCorners[info.cornerInliers[i]].pt.y, info.newCorners[info.cornerInliers[i]].pt.x, info.newCorners[info.cornerInliers[i]].pt.y, - QPen(QColor(0, 0, 255, alpha))); - item->setVisible(_ui->imageView_odometry->isLinesShown()); - item->setZValue(1); + Qt::blue); } } + _ui->imageView_odometry->update(); } } - } - _ui->imageView_odometry->resetZoom(); - _ui->imageView_odometry->setSceneRect(_ui->imageView_odometry->scene()->itemsBoundingRect()); - _ui->imageView_odometry->fitInView(_ui->imageView_odometry->sceneRect(), Qt::KeepAspectRatio); + } + if(!data.image().empty()) + { + _ui->imageView_odometry->setSceneRect(QRectF(0,0,(float)data.image().cols, (float)data.image().rows)); + } } if(_ui->actionAuto_screen_capture->isChecked() && _autoScreenCaptureOdomSync) @@ -937,10 +936,8 @@ void MainWindow::processStats(const rtabmap::Statistics & stat) // Loop closure info _ui->imageView_source->clear(); _ui->imageView_loopClosure->clear(); - _ui->imageView_source->resetTransform(); - _ui->imageView_loopClosure->resetTransform(); - _ui->imageView_source->setBackgroundBrush(QBrush(Qt::black)); - _ui->imageView_loopClosure->setBackgroundBrush(QBrush(Qt::black)); + _ui->imageView_source->setBackgroundColor(Qt::black); + _ui->imageView_loopClosure->setBackgroundColor(Qt::black); // update cache Signature signature = stat.getSignature(); @@ -955,15 +952,15 @@ void MainWindow::processStats(const rtabmap::Statistics & stat) if(rehearsed > 0) { - _ui->imageView_source->setBackgroundBrush(QBrush(Qt::blue)); + _ui->imageView_source->setBackgroundColor(Qt::blue); } else if(localTimeClosures > 0) { - _ui->imageView_source->setBackgroundBrush(QBrush(Qt::darkCyan)); + _ui->imageView_source->setBackgroundColor(Qt::darkCyan); } else if(scanMatchingSuccess) { - _ui->imageView_source->setBackgroundBrush(QBrush(Qt::gray)); + _ui->imageView_source->setBackgroundColor(Qt::gray); } UDEBUG("time= %d ms", time.restart()); @@ -978,7 +975,7 @@ void MainWindow::processStats(const rtabmap::Statistics & stat) bool show = true; if(stat.loopClosureId() > 0) { - _ui->imageView_loopClosure->setBackgroundBrush(QBrush(Qt::green)); + _ui->imageView_loopClosure->setBackgroundColor(Qt::green); _ui->label_stats_loopClosuresDetected->setText(QString::number(_ui->label_stats_loopClosuresDetected->text().toInt() + 1)); if(highestHypothesisIsSaved) { @@ -989,7 +986,7 @@ void MainWindow::processStats(const rtabmap::Statistics & stat) } else if(stat.localLoopClosureId()) { - _ui->imageView_loopClosure->setBackgroundBrush(QBrush(Qt::yellow)); + _ui->imageView_loopClosure->setBackgroundColor(Qt::yellow); _ui->label_matchId->setText(QString("Local match = %1 [%2]").arg(stat.localLoopClosureId()).arg(loopMapId)); matchId = stat.localLoopClosureId(); } @@ -998,7 +995,7 @@ void MainWindow::processStats(const rtabmap::Statistics & stat) show = _preferencesDialog->imageRejectedShown() || _preferencesDialog->imageHighestHypShown(); if(show) { - _ui->imageView_loopClosure->setBackgroundBrush(QBrush(Qt::red)); + _ui->imageView_loopClosure->setBackgroundColor(Qt::red); _ui->label_stats_loopClosuresRejected->setText(QString::number(_ui->label_stats_loopClosuresRejected->text().toInt() + 1)); _ui->label_matchId->setText(QString("Loop hypothesis %1 rejected!").arg(highestHypothesisId)); } @@ -1062,24 +1059,16 @@ void MainWindow::processStats(const rtabmap::Statistics & stat) { _ui->imageView_loopClosure->setImageDepth(lcDepth); } - QRectF sceneRect = img.rect(); - _ui->imageView_source->setSceneRect(sceneRect); - _ui->imageView_loopClosure->setSceneRect(sceneRect); + if(img.rect().isValid()) + { + QRectF sceneRect = img.rect(); + _ui->imageView_source->setSceneRect(sceneRect); + _ui->imageView_loopClosure->setSceneRect(sceneRect); + } } UDEBUG("time= %d ms", time.restart()); - // We use the reference image to resize the 2 views - _ui->imageView_source->resetZoom(); - _ui->imageView_loopClosure->resetZoom(); - if(signature.getImageRaw().empty()) - { - _ui->imageView_source->setSceneRect(_ui->imageView_source->scene()->itemsBoundingRect()); - _ui->imageView_loopClosure->setSceneRect(_ui->imageView_source->scene()->itemsBoundingRect()); - } - _ui->imageView_source->fitInView(_ui->imageView_source->sceneRect(), Qt::KeepAspectRatio); - _ui->imageView_loopClosure->fitInView(_ui->imageView_source->sceneRect(), Qt::KeepAspectRatio); - // do it after scaling this->drawKeypoints(signature.getWords(), loopSignature.getWords()); @@ -2059,101 +2048,78 @@ void MainWindow::drawKeypoints(const std::multimap & refWords timer.start(); KeypointItem * item = 0; - int alphaA = _ui->imageView_source->getAlpha(); ULOGGER_DEBUG("refWords.size() = %d", refWords.size()); - QMap addedKeypoints; - for(std::multimap::const_iterator i = refWords.begin(); i != refWords.end(); ++i ) + for(std::multimap::const_iterator iter = refWords.begin(); iter != refWords.end(); ++iter ) { - const cv::KeyPoint & r = (*i).second; - int id = (*i).first; - - QString info = QString( "WordRef = %1\n" - "Laplacian = %2\n" - "Dir = %3\n" - "Hessian = %4\n" - "X = %5\n" - "Y = %6\n" - "Size = %7").arg(id).arg(1).arg(r.angle).arg(r.response).arg(r.pt.x).arg(r.pt.y).arg(r.size); - float radius = r.size/2.0f; + int id = iter->first; + QColor color; if(uContains(loopWords, id)) { // PINK = FOUND IN LOOP SIGNATURE - item = new KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, QColor(255, 0, 255, alphaA)); + color = Qt::magenta; } else if(_lastIds.contains(id)) { // BLUE = FOUND IN LAST SIGNATURE - item = new KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, QColor(0, 0, 255, alphaA)); + color = Qt::blue; } else if(id<=_lastId) { // RED = ALREADY EXISTS - item = new KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, QColor(255, 0, 0, alphaA)); + color = Qt::red; } else if(refWords.count(id) > 1) { // YELLOW = NEW and multiple times - item = new KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, QColor(255, 255, 0, alphaA)); + color = Qt::yellow; } else { // GREEN = NEW - item = new KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, QColor(0, 255, 0, alphaA)); + color = Qt::green; } - item->setVisible(this->_ui->imageView_source->isFeaturesShown()); - this->_ui->imageView_source->scene()->addItem(item); - item->setZValue(1); - addedKeypoints.insert(id, item); + _ui->imageView_source->addFeature(iter->first, iter->second, color); } ULOGGER_DEBUG("source time = %f s", timer.ticks()); timer.start(); item = 0; - int alphaB = _ui->imageView_loopClosure->getAlpha(); ULOGGER_DEBUG("loopWords.size() = %d", loopWords.size()); - QList > uniqueCorrespondences; - for(std::multimap::const_iterator i = loopWords.begin(); i != loopWords.end(); ++i ) + QList > uniqueCorrespondences; + for(std::multimap::const_iterator iter = loopWords.begin(); iter != loopWords.end(); ++iter ) { - const cv::KeyPoint & r = (*i).second; - int id = (*i).first; - - QString info = QString( "WordRef = %1\n" - "Laplacian = %2\n" - "Dir = %3\n" - "Hessian = %4\n" - "X = %5\n" - "Y = %6\n" - "Size = %7").arg(id).arg(1).arg(r.angle).arg(r.response).arg(r.pt.x).arg(r.pt.y).arg(r.size); - float radius = r.size/2.0f; + int id = iter->first; + QColor color; if(uContains(refWords, id)) { // PINK = FOUND IN LOOP SIGNATURE - item = new KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, QColor(255, 0, 255, alphaB)); + color = Qt::magenta; //To draw lines... get only unique correspondences if(uValues(refWords, id).size() == 1 && uValues(loopWords, id).size() == 1) { - uniqueCorrespondences.push_back(QPair(addedKeypoints.value(id), item)); + const cv::KeyPoint & a = refWords.find(id)->second; + const cv::KeyPoint & b = iter->second; + uniqueCorrespondences.push_back(QPair(a.pt, b.pt)); } } else if(id<=_lastId) { // RED = ALREADY EXISTS - item = new KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, QColor(255, 0, 0, alphaB)); + color = Qt::red; } else if(refWords.count(id) > 1) { // YELLOW = NEW and multiple times - item = new KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, QColor(255, 255, 0, alphaB)); + color = Qt::yellow; } else { // GREEN = NEW - item = new KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, QColor(0, 255, 0, alphaB)); + color = Qt::green; } - item->setVisible(this->_ui->imageView_loopClosure->isFeaturesShown()); - this->_ui->imageView_loopClosure->scene()->addItem(item); - item->setZValue(1); + _ui->imageView_loopClosure->addFeature(iter->first, iter->second, color); } + ULOGGER_DEBUG("loop closure time = %f s", timer.ticks()); if(refWords.size()>0) @@ -2166,39 +2132,36 @@ void MainWindow::drawKeypoints(const std::multimap & refWords } // Draw lines between corresponding features... - float scaleX = _ui->imageView_source->transform().m11(); - float scaleY = _ui->imageView_source->transform().m22(); - UDEBUG("scaleX=%f scaleY=%f", scaleX, scaleY); - int deltaX = _ui->imageView_source->width()/scaleX; - int deltaY = 0; + float scale = _ui->imageView_source->viewScale(); + UDEBUG("scale=%f", scale); + float deltaX = _ui->imageView_source->width()/scale; + float deltaY = 0; if(_preferencesDialog->isVerticalLayoutUsed()) { deltaX = 0; - deltaY = _ui->imageView_source->height()/scaleY; - deltaY += _ui->label_matchId->height()/scaleY; + deltaY = _ui->imageView_source->height()/scale; + deltaY += _ui->label_matchId->height()/scale; } - for(QList >::iterator iter = uniqueCorrespondences.begin(); + for(QList >::iterator iter = uniqueCorrespondences.begin(); iter!=uniqueCorrespondences.end(); ++iter) { - QGraphicsLineItem * item = _ui->imageView_source->scene()->addLine( - iter->first->rect().x()+iter->first->rect().width()/2, - iter->first->rect().y()+iter->first->rect().height()/2, - iter->second->rect().x()+iter->second->rect().width()/2+deltaX, - iter->second->rect().y()+iter->second->rect().height()/2+deltaY, - QPen(QColor(0, 255, 255, alphaA))); - item->setVisible(_ui->imageView_source->isLinesShown()); - item->setZValue(1); + _ui->imageView_source->addLine( + iter->first.x, + iter->first.y, + iter->second.x+deltaX, + iter->second.y+deltaY, + Qt::cyan); - item = _ui->imageView_loopClosure->scene()->addLine( - iter->first->rect().x()+iter->first->rect().width()/2-deltaX, - iter->first->rect().y()+iter->first->rect().height()/2-deltaY, - iter->second->rect().x()+iter->second->rect().width()/2, - iter->second->rect().y()+iter->second->rect().height()/2, - QPen(QColor(0, 255, 255, alphaB))); - item->setVisible(_ui->imageView_loopClosure->isLinesShown()); - item->setZValue(1); + _ui->imageView_loopClosure->addLine( + iter->first.x-deltaX, + iter->first.y-deltaY, + iter->second.x, + iter->second.y, + Qt::cyan); } + _ui->imageView_source->update(); + _ui->imageView_loopClosure->update(); } void MainWindow::showEvent(QShowEvent* anEvent) @@ -2221,12 +2184,6 @@ void MainWindow::moveEvent(QMoveEvent* anEvent) void MainWindow::resizeEvent(QResizeEvent* anEvent) { - _ui->imageView_source->fitInView(_ui->imageView_source->sceneRect(), Qt::KeepAspectRatio); - _ui->imageView_loopClosure->fitInView(_ui->imageView_source->sceneRect(), Qt::KeepAspectRatio); - _ui->imageView_odometry->fitInView(_ui->imageView_odometry->sceneRect(), Qt::KeepAspectRatio); - _ui->imageView_source->resetZoom(); - _ui->imageView_loopClosure->resetZoom(); - _ui->imageView_odometry->resetZoom(); if(this->isVisible()) { this->configGUIModified(); @@ -2485,7 +2442,7 @@ void MainWindow::editDatabase() if(!path.isEmpty()) { DatabaseViewer * viewer = new DatabaseViewer(this); - viewer->setWindowModality(Qt::WindowModal); + viewer->setWindowFlags(Qt::Dialog); if(viewer->openDatabase(path)) { if(viewer->isSavedMaximized()) @@ -3774,12 +3731,9 @@ void MainWindow::clearTheCache() _ui->imageView_source->clear(); _ui->imageView_loopClosure->clear(); _ui->imageView_odometry->clear(); - _ui->imageView_source->resetTransform(); - _ui->imageView_loopClosure->resetTransform(); - _ui->imageView_odometry->resetTransform(); - _ui->imageView_source->setBackgroundBrush(QBrush(Qt::black)); - _ui->imageView_loopClosure->setBackgroundBrush(QBrush(Qt::black)); - _ui->imageView_odometry->setBackgroundBrush(QBrush(Qt::black)); + _ui->imageView_source->setBackgroundColor(Qt::black); + _ui->imageView_loopClosure->setBackgroundColor(Qt::black); + _ui->imageView_odometry->setBackgroundColor(Qt::black); } void MainWindow::updateElapsedTime() diff --git a/guilib/src/PreferencesDialog.cpp b/guilib/src/PreferencesDialog.cpp index 7487cb94..4fc7f802 100644 --- a/guilib/src/PreferencesDialog.cpp +++ b/guilib/src/PreferencesDialog.cpp @@ -1261,6 +1261,27 @@ bool PreferencesDialog::readCoreSettings(const QString & filePath) QString value = settings.value(key, "").toString(); if(!value.isEmpty()) { + if(key.toStdString().compare(Parameters::kRtabmapWorkingDirectory()) == 0) + { + // The directory should exist if not the default one + if(!QDir(value).exists() && value.compare(Parameters::defaultRtabmapWorkingDirectory().c_str()) != 0) + { + if(QDir(this->getWorkingDirectory().toStdString().c_str()).exists()) + { + UWARN("Reading config: Not existing working directory \"%s\". Keeping old one (\"%s\").", + value.toStdString().c_str(), + this->getWorkingDirectory().toStdString().c_str()); + value = this->getWorkingDirectory(); + } + else + { + UWARN("Reading config: Not existing working directory \"%s\". Using default one (\"%s\").", + value.toStdString().c_str(), + (*iter).second.c_str()); + value = (*iter).second.c_str(); + } + } + } this->setParameter(key.toStdString(), value.toStdString()); } else diff --git a/guilib/src/ui/DatabaseViewer.ui b/guilib/src/ui/DatabaseViewer.ui index c58f5628..6a06e759 100644 --- a/guilib/src/ui/DatabaseViewer.ui +++ b/guilib/src/ui/DatabaseViewer.ui @@ -7,7 +7,7 @@ 0 0 1182 - 804 + 821 @@ -16,7 +16,7 @@ - + 0 @@ -26,7 +26,7 @@ 0 - + @@ -41,8 +41,8 @@ 0 0 - 136 - 127 + 153 + 136 @@ -122,7 +122,16 @@ - + + 12 + + + 12 + + + 12 + + 12 @@ -181,7 +190,7 @@ 0 - + @@ -196,8 +205,8 @@ 0 0 - 137 - 127 + 152 + 136 @@ -277,7 +286,16 @@ - + + 12 + + + 12 + + + 12 + + 12 @@ -340,7 +358,7 @@ 0 0 1182 - 25 + 22 @@ -1124,9 +1142,9 @@ 4 - + - + @@ -1142,7 +1160,7 @@ 4 - + @@ -1679,7 +1697,7 @@ rtabmap::ImageView - QGraphicsView + QWidget
rtabmap/gui/ImageView.h
diff --git a/guilib/src/ui/mainWindow.ui b/guilib/src/ui/mainWindow.ui index 88b3a4bf..1c151fa2 100644 --- a/guilib/src/ui/mainWindow.ui +++ b/guilib/src/ui/mainWindow.ui @@ -45,8 +45,6 @@ - -
@@ -194,8 +192,11 @@ Tools - + + + + @@ -735,7 +736,7 @@ 1 - + 0 @@ -752,7 +753,7 @@ 0 - + 0 @@ -773,19 +774,12 @@
- - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - +
- + 0 @@ -806,14 +800,7 @@ - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - +
@@ -845,7 +832,7 @@ 0 - + @@ -1239,10 +1226,6 @@ - - - :/images/document-properties.png:/images/document-properties.png - Edit database... @@ -1275,7 +1258,7 @@ rtabmap::ImageView - QGraphicsView + QWidget
../include/rtabmap/gui/ImageView.h
diff --git a/tools/DataRecorder/main.cpp b/tools/DataRecorder/main.cpp index 4eb83b2d..4e15c74c 100644 --- a/tools/DataRecorder/main.cpp +++ b/tools/DataRecorder/main.cpp @@ -204,7 +204,7 @@ int main (int argc, char * argv[]) recorder.registerToEventsManager(); if(show) { - recorder.setWindowTitle("Cloud viewer"); + recorder.setWindowTitle("Data recorder"); recorder.setMinimumWidth(500); recorder.setMinimumHeight(300); recorder.showNormal(); diff --git a/tools/EpipolarGeometry/main.cpp b/tools/EpipolarGeometry/main.cpp index c783d8b5..91ddd401 100644 --- a/tools/EpipolarGeometry/main.cpp +++ b/tools/EpipolarGeometry/main.cpp @@ -641,22 +641,13 @@ public: this->layout()->setSpacing(0); this->layout()->setContentsMargins(0,0,0,0); this->layout()->addWidget(view1_); - view1_->setSceneRect(0,0,(float)image1.cols, (float)image1.rows); + view1_->setSceneRect(QRectF(0,0,(float)image1.cols, (float)image1.rows)); view1_->setLinesShown(true); view1_->setFeaturesShown(false); + view1_->setImageDepthShown(true); - QGraphicsPixmapItem * item1 = view1_->scene()->addPixmap(QPixmap::fromImage(uCvMat2QImage(image1))); - QGraphicsPixmapItem * item2 = view1_->scene()->addPixmap(QPixmap::fromImage(uCvMat2QImage(image2))); - - QGraphicsOpacityEffect * effect1 = new QGraphicsOpacityEffect(); - QGraphicsOpacityEffect * effect2 = new QGraphicsOpacityEffect(); - effect1->setOpacity(0.5); - effect2->setOpacity(0.5); - item1->setGraphicsEffect(effect1); - item2->setGraphicsEffect(effect2); - - item1->setVisible(view1_->isImageShown()); - item2->setVisible(view1_->isImageShown()); + view1_->setImage(uCvMat2QImage(image1)); + view1_->setImageDepth(uCvMat2QImage(image2)); drawKeypoints(words1, words2, status); } @@ -665,59 +656,41 @@ protected: { resizeEvent(0); } - virtual void resizeEvent(QResizeEvent* event) - { - view1_->fitInView(view1_->sceneRect(), Qt::KeepAspectRatio); - view1_->resetZoom(); - } private: void drawKeypoints(const std::multimap & refWords, const std::multimap & loopWords, const std::vector & status) { UTimer timer; timer.start(); - KeypointItem * item = 0; - int alpha = 10*255/100; QList > uniqueCorrespondences; QList inliers; int j=0; for(std::multimap::const_iterator i = refWords.begin(); i != refWords.end(); ++i ) { - const cv::KeyPoint & r = (*i).second; int id = (*i).first; - - QString info = QString( "WordRef = %1\n" - "Laplacian = %2\n" - "Dir = %3\n" - "Hessian = %4\n" - "X = %5\n" - "Y = %6\n" - "Size = %7").arg(id).arg(1).arg(r.angle).arg(r.response).arg(r.pt.x).arg(r.pt.y).arg(r.size); - float radius = r.size*1.2/9.*2; + QColor color; if(uContains(loopWords, id)) { // PINK = FOUND IN LOOP SIGNATURE - item = new KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, QColor(255, 0, 255, alpha)); + color = Qt::magenta; //To draw lines... get only unique correspondences if(uValues(refWords, id).size() == 1 && uValues(loopWords, id).size() == 1) { - uniqueCorrespondences.push_back(QPair(r.pt, uValues(loopWords, id).begin()->pt)); + uniqueCorrespondences.push_back(QPair(i->second.pt, uValues(loopWords, id).begin()->pt)); inliers.push_back(status[j++]); } } else if(refWords.count(id) > 1) { // YELLOW = NEW and multiple times - item = new KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, QColor(255, 255, 0, alpha)); + color = Qt::yellow; } else { // GREEN = NEW - item = new KeypointItem(r.pt.x-radius, r.pt.y-radius, radius*2, info, QColor(0, 255, 0, alpha)); + color = Qt::green; } - item->setVisible(view1_->isFeaturesShown()); - view1_->scene()->addItem(item); - item->setZValue(1); + view1_->addFeature(id, i->second, color); } ULOGGER_DEBUG("source time = %f s", timer.ticks()); @@ -728,16 +701,15 @@ private: iter!=uniqueCorrespondences.end(); ++iter) { - QGraphicsLineItem * item = view1_->scene()->addLine( + view1_->addLine( iter->first.x, iter->first.y, iter->second.x, iter->second.y, - *jter?QPen(Qt::cyan):QPen(Qt::red)); - item->setVisible(view1_->isLinesShown()); - item->setZValue(1); + *jter?Qt::cyan:Qt::red); ++jter; } + view1_->update(); } private: