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 <QWidget>
00029 #include <QPainter>
00030 #include <QMouseEvent>
00031 #include <QMenu>
00032 #include <QAction>
00033 #include <QInputDialog>
00034
00035 #include "rtabmap/gui/EditDepthArea.h"
00036 #include <rtabmap/utilite/ULogger.h>
00037 #include <rtabmap/utilite/UCv2Qt.h>
00038
00039 namespace rtabmap {
00040
00041 EditDepthArea::EditDepthArea(QWidget *parent)
00042 : QWidget(parent)
00043 {
00044 setAttribute(Qt::WA_StaticContents);
00045 modified_ = false;
00046 scribbling_ = false;
00047 myPenWidth_ = 10;
00048
00049 menu_ = new QMenu(tr(""), this);
00050 showRGB_ = menu_->addAction(tr("Show RGB Image"));
00051 showRGB_->setCheckable(true);
00052 showRGB_->setChecked(true);
00053 removeCluster_ = menu_->addAction(tr("Remove Cluster"));
00054 setPenWidth_ = menu_->addAction(tr("Set Pen Width..."));
00055 resetChanges_ = menu_->addAction(tr("Reset Changes"));
00056 }
00057
00058 void EditDepthArea::setImage(const cv::Mat &depth, const cv::Mat & rgb)
00059 {
00060 UASSERT(!depth.empty());
00061 UASSERT(depth.type() == CV_32FC1 ||
00062 depth.type() == CV_16UC1);
00063 originalImage_ = depth;
00064 image_ = uCvMat2QImage(depth).convertToFormat(QImage::Format_RGB32);
00065
00066 imageRGB_ = QImage();
00067 if(!rgb.empty())
00068 {
00069 imageRGB_ = uCvMat2QImage(rgb);
00070 if( depth.cols != rgb.cols ||
00071 depth.rows != rgb.rows)
00072 {
00073
00074 imageRGB_ = imageRGB_.scaled(image_.size());
00075 }
00076 }
00077 showRGB_->setEnabled(!imageRGB_.isNull());
00078 modified_ = false;
00079 update();
00080 }
00081
00082 cv::Mat EditDepthArea::getModifiedImage() const
00083 {
00084 cv::Mat modifiedImage = originalImage_.clone();
00085 if(modified_)
00086 {
00087 UASSERT(image_.width() == modifiedImage.cols &&
00088 image_.height() == modifiedImage.rows);
00089 UASSERT(modifiedImage.type() == CV_32FC1 ||
00090 modifiedImage.type() == CV_16UC1);
00091 for(int j=0; j<image_.height(); ++j)
00092 {
00093 for(int i=0; i<image_.width(); ++i)
00094 {
00095 if(qRed(image_.pixel(i, j)) == 0 &&
00096 qGreen(image_.pixel(i, j)) == 0 &&
00097 qBlue(image_.pixel(i, j)) == 0)
00098 {
00099 if(modifiedImage.type() == CV_32FC1)
00100 {
00101 modifiedImage.at<float>(j,i) = 0.0f;
00102 }
00103 else
00104 {
00105 modifiedImage.at<unsigned short>(j,i) = 0;
00106 }
00107 }
00108 }
00109 }
00110 }
00111 return modifiedImage;
00112 }
00113
00114 void EditDepthArea::setPenWidth(int newWidth)
00115 {
00116 myPenWidth_ = newWidth;
00117 }
00118
00119 void EditDepthArea::resetChanges()
00120 {
00121 image_ = uCvMat2QImage(originalImage_).convertToFormat(QImage::Format_RGB32);
00122 modified_ = false;
00123 update();
00124 }
00125
00126 void EditDepthArea::mousePressEvent(QMouseEvent *event)
00127 {
00128 if (event->button() == Qt::LeftButton) {
00129 float scale, offsetX, offsetY;
00130 computeScaleOffsets(rect(), scale, offsetX, offsetY);
00131 lastPoint_.setX((event->pos().x()-offsetX)/scale);
00132 lastPoint_.setY((event->pos().y()-offsetY)/scale);
00133
00134 scribbling_ = true;
00135 }
00136 }
00137
00138 void EditDepthArea::mouseMoveEvent(QMouseEvent *event)
00139 {
00140 if ((event->buttons() & Qt::LeftButton) && scribbling_)
00141 {
00142 float scale, offsetX, offsetY;
00143 computeScaleOffsets(rect(), scale, offsetX, offsetY);
00144 QPoint to;
00145 to.setX((event->pos().x()-offsetX)/scale);
00146 to.setY((event->pos().y()-offsetY)/scale);
00147 drawLineTo(to);
00148 }
00149 }
00150
00151 void EditDepthArea::mouseReleaseEvent(QMouseEvent *event)
00152 {
00153 if (event->button() == Qt::LeftButton && scribbling_) {
00154 float scale, offsetX, offsetY;
00155 computeScaleOffsets(rect(), scale, offsetX, offsetY);
00156 QPoint to;
00157 to.setX((event->pos().x()-offsetX)/scale);
00158 to.setY((event->pos().y()-offsetY)/scale);
00159 drawLineTo(to);
00160 scribbling_ = false;
00161 }
00162 }
00163
00164 void EditDepthArea::computeScaleOffsets(const QRect & targetRect, float & scale, float & offsetX, float & offsetY) const
00165 {
00166 scale = 1.0f;
00167 offsetX = 0.0f;
00168 offsetY = 0.0f;
00169
00170 if(!image_.isNull())
00171 {
00172 float w = image_.width();
00173 float h = image_.height();
00174 float widthRatio = float(targetRect.width()) / w;
00175 float heightRatio = float(targetRect.height()) / h;
00176
00177
00178 if(widthRatio < heightRatio)
00179 {
00180 scale = widthRatio;
00181 }
00182 else
00183 {
00184 scale = heightRatio;
00185 }
00186
00187
00188
00189 w *= scale;
00190 h *= scale;
00191
00192 if(w < targetRect.width())
00193 {
00194 offsetX = (targetRect.width() - w)/2.0f;
00195 }
00196 if(h < targetRect.height())
00197 {
00198 offsetY = (targetRect.height() - h)/2.0f;
00199 }
00200
00201 }
00202 }
00203
00204 void EditDepthArea::paintEvent(QPaintEvent *event)
00205 {
00206
00207 float ratio, offsetX, offsetY;
00208 this->computeScaleOffsets(event->rect(), ratio, offsetX, offsetY);
00209 QPainter painter(this);
00210
00211 painter.translate(offsetX, offsetY);
00212 painter.scale(ratio, ratio);
00213
00214 if(showRGB_->isChecked() && !imageRGB_.isNull())
00215 {
00216 painter.setOpacity(0.5);
00217 painter.drawImage(QPoint(0,0), imageRGB_);
00218 }
00219
00220 painter.drawImage(QPoint(0,0), image_);
00221 }
00222
00223 void EditDepthArea::resizeEvent(QResizeEvent *event)
00224 {
00225 QWidget::resizeEvent(event);
00226 }
00227
00228 void floodfill(QImage & image, const cv::Mat & depthImage, int x, int y, float lastDepthValue, float error)
00229 {
00230 if(x>=0 && x<depthImage.cols &&
00231 y>=0 && y<depthImage.rows)
00232 {
00233 float currentValue;
00234 if(depthImage.type() == CV_32FC1)
00235 {
00236 currentValue = depthImage.at<float>(y, x);
00237 }
00238 else
00239 {
00240 currentValue = float(depthImage.at<unsigned short>(y, x))/1000.0f;
00241 }
00242
00243 QRgb rgb = image.pixel(x,y);
00244 if(qRed(rgb) == 0 && qGreen(rgb) == 0 && qBlue(rgb) == 0)
00245 {
00246 return;
00247 }
00248 if(currentValue == 0.0f)
00249 {
00250 return;
00251 }
00252 if(lastDepthValue>=0.0f && fabs(lastDepthValue - currentValue) > error*lastDepthValue)
00253 {
00254 return;
00255 }
00256
00257 image.setPixel(x, y, 0);
00258
00259 floodfill(image, depthImage, x, y+1, currentValue, error);
00260 floodfill(image, depthImage, x, y-1, currentValue, error);
00261 floodfill(image, depthImage, x-1, y, currentValue, error);
00262 floodfill(image, depthImage, x+1, y, currentValue, error);
00263 }
00264 }
00265
00266 void EditDepthArea::contextMenuEvent(QContextMenuEvent * e)
00267 {
00268 QAction * action = menu_->exec(e->globalPos());
00269 if(action == showRGB_)
00270 {
00271 this->update();
00272 }
00273 else if(action == removeCluster_)
00274 {
00275 float scale, offsetX, offsetY;
00276 computeScaleOffsets(rect(), scale, offsetX, offsetY);
00277 QPoint pixel;
00278 pixel.setX((e->pos().x()-offsetX)/scale);
00279 pixel.setY((e->pos().y()-offsetY)/scale);
00280 if(pixel.x()>=0 && pixel.x() < originalImage_.cols &&
00281 pixel.y()>=0 && pixel.y() < originalImage_.rows)
00282 {
00283 floodfill(image_, originalImage_, pixel.x(), pixel.y(), -1.0f, 0.02f);
00284 }
00285 modified_=true;
00286 this->update();
00287 }
00288 else if(action == setPenWidth_)
00289 {
00290 bool ok;
00291 int width = QInputDialog::getInt(this, tr("Set Pen Width"), tr("Width:"), penWidth(), 1, 99, 1, &ok);
00292 if(ok)
00293 {
00294 myPenWidth_ = width;
00295 }
00296 }
00297 else if(action == resetChanges_)
00298 {
00299 this->resetChanges();
00300 }
00301 }
00302
00303 void EditDepthArea::drawLineTo(const QPoint &endPoint)
00304 {
00305 QPainter painter(&image_);
00306 painter.setPen(QPen(Qt::black, myPenWidth_, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
00307 painter.drawLine(lastPoint_, endPoint);
00308 modified_ = true;
00309
00310 update();
00311 lastPoint_ = endPoint;
00312 }
00313
00314 }