EditDepthArea.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the name of the Universite de Sherbrooke nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 #include <QWidget>
29 #include <QPainter>
30 #include <QMouseEvent>
31 #include <QMenu>
32 #include <QAction>
33 #include <QInputDialog>
34 
37 #include <rtabmap/utilite/UCv2Qt.h>
38 
39 namespace rtabmap {
40 
42  : QWidget(parent)
43 {
44  setAttribute(Qt::WA_StaticContents);
45  modified_ = false;
46  scribbling_ = false;
47  myPenWidth_ = 10;
48 
49  menu_ = new QMenu(tr(""), this);
50  showRGB_ = menu_->addAction(tr("Show RGB Image"));
51  showRGB_->setCheckable(true);
52  showRGB_->setChecked(true);
53  removeCluster_ = menu_->addAction(tr("Remove Cluster"));
54  setPenWidth_ = menu_->addAction(tr("Set Pen Width..."));
55  resetChanges_ = menu_->addAction(tr("Reset Changes"));
56 }
57 
58 void EditDepthArea::setImage(const cv::Mat &depth, const cv::Mat & rgb)
59 {
60  UASSERT(!depth.empty());
61  UASSERT(depth.type() == CV_32FC1 ||
62  depth.type() == CV_16UC1);
63  originalImage_ = depth;
64  image_ = uCvMat2QImage(depth).convertToFormat(QImage::Format_RGB32);
65 
66  imageRGB_ = QImage();
67  if(!rgb.empty())
68  {
69  imageRGB_ = uCvMat2QImage(rgb);
70  if( depth.cols != rgb.cols ||
71  depth.rows != rgb.rows)
72  {
73  // scale rgb to depth
74  imageRGB_ = imageRGB_.scaled(image_.size());
75  }
76  }
77  showRGB_->setEnabled(!imageRGB_.isNull());
78  modified_ = false;
79  update();
80 }
81 
83 {
84  cv::Mat modifiedImage = originalImage_.clone();
85  if(modified_)
86  {
87  UASSERT(image_.width() == modifiedImage.cols &&
88  image_.height() == modifiedImage.rows);
89  UASSERT(modifiedImage.type() == CV_32FC1 ||
90  modifiedImage.type() == CV_16UC1);
91  for(int j=0; j<image_.height(); ++j)
92  {
93  for(int i=0; i<image_.width(); ++i)
94  {
95  if(qRed(image_.pixel(i, j)) == 0 &&
96  qGreen(image_.pixel(i, j)) == 0 &&
97  qBlue(image_.pixel(i, j)) == 0)
98  {
99  if(modifiedImage.type() == CV_32FC1)
100  {
101  modifiedImage.at<float>(j,i) = 0.0f;
102  }
103  else // CV_16UC1
104  {
105  modifiedImage.at<unsigned short>(j,i) = 0;
106  }
107  }
108  }
109  }
110  }
111  return modifiedImage;
112 }
113 
114 void EditDepthArea::setPenWidth(int newWidth)
115 {
116  myPenWidth_ = newWidth;
117 }
118 
120 {
121  image_ = uCvMat2QImage(originalImage_).convertToFormat(QImage::Format_RGB32);
122  modified_ = false;
123  update();
124 }
125 
126 void EditDepthArea::mousePressEvent(QMouseEvent *event)
127 {
128  if (event->button() == Qt::LeftButton) {
129  float scale, offsetX, offsetY;
130  computeScaleOffsets(rect(), scale, offsetX, offsetY);
131  lastPoint_.setX((event->pos().x()-offsetX)/scale);
132  lastPoint_.setY((event->pos().y()-offsetY)/scale);
133 
134  scribbling_ = true;
135  }
136 }
137 
138 void EditDepthArea::mouseMoveEvent(QMouseEvent *event)
139 {
140  if ((event->buttons() & Qt::LeftButton) && scribbling_)
141  {
142  float scale, offsetX, offsetY;
143  computeScaleOffsets(rect(), scale, offsetX, offsetY);
144  QPoint to;
145  to.setX((event->pos().x()-offsetX)/scale);
146  to.setY((event->pos().y()-offsetY)/scale);
147  drawLineTo(to);
148  }
149 }
150 
151 void EditDepthArea::mouseReleaseEvent(QMouseEvent *event)
152 {
153  if (event->button() == Qt::LeftButton && scribbling_) {
154  float scale, offsetX, offsetY;
155  computeScaleOffsets(rect(), scale, offsetX, offsetY);
156  QPoint to;
157  to.setX((event->pos().x()-offsetX)/scale);
158  to.setY((event->pos().y()-offsetY)/scale);
159  drawLineTo(to);
160  scribbling_ = false;
161  }
162 }
163 
164 void EditDepthArea::computeScaleOffsets(const QRect & targetRect, float & scale, float & offsetX, float & offsetY) const
165 {
166  scale = 1.0f;
167  offsetX = 0.0f;
168  offsetY = 0.0f;
169 
170  if(!image_.isNull())
171  {
172  float w = image_.width();
173  float h = image_.height();
174  float widthRatio = float(targetRect.width()) / w;
175  float heightRatio = float(targetRect.height()) / h;
176 
177  //printf("w=%f, h=%f, wR=%f, hR=%f, sW=%d, sH=%d\n", w, h, widthRatio, heightRatio, this->rect().width(), this->rect().height());
178  if(widthRatio < heightRatio)
179  {
180  scale = widthRatio;
181  }
182  else
183  {
184  scale = heightRatio;
185  }
186 
187  //printf("ratio=%f\n",ratio);
188 
189  w *= scale;
190  h *= scale;
191 
192  if(w < targetRect.width())
193  {
194  offsetX = (targetRect.width() - w)/2.0f;
195  }
196  if(h < targetRect.height())
197  {
198  offsetY = (targetRect.height() - h)/2.0f;
199  }
200  //printf("offsetX=%f, offsetY=%f\n",offsetX, offsetY);
201  }
202 }
203 
204 void EditDepthArea::paintEvent(QPaintEvent *event)
205 {
206  //Scale
207  float ratio, offsetX, offsetY;
208  this->computeScaleOffsets(event->rect(), ratio, offsetX, offsetY);
209  QPainter painter(this);
210 
211  painter.translate(offsetX, offsetY);
212  painter.scale(ratio, ratio);
213 
214  if(showRGB_->isChecked() && !imageRGB_.isNull())
215  {
216  painter.setOpacity(0.5);
217  painter.drawImage(QPoint(0,0), imageRGB_);
218  }
219 
220  painter.drawImage(QPoint(0,0), image_);
221 }
222 
223 void EditDepthArea::resizeEvent(QResizeEvent *event)
224 {
225  QWidget::resizeEvent(event);
226 }
227 
228 void floodfill(QImage & image, const cv::Mat & depthImage, int x, int y, float lastDepthValue, float error)
229 {
230  if(x>=0 && x<depthImage.cols &&
231  y>=0 && y<depthImage.rows)
232  {
233  float currentValue;
234  if(depthImage.type() == CV_32FC1)
235  {
236  currentValue = depthImage.at<float>(y, x);
237  }
238  else
239  {
240  currentValue = float(depthImage.at<unsigned short>(y, x))/1000.0f;
241  }
242 
243  QRgb rgb = image.pixel(x,y);
244  if(qRed(rgb) == 0 && qGreen(rgb) == 0 && qBlue(rgb) == 0)
245  {
246  return;
247  }
248  if(currentValue == 0.0f)
249  {
250  return;
251  }
252  if(lastDepthValue>=0.0f && fabs(lastDepthValue - currentValue) > error*lastDepthValue)
253  {
254  return;
255  }
256 
257  image.setPixel(x, y, 0);
258 
259  floodfill(image, depthImage, x, y+1, currentValue, error);
260  floodfill(image, depthImage, x, y-1, currentValue, error);
261  floodfill(image, depthImage, x-1, y, currentValue, error);
262  floodfill(image, depthImage, x+1, y, currentValue, error);
263  }
264 }
265 
266 void EditDepthArea::contextMenuEvent(QContextMenuEvent * e)
267 {
268  QAction * action = menu_->exec(e->globalPos());
269  if(action == showRGB_)
270  {
271  this->update();
272  }
273  else if(action == removeCluster_)
274  {
275  float scale, offsetX, offsetY;
276  computeScaleOffsets(rect(), scale, offsetX, offsetY);
277  QPoint pixel;
278  pixel.setX((e->pos().x()-offsetX)/scale);
279  pixel.setY((e->pos().y()-offsetY)/scale);
280  if(pixel.x()>=0 && pixel.x() < originalImage_.cols &&
281  pixel.y()>=0 && pixel.y() < originalImage_.rows)
282  {
283  floodfill(image_, originalImage_, pixel.x(), pixel.y(), -1.0f, 0.02f);
284  }
285  modified_=true;
286  this->update();
287  }
288  else if(action == setPenWidth_)
289  {
290  bool ok;
291  int width = QInputDialog::getInt(this, tr("Set Pen Width"), tr("Width:"), penWidth(), 1, 99, 1, &ok);
292  if(ok)
293  {
294  myPenWidth_ = width;
295  }
296  }
297  else if(action == resetChanges_)
298  {
299  this->resetChanges();
300  }
301 }
302 
303 void EditDepthArea::drawLineTo(const QPoint &endPoint)
304 {
305  QPainter painter(&image_);
306  painter.setPen(QPen(Qt::black, myPenWidth_, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
307  painter.drawLine(lastPoint_, endPoint);
308  modified_ = true;
309 
310  update();
311  lastPoint_ = endPoint;
312 }
313 
314 }
void setImage(const cv::Mat &depth, const cv::Mat &rgb=cv::Mat())
EditDepthArea(QWidget *parent=0)
void drawLineTo(const QPoint &endPoint)
void setPenWidth(int newWidth)
f
GLM_FUNC_DECL genType e()
virtual void resizeEvent(QResizeEvent *event)
GLM_FUNC_DECL detail::tmat4x4< T, P > scale(detail::tmat4x4< T, P > const &m, detail::tvec3< T, P > const &v)
virtual void contextMenuEvent(QContextMenuEvent *e)
virtual void mouseMoveEvent(QMouseEvent *event)
#define UASSERT(condition)
cv::Mat getModifiedImage() const
virtual void mouseReleaseEvent(QMouseEvent *event)
QImage uCvMat2QImage(const cv::Mat &image, bool isBgr=true, uCvQtDepthColorMap colorMap=uCvQtDepthWhiteToBlack)
Definition: UCv2Qt.h:44
void computeScaleOffsets(const QRect &targetRect, float &scale, float &offsetX, float &offsetY) const
virtual void mousePressEvent(QMouseEvent *event)
void floodfill(QImage &image, const cv::Mat &depthImage, int x, int y, float lastDepthValue, float error)
ULogger class and convenient macros.
virtual void paintEvent(QPaintEvent *event)


rtabmap
Author(s): Mathieu Labbe
autogenerated on Wed Jun 5 2019 22:41:31