00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "rtabmap/gui/ImageView.h"
00029
00030 #include <QtGui/QWheelEvent>
00031 #include <QtCore/qmath.h>
00032 #include <QMenu>
00033 #include <QFileDialog>
00034 #include <QtCore/QDir>
00035 #include <QAction>
00036 #include <QGraphicsEffect>
00037 #include <QInputDialog>
00038 #include <QVBoxLayout>
00039 #include "rtabmap/utilite/ULogger.h"
00040 #include "rtabmap/gui/KeypointItem.h"
00041 #include "rtabmap/core/util3d.h"
00042
00043 namespace rtabmap {
00044
00045 ImageView::ImageView(QWidget * parent) :
00046 QWidget(parent),
00047 _savedFileName((QDir::homePath()+ "/") + "picture" + ".png"),
00048 _alpha(50),
00049 _imageItem(0),
00050 _imageDepthItem(0)
00051 {
00052 _graphicsView = new QGraphicsView(this);
00053 _graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
00054 _graphicsView->setScene(new QGraphicsScene(this));
00055 _graphicsView->setVisible(false);
00056
00057 this->setLayout(new QVBoxLayout(this));
00058 this->layout()->addWidget(_graphicsView);
00059 this->layout()->setContentsMargins(0,0,0,0);
00060
00061 _menu = new QMenu(tr(""), this);
00062 _showImage = _menu->addAction(tr("Show image"));
00063 _showImage->setCheckable(true);
00064 _showImage->setChecked(true);
00065 _showImageDepth = _menu->addAction(tr("Show image depth"));
00066 _showImageDepth->setCheckable(true);
00067 _showImageDepth->setChecked(false);
00068 _showFeatures = _menu->addAction(tr("Show features"));
00069 _showFeatures->setCheckable(true);
00070 _showFeatures->setChecked(true);
00071 _showLines = _menu->addAction(tr("Show lines"));
00072 _showLines->setCheckable(true);
00073 _showLines->setChecked(true);
00074 _graphicsViewMode = _menu->addAction(tr("Graphics view"));
00075 _graphicsViewMode->setCheckable(true);
00076 _graphicsViewMode->setChecked(false);
00077 _graphicsViewScaled = _menu->addAction(tr("Scale image"));
00078 _graphicsViewScaled->setCheckable(true);
00079 _graphicsViewScaled->setChecked(true);
00080 _graphicsViewScaled->setEnabled(false);
00081 _setAlpha = _menu->addAction(tr("Set transparency..."));
00082 _saveImage = _menu->addAction(tr("Save picture..."));
00083 _saveImage->setEnabled(false);
00084
00085 connect(_graphicsView->scene(), SIGNAL(sceneRectChanged(const QRectF &)), this, SLOT(sceneRectChanged(const QRectF &)));
00086 }
00087
00088 ImageView::~ImageView() {
00089 clear();
00090 }
00091
00092 void ImageView::saveSettings(QSettings & settings, const QString & group) const
00093 {
00094 if(!group.isEmpty())
00095 {
00096 settings.beginGroup(group);
00097 }
00098 settings.setValue("image_shown", this->isImageShown());
00099 settings.setValue("depth_shown", this->isImageDepthShown());
00100 settings.setValue("features_shown", this->isFeaturesShown());
00101 settings.setValue("lines_shown", this->isLinesShown());
00102 settings.setValue("alpha", this->getAlpha());
00103 settings.setValue("graphics_view", this->isGraphicsViewMode());
00104 settings.setValue("graphics_view_scale", this->isGraphicsViewScaled());
00105 if(!group.isEmpty())
00106 {
00107 settings.endGroup();
00108 }
00109 }
00110
00111 void ImageView::loadSettings(QSettings & settings, const QString & group)
00112 {
00113 if(!group.isEmpty())
00114 {
00115 settings.beginGroup(group);
00116 }
00117 this->setImageShown(settings.value("image_shown", this->isImageShown()).toBool());
00118 this->setImageDepthShown(settings.value("depth_shown", this->isImageDepthShown()).toBool());
00119 this->setFeaturesShown(settings.value("features_shown", this->isFeaturesShown()).toBool());
00120 this->setLinesShown(settings.value("lines_shown", this->isLinesShown()).toBool());
00121 this->setAlpha(settings.value("alpha", this->getAlpha()).toInt());
00122 this->setGraphicsViewMode(settings.value("graphics_view", this->isGraphicsViewMode()).toBool());
00123 this->setGraphicsViewScaled(settings.value("graphics_view_scale", this->isGraphicsViewScaled()).toBool());
00124 if(!group.isEmpty())
00125 {
00126 settings.endGroup();
00127 }
00128 }
00129
00130 bool ImageView::isImageShown() const
00131 {
00132 return _showImage->isChecked();
00133 }
00134
00135 bool ImageView::isImageDepthShown() const
00136 {
00137 return _showImageDepth->isChecked();
00138 }
00139
00140 bool ImageView::isFeaturesShown() const
00141 {
00142 return _showFeatures->isChecked();
00143 }
00144
00145 bool ImageView::isGraphicsViewMode() const
00146 {
00147 return _graphicsViewMode->isChecked();
00148 }
00149
00150 bool ImageView::isGraphicsViewScaled() const
00151 {
00152 return _graphicsViewScaled->isChecked();
00153 }
00154
00155 const QColor & ImageView::getBackgroundColor() const
00156 {
00157 return _graphicsView->backgroundBrush().color();
00158 }
00159
00160
00161 void ImageView::setFeaturesShown(bool shown)
00162 {
00163 _showFeatures->setChecked(shown);
00164 for(QMultiMap<int, KeypointItem*>::iterator iter=_features.begin(); iter!=_features.end(); ++iter)
00165 {
00166 iter.value()->setVisible(_showFeatures->isChecked());
00167 }
00168
00169 if(!_graphicsView->isVisible())
00170 {
00171 this->update();
00172 }
00173 }
00174
00175 void ImageView::setImageShown(bool shown)
00176 {
00177 _showImage->setChecked(shown);
00178 if(_imageItem)
00179 {
00180 _imageItem->setVisible(_showImage->isChecked());
00181 this->updateOpacity();
00182 }
00183
00184 if(!_graphicsView->isVisible())
00185 {
00186 this->update();
00187 }
00188 }
00189
00190 void ImageView::setImageDepthShown(bool shown)
00191 {
00192 _showImageDepth->setChecked(shown);
00193 if(_imageDepthItem)
00194 {
00195 _imageDepthItem->setVisible(_showImageDepth->isChecked());
00196 this->updateOpacity();
00197 }
00198
00199 if(!_graphicsView->isVisible())
00200 {
00201 this->update();
00202 }
00203 }
00204
00205 bool ImageView::isLinesShown() const
00206 {
00207 return _showLines->isChecked();
00208 }
00209
00210 void ImageView::setLinesShown(bool shown)
00211 {
00212 _showLines->setChecked(shown);
00213 for(int i=0; i<_lines.size(); ++i)
00214 {
00215 _lines.at(i)->setVisible(_showLines->isChecked());
00216 }
00217
00218 if(!_graphicsView->isVisible())
00219 {
00220 this->update();
00221 }
00222 }
00223
00224 float ImageView::viewScale() const
00225 {
00226 if(_graphicsView->isVisible())
00227 {
00228 return _graphicsView->transform().m11();
00229 }
00230 else
00231 {
00232 float scale, offsetX, offsetY;
00233 computeScaleOffsets(this->rect(), scale, offsetX, offsetY);
00234 return scale;
00235 }
00236 }
00237
00238 void ImageView::setGraphicsViewMode(bool on)
00239 {
00240 _graphicsViewMode->setChecked(on);
00241 _graphicsView->setVisible(on);
00242 _graphicsViewScaled->setEnabled(on);
00243
00244 if(on)
00245 {
00246 for(QMultiMap<int, KeypointItem*>::iterator iter=_features.begin(); iter!=_features.end(); ++iter)
00247 {
00248 _graphicsView->scene()->addItem(iter.value());
00249 }
00250
00251 for(QList<QGraphicsLineItem*>::iterator iter=_lines.begin(); iter!=_lines.end(); ++iter)
00252 {
00253 _graphicsView->scene()->addItem(*iter);
00254 }
00255
00256
00257 if(_imageItem)
00258 {
00259 _imageItem->setPixmap(_image);
00260 }
00261 else
00262 {
00263 _imageItem = _graphicsView->scene()->addPixmap(_image);
00264 _imageItem->setVisible(_showImage->isChecked());
00265 _showImage->setEnabled(true);
00266 }
00267
00268 if(_imageDepthItem)
00269 {
00270 _imageDepthItem->setPixmap(_imageDepth);
00271 }
00272 else
00273 {
00274 _imageDepthItem = _graphicsView->scene()->addPixmap(_imageDepth);
00275 _imageDepthItem->setVisible(_showImageDepth->isChecked());
00276 _showImageDepth->setEnabled(true);
00277 }
00278 this->updateOpacity();
00279
00280 if(_graphicsViewScaled->isChecked())
00281 {
00282 _graphicsView->fitInView(_graphicsView->sceneRect(), Qt::KeepAspectRatio);
00283 }
00284 else
00285 {
00286 _graphicsView->resetTransform();
00287 }
00288 }
00289 else
00290 {
00291 this->update();
00292 }
00293 }
00294
00295 void ImageView::setGraphicsViewScaled(bool scaled)
00296 {
00297 _graphicsViewScaled->setChecked(scaled);
00298
00299 if(scaled)
00300 {
00301 _graphicsView->fitInView(_graphicsView->sceneRect(), Qt::KeepAspectRatio);
00302 }
00303 else
00304 {
00305 _graphicsView->resetTransform();
00306 }
00307
00308 if(!_graphicsView->isVisible())
00309 {
00310 this->update();
00311 }
00312 }
00313
00314 void ImageView::setBackgroundColor(const QColor & color)
00315 {
00316 _graphicsView->setBackgroundBrush(QBrush(color));
00317
00318 if(!_graphicsView->isVisible())
00319 {
00320 this->update();
00321 }
00322 }
00323
00324 void ImageView::computeScaleOffsets(const QRect & targetRect, float & scale, float & offsetX, float & offsetY) const
00325 {
00326 scale = 1.0f;
00327 offsetX = 0.0f;
00328 offsetY = 0.0f;
00329
00330 if(!_graphicsView->scene()->sceneRect().isNull())
00331 {
00332 float w = _graphicsView->scene()->width();
00333 float h = _graphicsView->scene()->height();
00334 float widthRatio = float(targetRect.width()) / w;
00335 float heightRatio = float(targetRect.height()) / h;
00336
00337
00338 if(widthRatio < heightRatio)
00339 {
00340 scale = widthRatio;
00341 }
00342 else
00343 {
00344 scale = heightRatio;
00345 }
00346
00347
00348
00349 w *= scale;
00350 h *= scale;
00351
00352 if(w < targetRect.width())
00353 {
00354 offsetX = (targetRect.width() - w)/2.0f;
00355 }
00356 if(h < targetRect.height())
00357 {
00358 offsetY = (targetRect.height() - h)/2.0f;
00359 }
00360
00361 }
00362 }
00363
00364 void ImageView::sceneRectChanged(const QRectF & rect)
00365 {
00366 _saveImage->setEnabled(rect.isValid());
00367 }
00368
00369 void ImageView::paintEvent(QPaintEvent *event)
00370 {
00371 if(_graphicsViewMode->isChecked())
00372 {
00373 QWidget::paintEvent(event);
00374 }
00375 else
00376 {
00377 if(!_graphicsView->scene()->sceneRect().isNull())
00378 {
00379
00380 float ratio, offsetX, offsetY;
00381 this->computeScaleOffsets(event->rect(), ratio, offsetX, offsetY);
00382 QPainter painter(this);
00383
00384
00385 painter.save();
00386 painter.setBrush(_graphicsView->backgroundBrush());
00387 painter.drawRect(event->rect());
00388 painter.restore();
00389
00390 painter.translate(offsetX, offsetY);
00391 painter.scale(ratio, ratio);
00392
00393 painter.save();
00394 if(_showImage->isChecked() && !_image.isNull() &&
00395 _showImageDepth->isChecked() && !_imageDepth.isNull())
00396 {
00397 painter.setOpacity(0.5);
00398 }
00399
00400 if(_showImage->isChecked() && !_image.isNull())
00401 {
00402 painter.drawPixmap(QPoint(0,0), _image);
00403 }
00404
00405 if(_showImageDepth->isChecked() && !_imageDepth.isNull())
00406 {
00407 painter.drawPixmap(QPoint(0,0), _imageDepth);
00408 }
00409 painter.restore();
00410
00411 if(_showFeatures->isChecked())
00412 {
00413 for(QMultiMap<int, rtabmap::KeypointItem *>::iterator iter = _features.begin(); iter != _features.end(); ++iter)
00414 {
00415 QColor color = iter.value()->pen().color();
00416 painter.save();
00417 painter.setPen(color);
00418 painter.setBrush(color);
00419 painter.drawEllipse(iter.value()->rect());
00420 painter.restore();
00421 }
00422 }
00423
00424 if(_showLines->isChecked())
00425 {
00426 for(QList<QGraphicsLineItem*>::iterator iter = _lines.begin(); iter != _lines.end(); ++iter)
00427 {
00428 QColor color = (*iter)->pen().color();
00429 painter.save();
00430 painter.setPen(color);
00431 painter.drawLine((*iter)->line());
00432 painter.restore();
00433 }
00434 }
00435 }
00436 }
00437 }
00438
00439 void ImageView::resizeEvent(QResizeEvent* event)
00440 {
00441 QWidget::resizeEvent(event);
00442 if(_graphicsView->isVisible() && _graphicsViewScaled->isChecked())
00443 {
00444 _graphicsView->fitInView(_graphicsView->sceneRect(), Qt::KeepAspectRatio);
00445 }
00446 }
00447
00448 void ImageView::contextMenuEvent(QContextMenuEvent * e)
00449 {
00450 QAction * action = _menu->exec(e->globalPos());
00451 if(action == _saveImage)
00452 {
00453 if(!_graphicsView->scene()->sceneRect().isNull())
00454 {
00455 QString text;
00456 #ifdef QT_SVG_LIB
00457 text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), _savedFileName, "*.png *.xpm *.jpg *.pdf *.svg");
00458 #else
00459 text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), _savedFileName, "*.png *.xpm *.jpg *.pdf");
00460 #endif
00461 if(!text.isEmpty())
00462 {
00463 _savedFileName = text;
00464 QImage img(_graphicsView->sceneRect().width(), _graphicsView->sceneRect().height(), QImage::Format_ARGB32_Premultiplied);
00465 QPainter p(&img);
00466 if(_graphicsView->isVisible())
00467 {
00468 _graphicsView->scene()->render(&p, _graphicsView->sceneRect(), _graphicsView->sceneRect());
00469 }
00470 else
00471 {
00472 this->render(&p, QPoint(), _graphicsView->sceneRect().toRect());
00473 }
00474 img.save(text);
00475 }
00476 }
00477 }
00478 else if(action == _showFeatures)
00479 {
00480 this->setFeaturesShown(_showFeatures->isChecked());
00481 emit configChanged();
00482 }
00483 else if(action == _showImage)
00484 {
00485 this->setImageShown(_showImage->isChecked());
00486 emit configChanged();
00487 }
00488 else if(action == _showImageDepth)
00489 {
00490 this->setImageDepthShown(_showImageDepth->isChecked());
00491 emit configChanged();
00492 }
00493 else if(action == _showLines)
00494 {
00495 this->setLinesShown(_showLines->isChecked());
00496 emit configChanged();
00497 }
00498 else if(action == _graphicsViewMode)
00499 {
00500 this->setGraphicsViewMode(_graphicsViewMode->isChecked());
00501 emit configChanged();
00502 }
00503 else if(action == _graphicsViewScaled)
00504 {
00505 this->setGraphicsViewScaled(_graphicsViewScaled->isChecked());
00506 emit configChanged();
00507 }
00508 else if(action == _setAlpha)
00509 {
00510 bool ok = false;
00511 int value = QInputDialog::getInt(this, tr("Set features and lines transparency"), tr("alpha (0-255)"), _alpha, 0, 255, 10, &ok);
00512 if(ok)
00513 {
00514 this->setAlpha(value);
00515 emit configChanged();
00516 }
00517 }
00518
00519 if(action == _showImage || action ==_showImageDepth)
00520 {
00521 this->updateOpacity();
00522 emit configChanged();
00523 }
00524 }
00525
00526 void ImageView::updateOpacity()
00527 {
00528 if(_imageItem && _imageDepthItem)
00529 {
00530 if(_imageItem->isVisible() && _imageDepthItem->isVisible())
00531 {
00532 QGraphicsOpacityEffect * effect = new QGraphicsOpacityEffect();
00533 effect->setOpacity(0.5);
00534 _imageDepthItem->setGraphicsEffect(effect);
00535 }
00536 else
00537 {
00538 _imageDepthItem->setGraphicsEffect(0);
00539 }
00540 }
00541 else if(_imageDepthItem)
00542 {
00543 _imageDepthItem->setGraphicsEffect(0);
00544 }
00545 }
00546
00547 void ImageView::setFeatures(const std::multimap<int, cv::KeyPoint> & refWords, const cv::Mat & depth, const QColor & color)
00548 {
00549 qDeleteAll(_features);
00550 _features.clear();
00551
00552 for(std::multimap<int, cv::KeyPoint>::const_iterator iter = refWords.begin(); iter != refWords.end(); ++iter )
00553 {
00554 addFeature(iter->first, iter->second, depth.empty()?0:util3d::getDepth(depth, iter->second.pt.x, iter->second.pt.y, false), color);
00555 }
00556
00557 if(!_graphicsView->isVisible())
00558 {
00559 this->update();
00560 }
00561 }
00562
00563 void ImageView::setFeatures(const std::vector<cv::KeyPoint> & features, const cv::Mat & depth, const QColor & color)
00564 {
00565 qDeleteAll(_features);
00566 _features.clear();
00567
00568 for(unsigned int i = 0; i< features.size(); ++i )
00569 {
00570 addFeature(i, features[i], depth.empty()?0:util3d::getDepth(depth, features[i].pt.x, features[i].pt.y, false), color);
00571 }
00572
00573 if(!_graphicsView->isVisible())
00574 {
00575 this->update();
00576 }
00577 }
00578
00579 void ImageView::addFeature(int id, const cv::KeyPoint & kpt, float depth, QColor color)
00580 {
00581 color.setAlpha(this->getAlpha());
00582 rtabmap::KeypointItem * item = new rtabmap::KeypointItem(id, kpt, depth, color);
00583 _features.insert(id, item);
00584 item->setVisible(isFeaturesShown());
00585 item->setZValue(1);
00586
00587 if(_graphicsView->isVisible())
00588 {
00589 _graphicsView->scene()->addItem(item);
00590 }
00591 }
00592
00593 void ImageView::addLine(float x1, float y1, float x2, float y2, QColor color)
00594 {
00595 color.setAlpha(this->getAlpha());
00596 QGraphicsLineItem * item = new QGraphicsLineItem(x1, y1, x2, y2);
00597 item->setPen(QPen(color));
00598 _lines.push_back(item);
00599 item->setVisible(isLinesShown());
00600 item->setZValue(1);
00601
00602 if(_graphicsView->isVisible())
00603 {
00604 _graphicsView->scene()->addItem(item);
00605 }
00606 }
00607
00608 void ImageView::setImage(const QImage & image)
00609 {
00610 _image = QPixmap::fromImage(image);
00611 if(_graphicsView->isVisible())
00612 {
00613 if(_imageItem)
00614 {
00615 _imageItem->setPixmap(_image);
00616 }
00617 else
00618 {
00619 _imageItem = _graphicsView->scene()->addPixmap(_image);
00620 _imageItem->setVisible(_showImage->isChecked());
00621 _showImage->setEnabled(true);
00622 this->updateOpacity();
00623 }
00624 }
00625 else
00626 {
00627 this->setSceneRect(image.rect());
00628 this->update();
00629 }
00630 }
00631
00632 void ImageView::setImageDepth(const QImage & imageDepth)
00633 {
00634 _imageDepth = QPixmap::fromImage(imageDepth);
00635 if(_graphicsView->isVisible())
00636 {
00637 if(_imageDepthItem)
00638 {
00639 _imageDepthItem->setPixmap(_imageDepth);
00640 }
00641 else
00642 {
00643 _imageDepthItem = _graphicsView->scene()->addPixmap(_imageDepth);
00644 _imageDepthItem->setVisible(_showImageDepth->isChecked());
00645 _showImageDepth->setEnabled(true);
00646 this->updateOpacity();
00647 }
00648 }
00649 else
00650 {
00651 this->setSceneRect(imageDepth.rect());
00652 this->update();
00653 }
00654 }
00655
00656 void ImageView::setFeatureColor(int id, QColor color)
00657 {
00658 color.setAlpha(getAlpha());
00659 QList<KeypointItem*> items = _features.values(id);
00660 if(items.size())
00661 {
00662 for(int i=0; i<items.size(); ++i)
00663 {
00664 items[i]->setColor(color);
00665 }
00666 }
00667 else
00668 {
00669 UWARN("Not found feature %d", id);
00670 }
00671
00672 if(!_graphicsView->isVisible())
00673 {
00674 this->update();
00675 }
00676 }
00677
00678 void ImageView::setFeaturesColor(QColor color)
00679 {
00680 color.setAlpha(getAlpha());
00681 for(QMultiMap<int, KeypointItem*>::iterator iter=_features.begin(); iter!=_features.end(); ++iter)
00682 {
00683 iter.value()->setColor(color);
00684 }
00685
00686 if(!_graphicsView->isVisible())
00687 {
00688 this->update();
00689 }
00690 }
00691
00692 void ImageView::setAlpha(int alpha)
00693 {
00694 UASSERT(alpha >=0 && alpha <= 255);
00695 _alpha = alpha;
00696 for(QMultiMap<int, KeypointItem*>::iterator iter=_features.begin(); iter!=_features.end(); ++iter)
00697 {
00698 QColor c = iter.value()->pen().color();
00699 c.setAlpha(_alpha);
00700 iter.value()->setPen(QPen(c));
00701 iter.value()->setBrush(QBrush(c));
00702 }
00703
00704 for(QList<QGraphicsLineItem*>::iterator iter=_lines.begin(); iter!=_lines.end(); ++iter)
00705 {
00706 QColor c = (*iter)->pen().color();
00707 c.setAlpha(_alpha);
00708 (*iter)->setPen(QPen(c));
00709 }
00710
00711 if(!_graphicsView->isVisible())
00712 {
00713 this->update();
00714 }
00715 }
00716
00717 void ImageView::setSceneRect(const QRectF & rect)
00718 {
00719 _graphicsView->scene()->setSceneRect(rect);
00720
00721 if(_graphicsViewScaled->isChecked())
00722 {
00723 _graphicsView->fitInView(_graphicsView->sceneRect(), Qt::KeepAspectRatio);
00724 }
00725 else
00726 {
00727 _graphicsView->resetTransform();
00728 }
00729
00730 if(!_graphicsView->isVisible())
00731 {
00732 this->update();
00733 }
00734 }
00735
00736 void ImageView::clearLines()
00737 {
00738 qDeleteAll(_lines);
00739 _lines.clear();
00740
00741 if(!_graphicsView->isVisible())
00742 {
00743 this->update();
00744 }
00745 }
00746
00747 void ImageView::clear()
00748 {
00749 qDeleteAll(_features);
00750 _features.clear();
00751
00752 qDeleteAll(_lines);
00753 _lines.clear();
00754
00755 if(_imageItem)
00756 {
00757 _graphicsView->scene()->removeItem(_imageItem);
00758 delete _imageItem;
00759 _imageItem = 0;
00760 _showImage->setEnabled(false);
00761 }
00762 _image = QPixmap();
00763
00764 if(_imageDepthItem)
00765 {
00766 _graphicsView->scene()->removeItem(_imageDepthItem);
00767 delete _imageDepthItem;
00768 _imageDepthItem = 0;
00769 _showImageDepth->setEnabled(false);
00770 }
00771 _imageDepth = QPixmap();
00772
00773 if(!_graphicsView->isVisible())
00774 {
00775 this->update();
00776 }
00777 }
00778
00779 QSize ImageView::sizeHint() const
00780 {
00781 return _graphicsView->sizeHint();
00782 }
00783
00784 }