ImageMaskPainterWidgetController.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * \package VisionX::gui-plugins::ImageMaskPainterWidgetController
17 * \author Raphael Grimm ( raphael dot grimm at kit dot edu )
18 * \date 2018
19 * \copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
24
25#include <string>
26
27#include <QImage>
28
30
32
33using namespace armarx;
34
36{
37 _widget.setupUi(getWidget());
38
39 _maskEditor = new ImageMaskEditor;
40 _widget.horizontalLayoutImageMonitors->addWidget(_maskEditor);
41
42 _maskEditor->setPenCircleVisible(true);
43 QImage bg(512, 512, QImage::Format_ARGB32);
44 bg.fill(Qt::red);
45 _maskEditor->setBackgroundImage(bg);
46 _maskEditor->setPenWidth(_widget.spinBoxPenWidth->value());
47 _maskEditor->setMaskAlpha(_widget.spinBoxPenAlpha->value());
48
49 updatePenColor();
50
51 connect(_maskEditor, SIGNAL(maskUpdateFinished()), this, SLOT(maskUpdated()));
52 connect(_maskEditor,
53 SIGNAL(arrowDrawn(const QPoint&, const QPoint&)),
54 this,
55 SLOT(arrowDrawn(const QPoint&, const QPoint&)));
56
57 connect(
58 _widget.spinBoxPenWidth, SIGNAL(valueChanged(int)), _maskEditor, SLOT(setPenWidth(int)));
59 connect(
60 _widget.spinBoxPenAlpha, SIGNAL(valueChanged(int)), _maskEditor, SLOT(setMaskAlpha(int)));
61 connect(_widget.pushButtonClear, SIGNAL(clicked()), _maskEditor, SLOT(clearMaskImage()));
62
63 connect(
64 _widget.spinBoxImageIndex, SIGNAL(valueChanged(int)), this, SLOT(imageIndexChanged(int)));
65 connect(_widget.checkBoxErase, SIGNAL(clicked()), this, SLOT(updatePenColor()));
66
67 startTimer(1);
68}
69
71
72QPointer<QDialog>
74{
75 if (!_dialog)
76 {
77 _dialog = new SimpleConfigDialog(parent);
78 _dialog->addProxyFinder<visionx::ImageProviderInterfacePrx>(
79 {"ImageProvider", "ImageProvider", "Image*|*Provider"});
80 }
81 return qobject_cast<SimpleConfigDialog*>(_dialog);
82}
83
84void
89
90void
92{
93 _imageProviderName = _dialog->getProxyName("ImageProvider");
94}
95
96void
98{
99 _imageProviderName =
100 settings->value("_imageProviderName", "OpenNIPointCloudProvider").toString().toStdString();
101}
102
103void
105{
106 settings->setValue("_imageProviderName", QString::fromStdString(_imageProviderName));
107}
108
109void
111{
112 if (!_providerImagesOwner.empty())
113 {
114 return;
115 }
116 _imageProviderInfo = getImageProvider(_imageProviderName, true);
117 _imageProvider = _imageProviderInfo.proxy;
118 ARMARX_CHECK_GREATER(_imageProviderInfo.numberImages, 0);
119 ARMARX_CHECK_EQUAL(_imageProviderInfo.imageFormat.type, visionx::ImageType::eRgb);
120 //reserve buffers
121 _providerImagesOwner.reserve(_imageProviderInfo.numberImages);
122 _providerImages.reserve(_imageProviderInfo.numberImages);
123 for (int i = 0; i < _imageProviderInfo.numberImages; ++i)
124 {
125 _providerImagesOwner.emplace_back(visionx::tools::createByteImage(_imageProviderInfo));
126 _providerImages.emplace_back(static_cast<void*>(_providerImagesOwner.back()->pixels));
127 }
128 _numberOfImages = _imageProviderInfo.numberImages;
129 _resultImage.reset(visionx::tools::createByteImage(_imageProviderInfo));
131 _imageProviderInfo.imageFormat.dimension,
132 visionx::ImageType::eRgb,
133 _imageProviderName + "_Mask");
134
135 {
136 _imageProviderReferenceFrame = "Global";
137 auto frameprov = visionx::ReferenceFrameInterfacePrx::checkedCast(_imageProvider);
138 if (frameprov)
139 {
140 _imageProviderReferenceFrame = frameprov->getReferenceFrame();
141 }
142 }
143 {
144 _imageProviderAreImagesUndistorted = true;
145
146 auto mcalibprov =
147 visionx::MonocularCalibrationCapturingProviderInterfacePrx::checkedCast(_imageProvider);
148 auto scalibprov = visionx::StereoCalibrationInterfacePrx::checkedCast(_imageProvider);
149 if (scalibprov)
150 {
151 _imageProviderCalibration = scalibprov->getStereoCalibration();
152 _imageProviderAreImagesUndistorted = scalibprov->getImagesAreUndistorted();
153 }
154 else if (mcalibprov)
155 {
156 ARMARX_WARNING << "only monoocular upstream calibration! duplicating it and using "
157 "identity matices";
158 auto mono = mcalibprov->getCalibration();
159 _imageProviderCalibration.calibrationLeft = mono;
160 _imageProviderCalibration.calibrationRight = mono;
161 _imageProviderCalibration.rectificationHomographyLeft = {
162 {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
163 _imageProviderCalibration.rectificationHomographyRight = {
164 {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
165
166 _imageProviderAreImagesUndistorted = true;
167 }
168 else
169 {
170 ARMARX_WARNING << "no upstream calibration! using default values";
171 _imageProviderCalibration.calibrationLeft.cameraParam.distortion = {0, 0};
172 _imageProviderCalibration.calibrationLeft.cameraParam.focalLength = {50, 50};
173 _imageProviderCalibration.calibrationLeft.cameraParam.height =
174 _imageProviderInfo.imageFormat.dimension.height;
175 _imageProviderCalibration.calibrationLeft.cameraParam.width =
176 _imageProviderInfo.imageFormat.dimension.width;
177 _imageProviderCalibration.calibrationLeft.cameraParam.principalPoint = {
178 _imageProviderInfo.imageFormat.dimension.width / 2.f,
179 _imageProviderInfo.imageFormat.dimension.height / 2.f};
180 _imageProviderCalibration.calibrationLeft.cameraParam.rotation = {
181 {1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
182 _imageProviderCalibration.calibrationLeft.cameraParam.translation = {0, 0, 0};
183
184 _imageProviderCalibration.calibrationRight = _imageProviderCalibration.calibrationLeft;
185 _imageProviderCalibration.rectificationHomographyLeft = {
186 {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
187 _imageProviderCalibration.rectificationHomographyRight = {
188 {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
189 }
190 }
191}
192
193void
195{
196 if (!waitForImages(_imageProviderName, 1000))
197 {
198 return;
199 }
200 getImages(_providerImages.data());
201 const CByteImage& img = *(_providerImagesOwner.at(_imageIndex));
202 {
203 std::lock_guard<std::mutex> guard{_currentImageMutex};
204 _currentImage = QImage(img.width, img.height, QImage::Format_RGB888);
205 ARMARX_CHECK_NOT_NULL(_currentImage.bits());
206 ARMARX_CHECK_NOT_NULL(img.pixels);
207 std::memcpy(_currentImage.bits(), img.pixels, 3 * img.width * img.height);
208 _currentImageDirty = true;
209 }
210 ARMARX_INFO << deactivateSpam() << "received image";
211}
212
213void
215{
216 _widget.spinBoxImageIndex->setMaximum(std::max(1, _numberOfImages.load()) - 1);
217 if (!_currentImageDirty)
218 {
219 return;
220 }
221 {
222 std::lock_guard<std::mutex> guard{_currentImageMutex};
223 _maskEditor->setBackgroundImage(_currentImage);
224 _currentImageDirty = false;
225 }
226 ARMARX_INFO << deactivateSpam() << "updated displayed image";
227 if (_maskSet)
228 {
229 ARMARX_INFO << deactivateSpam() << "send new mask";
230 auto ptr = _resultImage.get();
232 }
233}
234
235QString
237{
238 return "VisionX.ImageMaskPainter";
239}
240
241void
242ImageMaskPainterWidgetController::updatePenColor()
243{
244 auto color =
245 _widget.checkBoxErase->isChecked() ? _maskEditor->transparentColor() : QColor(0, 0, 255);
246 _maskEditor->setMaskColor(color);
247}
248
249void
250ImageMaskPainterWidgetController::imageIndexChanged(int i)
251{
252 _imageIndex = _widget.spinBoxImageIndex->value();
253}
254
255void
256ImageMaskPainterWidgetController::maskUpdated()
257{
258 if (!_resultImage)
259 {
260 //oninit did not run
261 return;
262 }
263 QSize sz = _maskEditor->imageSize();
264 if (sz.width() != _resultImage->width || sz.height() != _resultImage->height)
265 {
266 //the initial mask was set. the mask was not resized to the providers size
267 return;
268 }
269
270 QImage mask = _maskEditor->maskImage();
271 sz = mask.size();
272 ARMARX_CHECK_EQUAL(sz.width(), _resultImage->width);
273 ARMARX_CHECK_EQUAL(sz.height(), _resultImage->height);
274
275 //the qimage has an alpha channel!
276 for (int x = 0; x < _resultImage->width; ++x)
277 {
278 for (int y = 0; y < _resultImage->height; ++y)
279 {
280 int offset = (x + y * _resultImage->width) * 3;
281 const QColor color{mask.pixel(x, y)};
282 _resultImage->pixels[offset + 0] = color.red();
283 _resultImage->pixels[offset + 1] = color.green();
284 _resultImage->pixels[offset + 2] = color.blue();
285 }
286 }
287 _maskSet = true;
288}
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
void setMaskColor(const QColor &newColor)
const QColor & transparentColor() const
void setPenCircleVisible(bool b=true)
virtual QPointer< QWidget > getWidget()
getWidget returns a pointer to the a widget of this controller.
void onConnectImageProcessor() override
Implement this method in the ImageProcessor in order execute parts when the component is fully initia...
static QString GetWidgetName()
Returns the Widget name displayed in the ArmarXGui to create an instance of this class.
void process() override
Process the vision component.
void onInitImageProcessor() override
Setup the vision component.
void configured() override
This function must be implemented by the user, if he supplies a config dialog.
QPointer< QDialog > getConfigDialog(QWidget *parent) override
getConfigDialog returns a pointer to the a configuration widget of this controller.
virtual ~ImageMaskPainterWidgetController()
Controller destructor.
A config-dialog containing one (or multiple) proxy finders.
void enableResultImages(int numberImages, ImageDimension imageDimension, ImageType imageType, const std::string &name="")
Enables visualization.
void usingImageProvider(std::string name)
Registers a delayed topic subscription and a delayed provider proxy retrieval which all will be avail...
bool waitForImages(int milliseconds=1000)
Wait for new images.
ImageProviderInfo getImageProvider(std::string name, ImageType destinationImageType=eRgb, bool waitForProxy=false)
Select an ImageProvider.
int getImages(CByteImage **ppImages)
Poll images from provider.
void provideResultImages(CByteImage **images, armarx::MetaInfoSizeBasePtr info=nullptr)
sends result images for visualization
#define ARMARX_CHECK_GREATER(lhs, rhs)
This macro evaluates whether lhs is greater (>) than rhs and if it turns out to be false it will thro...
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
This file offers overloads of toIce() and fromIce() functions for STL container types.
CByteImage * createByteImage(const ImageFormatInfo &imageFormat, const ImageType imageType)
Creates a ByteImage for the destination type specified in the given imageProviderInfo.