HsvColorSegmentationWidgetController.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::HsvColorSegmentationWidgetController
17 * \author Rainer Kartmann ( rainer dot kartmann at student dot 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 <pwd.h>
26
27#include <QFileDialog>
28#include <QMessageBox>
29
32
33// ivt
34#include <VisionX/interface/core/ImageProviderInterface.h>
36
37#include <Image/PrimitivesDrawer.h>
38
39
40using namespace armarx;
41
42
43const QStringList HsvColorSegmentationWidgetController::COLOR_PARAMETER_NAMES = {"none",
44 "blue",
45 "blue2",
46 "blue3",
47 "colored",
48 "green",
49 "green2",
50 "green3",
51 "orange",
52 "orange2",
53 "orange3",
54 "red",
55 "red2",
56 "red3",
57 "skin",
58 "white",
59 "yellow",
60 "yellow2",
61 "yellow3"};
62
63const std::string HsvColorSegmentationWidgetController::DEFAULT_COLOR_PARAMETER_FILE =
64 // "armarx/VisionX/data/VisionX/examples/colors.txt";
65 "armarx/VisionX/data/VisionX/examples/cebit-colors.txt";
66
68{
69 widget.setupUi(getWidget());
70
71 widget.comboBoxColor->addItems(COLOR_PARAMETER_NAMES);
72 widget.comboBoxColor->setCurrentIndex(0);
73 currentColorIndex = 0;
74
75 autoValues.resize(NUM_PARAMS, 0);
76
77
78 guiAutoCheckBoxes.resize(NUM_PARAMS);
79 guiAutoCheckBoxes[HUE_MID] = widget.checkBoxAutoHue;
80 guiAutoCheckBoxes[HUE_TOL] = widget.checkBoxAutoHueTol;
81 guiAutoCheckBoxes[SAT_MIN] = widget.checkBoxAutoSatMin;
82 guiAutoCheckBoxes[SAT_MAX] = widget.checkBoxAutoSatMax;
83 guiAutoCheckBoxes[VAL_MIN] = widget.checkBoxAutoValMin;
84 guiAutoCheckBoxes[VAL_MAX] = widget.checkBoxAutoValMax;
85
86 guiValueSpinBoxes.resize(NUM_PARAMS);
87 guiValueSpinBoxes[HUE_MID] = widget.spinBoxHue;
88 guiValueSpinBoxes[HUE_TOL] = widget.spinBoxHueTol;
89 guiValueSpinBoxes[SAT_MIN] = widget.spinBoxSatMin;
90 guiValueSpinBoxes[SAT_MAX] = widget.spinBoxSatMax;
91 guiValueSpinBoxes[VAL_MIN] = widget.spinBoxValMin;
92 guiValueSpinBoxes[VAL_MAX] = widget.spinBoxValMax;
93
94 guiValueSliders.resize(NUM_PARAMS);
95 guiValueSliders[HUE_MID] = widget.sliderHue;
96 guiValueSliders[HUE_TOL] = widget.sliderHueTol;
97 guiValueSliders[SAT_MIN] = widget.sliderSatMin;
98 guiValueSliders[SAT_MAX] = widget.sliderSatMax;
99 guiValueSliders[VAL_MIN] = widget.sliderValMin;
100 guiValueSliders[VAL_MAX] = widget.sliderValMax;
101
102
103 // proxy finder
105 proxyFinder->setSearchMask("*Provider|*Result");
106 widget.layoutChooseProvider->addWidget(proxyFinder);
107
108
109 // image viewer input
110 imageViewerInput = new SelectableImageViewer();
111 QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
112 imageViewerInput->setSizePolicy(sizePolicy);
113
114 widget.layoutImageViewerInput->addWidget(imageViewerInput);
115 imageViewerInput->show();
116
117
118 // image viewer output
119 imageViewerOutput = new visionx::ImageViewerArea();
120 //QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
121 imageViewerOutput->setSizePolicy(sizePolicy);
122
123 widget.layoutImageViewerOutput->addWidget(imageViewerOutput);
124 imageViewerOutput->show();
125
126
127 armarx::CMakePackageFinder finder("VisionX");
128 if (finder.packageFound())
129 {
130 ARMARX_INFO << "Adding to datapaths: " << finder.getDataDir();
132 }
133}
134
138
139void
141{
142 widget.lineEditColorParameterFile->setText(
143 settings->value("ColorParameterFile", getDefaultColorParameterFile()).toString());
145}
146
147void
149{
150 settings->setValue("ColorParameterFile", widget.lineEditColorParameterFile->text());
151}
152
153void
155{
156 proxyFinder->setIceManager(this->getIceManager(),
157 proxyFinder->getSelectedProxyName().isEmpty());
158
159 connected = false;
160 isPaused = true;
161
162 connect(widget.buttonConnect, SIGNAL(clicked(bool)), this, SLOT(clickedButtonConnect(bool)));
163 connect(
164 widget.buttonDisconnect, SIGNAL(clicked(bool)), this, SLOT(clickedButtonDisconnect(bool)));
165 connect(
166 widget.buttonPlayPause, SIGNAL(clicked(bool)), this, SLOT(clickedButtonPlayPause(bool)));
167
168 // image viewer selection
169 connect(imageViewerInput,
170 SIGNAL(selected(int, float, float)),
171 this,
172 SLOT(addColorSelection(int, float, float)));
173 connect(widget.buttonClearSelectedPoints, SIGNAL(pressed()), this, SLOT(clearColorSelection()));
174
175 // COLOR SETTINGS
176
177 connect(widget.buttonColorSettingsReset,
178 SIGNAL(pressed()),
179 this,
181
182 // sliders to manual setters
183 connect(widget.sliderHue, SIGNAL(valueChanged(int)), this, SLOT(setManualHueMid(int)));
184 connect(widget.sliderHueTol, SIGNAL(valueChanged(int)), this, SLOT(setManualHueTol(int)));
185 connect(widget.sliderSatMin, SIGNAL(valueChanged(int)), this, SLOT(setManualSatMin(int)));
186 connect(widget.sliderSatMax, SIGNAL(valueChanged(int)), this, SLOT(setManualSatMax(int)));
187 connect(widget.sliderValMin, SIGNAL(valueChanged(int)), this, SLOT(setManualValMin(int)));
188 connect(widget.sliderValMax, SIGNAL(valueChanged(int)), this, SLOT(setManualValMax(int)));
189
190 // spin boxes to manual setters
191 connect(widget.spinBoxHue, SIGNAL(valueChanged(int)), this, SLOT(setManualHueMid(int)));
192 connect(widget.spinBoxHueTol, SIGNAL(valueChanged(int)), this, SLOT(setManualHueTol(int)));
193 connect(widget.spinBoxSatMin, SIGNAL(valueChanged(int)), this, SLOT(setManualSatMin(int)));
194 connect(widget.spinBoxSatMax, SIGNAL(valueChanged(int)), this, SLOT(setManualSatMax(int)));
195 connect(widget.spinBoxValMin, SIGNAL(valueChanged(int)), this, SLOT(setManualValMin(int)));
196 connect(widget.spinBoxValMax, SIGNAL(valueChanged(int)), this, SLOT(setManualValMax(int)));
197
198 // check boxes to auto setters
199 connect(
200 widget.checkBoxAutoAll, SIGNAL(toggled(bool)), this, SLOT(onToggledCheckBoxAutoAll(bool)));
201 connect(widget.checkBoxAutoHue, SIGNAL(toggled(bool)), this, SLOT(onToggledCheckBoxAuto(bool)));
202 connect(
203 widget.checkBoxAutoHueTol, SIGNAL(toggled(bool)), this, SLOT(onToggledCheckBoxAuto(bool)));
204 connect(
205 widget.checkBoxAutoSatMin, SIGNAL(toggled(bool)), this, SLOT(onToggledCheckBoxAuto(bool)));
206 connect(
207 widget.checkBoxAutoSatMax, SIGNAL(toggled(bool)), this, SLOT(onToggledCheckBoxAuto(bool)));
208 connect(
209 widget.checkBoxAutoValMin, SIGNAL(toggled(bool)), this, SLOT(onToggledCheckBoxAuto(bool)));
210 connect(
211 widget.checkBoxAutoValMax, SIGNAL(toggled(bool)), this, SLOT(onToggledCheckBoxAuto(bool)));
212
213 connect(
214 widget.spinBoxAddTol, SIGNAL(valueChanged(int)), this, SLOT(onChangedAddTolerance(int)));
215
216
217 // color selection
218
219 connect(widget.comboBoxColor,
220 SIGNAL(currentIndexChanged(int)),
221 this,
222 SLOT(onColorIndexChanged(int)));
223 connect(widget.buttonColorParameterFileSearch,
224 SIGNAL(pressed()),
225 this,
227 connect(widget.buttonColorParameterFileReset,
228 SIGNAL(pressed()),
229 this,
231 connect(widget.buttonColorParametersReload,
232 SIGNAL(pressed()),
233 this,
235 connect(widget.buttonColorParametersSave,
236 SIGNAL(pressed()),
237 this,
239
240
241 // inner connections
242 connect(this, SIGNAL(imageProviderConnected(bool)), this, SLOT(updateImageMonitorUI()));
243
244
247}
248
249void
253
254void
258
259void
263
264void
265HsvColorSegmentationWidgetController::reconnect()
266{
267 std::unique_lock lock(imageMutex);
268
269 disconnectFromProvider();
270
271 // connect to provider
272 try
273 {
274 connectToProvider();
275 }
276 catch (...)
277 {
279 }
280}
281
282void
283HsvColorSegmentationWidgetController::connectToProvider()
284{
285 if (connected)
286 {
287 return;
288 }
289
290 std::unique_lock lock(imageMutex);
291
292 imageProviderName = proxyFinder->getSelectedProxyName().toStdString();
293 ARMARX_INFO << "Trying to connect to provider " << imageProviderName;
294
295 usingImageProvider(imageProviderName);
296
297 ARMARX_INFO << getName() << " connecting to " << imageProviderName;
298
299 // connect to proxy
300 imageProviderInfo =
301 getImageProvider(imageProviderName, visionx::tools::typeNameToImageType("rgb"));
302
303 int width = imageProviderInfo.imageFormat.dimension.width;
304 int height = imageProviderInfo.imageFormat.dimension.height;
305
306 segmentation = HsvImageSegmentation(imageProviderInfo);
307
308 bool makeResultImageNamePretty = false;
309 std::string managedIceObjectName;
310 if (makeResultImageNamePretty)
311 {
312 managedIceObjectName = getName();
314 }
315
316 ARMARX_INFO << "Enabling result images";
317 enableResultImages(numImages, visionx::ImageDimension(width, height), visionx::ImageType::eRgb);
318
319 if (makeResultImageNamePretty)
320 {
321 setName(managedIceObjectName);
322 }
323
324 isPaused = false;
325 connected = true;
326
327 emit imageProviderConnected(true);
328}
329
330void
331HsvColorSegmentationWidgetController::disconnectFromProvider()
332{
333 if (!connected)
334 {
335 return;
336 }
337
338 ARMARX_WARNING << "ImageProcessor does not allow re-enabling result images. "
339 "If you connect to another image provider, there might be "
340 "errors in the result images due to different image formats.";
341
342 ARMARX_INFO << "Disconnecting from provider " << imageProviderName;
343
344 std::unique_lock lock(imageMutex);
345 segmentation = HsvImageSegmentation();
346
347 releaseImageProvider(imageProviderName);
348
349 imageProviderPrx = 0;
350
351 connected = false;
352 isPaused = true;
353
354 emit imageProviderConnected(false);
355}
356
357void
359{
360 std::unique_lock lock(imageMutex);
361
362 if (!lock.owns_lock())
363 {
364 ARMARX_INFO << deactivateSpam(3) << "unable to process next image(" << lock.owns_lock()
365 << ")";
366 return;
367 }
368
369 if (!connected)
370 {
371 ARMARX_INFO << deactivateSpam(3) << "Not connected to any image provider";
372 return;
373 }
374
375 armarx::MetaInfoSizeBasePtr info;
376 IceUtil::Time timeReceived;
377 if (!isPaused)
378 {
379 //only update current image if unpaused
380 if (!waitForImages(imageProviderName))
381 {
382 ARMARX_WARNING << "Timeout while waiting for images";
383 return;
384 }
385
386 if (getImages(imageProviderName, segmentation.getInputImagesRgb(), info) != numImages)
387 {
388 ARMARX_WARNING << "Unable to transfer or read images";
389 return;
390 }
391 timeReceived = TimeUtil::GetTime();
392 }
393
394 // perform segmentation
395 segmentation.processInputImages(value(HUE_MID),
396 value(HUE_TOL),
397 value(SAT_MIN),
398 value(SAT_MAX),
399 value(VAL_MIN),
400 value(VAL_MAX));
401
402 // draw selected points on current input images
403 drawSelectedPoints();
404
405 // update image viewers
406 imageViewerInput->setImages(numImages,
407 segmentation.getInputVisuImages(),
408 IceUtil::Time::microSeconds(info->timeProvided),
409 timeReceived);
410 imageViewerOutput->setImages(numImages,
411 segmentation.getOutputImagesRgb(),
412 IceUtil::Time::microSeconds(info->timeProvided),
413 timeReceived);
414
415 // publish results
416 provideResultImages(segmentation.getOutputImagesRgb());
417}
418
419void
421{
422 reconnect();
423}
424
425void
427{
428 disconnectFromProvider();
429}
430
431void
433{
434 if (!connected)
435 {
436 isPaused = false;
437 }
438 else
439 {
440 isPaused = !isPaused;
441 }
443}
444
445void
447{
448 if (!connected)
449 {
450 return;
451 }
452
453 // lookup pixel value in respective image
454
455 int red, green, blue;
456 {
457 std::unique_lock lock(imageMutex);
458
459 CByteImage* image = segmentation.getInputImagesRgb()[imageIndex];
460 int col = image->width * x;
461 int row = image->height * y;
462
463 if (image->type != CByteImage::eRGB24)
464 {
465 ARMARX_WARNING << "Input image type is not eRGB24 (is " << image->type << " instead of "
466 << CByteImage::eRGB24 << ")";
467 }
468
469 int pixelIndex = 0;
470 pixelIndex += row * image->width * image->bytesPerPixel; // skip rows
471 pixelIndex += col * image->bytesPerPixel; // skip columns in row
472
473 red = image->pixels[pixelIndex];
474 green = image->pixels[pixelIndex + 1];
475 blue = image->pixels[pixelIndex + 2];
476 }
477
478
479 // convert to HSV and store point
480
481 SelectedPoint sp(imageIndex, x, y, red, green, blue);
482
483 selectedPoints.push_back(sp);
484
485 // update
486 onSelectedPointsChanged();
487}
488
489void
491{
492 selectedPoints.clear();
493 onSelectedPointsChanged();
494}
495
496void
498{
499 if (dirtyColors.find(widget.comboBoxColor->currentIndex()) == dirtyColors.end())
500 {
501 markCurrentColorDirty();
502 }
503
504 updateColorVisualization();
505
506 widget.buttonColorParametersSave->setText("Save");
507}
508
509void
511{
512 saveCurrentColorParameters(currentColorIndex);
513 loadCurrentColorParameters(value);
514 currentColorIndex = value;
515}
516
517void
519{
520 guiAutoCheckBoxes[HUE_MID]->setChecked(false);
522}
523
524void
526{
527 guiAutoCheckBoxes[HUE_TOL]->setChecked(false);
529}
530
531void
533{
534 guiAutoCheckBoxes[SAT_MIN]->setChecked(false);
536}
537
538void
540{
541 guiAutoCheckBoxes[SAT_MAX]->setChecked(false);
543}
544
545void
547{
548 guiAutoCheckBoxes[VAL_MIN]->setChecked(false);
550}
551
552void
554{
555 guiAutoCheckBoxes[VAL_MAX]->setChecked(false);
557}
558
559void
561{
562 widget.checkBoxAutoHue->setChecked(enabled);
563 widget.checkBoxAutoHueTol->setChecked(enabled);
564 widget.checkBoxAutoSatMin->setChecked(enabled);
565 widget.checkBoxAutoSatMax->setChecked(enabled);
566 widget.checkBoxAutoValMin->setChecked(enabled);
567 widget.checkBoxAutoValMax->setChecked(enabled);
568
569 onToggledCheckBoxAuto(enabled);
570}
571
572void
574{
575 if (enabled)
576 {
577 updateAutoValuesUI();
579 }
580}
581
582void
584{
585 recomputeAutoValues();
586 updateAutoValuesUI();
587}
588
589void
591{
592 loadCurrentColorParameters(widget.comboBoxColor->currentIndex());
593}
594
595void
597{
598 if (showMsgBoxes && !dirtyColors.empty())
599 {
600 QMessageBox msgBox;
601 msgBox.setText("Unsaved changes");
602 std::stringstream infText;
603 infText << "There are colors with unsaved changes: \n\n";
604 for (int i : dirtyColors)
605 {
606 infText << COLOR_PARAMETER_NAMES.at(i).toStdString() << " ";
607 }
608 infText << "\n\nAre you sure to discard these changes?";
609
610 msgBox.setInformativeText(QString::fromStdString(infText.str()));
611 msgBox.setIcon(QMessageBox::Question);
612 msgBox.setStandardButtons(QMessageBox::Discard | QMessageBox::Cancel);
613 msgBox.setDefaultButton(QMessageBox::Discard);
614 int option = msgBox.exec();
615 if (option == QMessageBox::Cancel)
616 {
617 return; // cancel
618 }
619 }
620
621 std::string fileName = colorParameterFile();
622 if (!ArmarXDataPath::getAbsolutePath(fileName, fileName))
623 {
624 ARMARX_WARNING << "Could not find color parameter file in ArmarXDataPath: " << fileName;
625 }
626
627 bool success = colorParameterSet.LoadFromFile(fileName.c_str());
628 if (!success)
629 {
630 if (showMsgBoxes)
631 {
632 std::stringstream text;
633 text << "Failed to load color parameters from file:\n\n"
634 << "" << fileName << "\n\n"
635 << "Please check whether the file exists and is readable.";
636
637 QMessageBox msgBox;
638 msgBox.setText("Could not load color parameters.");
639 msgBox.setInformativeText(QString::fromStdString(text.str()));
640 msgBox.setIcon(QMessageBox::Warning);
641 msgBox.exec();
642 }
643
644
645 return;
646 }
647
648 widget.lineEditColorParameterFile->setText(QString::fromStdString(fileName));
649 loadCurrentColorParameters(widget.comboBoxColor->currentIndex());
650
651 markAllColorsClean();
652}
653
654void
656{
657 saveCurrentColorParameters(widget.comboBoxColor->currentIndex());
658
659 bool success = colorParameterSet.SaveToFile(colorParameterFile().c_str());
660 if (!success)
661 {
662 std::stringstream text;
663 text << "Failed to save color parameters to file:\n\n"
664 << "" << colorParameterFile() << "\n\n"
665 << "Please check whether the file is writable.";
666
667 QMessageBox msgBox;
668 msgBox.setText("Could not save color parameters.");
669 msgBox.setInformativeText(QString::fromStdString(text.str()));
670 msgBox.setIcon(QMessageBox::Warning);
671 msgBox.exec();
672
673 return;
674 }
675
676 markAllColorsClean();
677 widget.buttonColorParametersSave->setText("Saved");
678}
679
680void
682{
683 QString selectedFile = QFileDialog::getOpenFileName(widget.buttonColorParameterFileSearch,
684 tr("Choose Color Parameter File"),
685 widget.lineEditColorParameterFile->text());
686
687 if (!selectedFile.isNull())
688 {
689 widget.lineEditColorParameterFile->setText(selectedFile);
690 }
691}
692
693void
695{
696 widget.lineEditColorParameterFile->setText(getDefaultColorParameterFile());
697}
698
699int
700HsvColorSegmentationWidgetController::value(int param)
701{
702 return guiValueSpinBoxes[param]->value();
703}
704
705int
706HsvColorSegmentationWidgetController::hueMin()
707{
708 return std::max(0, value(HUE_MID) - value(HUE_TOL));
709}
710
711int
712HsvColorSegmentationWidgetController::hueMax()
713{
714 return std::min(179, value(HUE_MID) + value(HUE_TOL));
715}
716
717int
718HsvColorSegmentationWidgetController::satMid()
719{
720 return 0.5 * (value(SAT_MIN) + value(SAT_MAX));
721}
722
723int
724HsvColorSegmentationWidgetController::valMid()
725{
726 return 0.5 * (value(VAL_MIN) + value(VAL_MAX));
727}
728
729bool
730HsvColorSegmentationWidgetController::isAutoEnabled(int param)
731{
732 return guiAutoCheckBoxes[param]->isChecked();
733}
734
735int
736HsvColorSegmentationWidgetController::additionalTolerance()
737{
738 return widget.spinBoxAddTol->value();
739}
740
741std::string
742HsvColorSegmentationWidgetController::colorParameterFile()
743{
744 return widget.lineEditColorParameterFile->text().toStdString();
745}
746
747void
748HsvColorSegmentationWidgetController::recomputeAutoValues()
749{
750 for (int i = 0; i < NUM_PARAMS; ++i)
751 {
752 autoValues[i] = 0;
753 }
754
755 if (selectedPoints.empty())
756 {
757 return; // all 0
758 }
759
760 // compute minima and maxima
761
762 // trigger min() in first element by setting mins to 255
763 int hueMin = 179;
764 int hueMax = 0;
765 autoValues[SAT_MIN] = 255;
766 autoValues[VAL_MIN] = 255;
767
768 auto setMin = [](int& target, int compare) { target = std::min(target, compare); };
769 auto setMax = [](int& target, int compare) { target = std::max(target, compare); };
770
771 for (SelectedPoint& p : selectedPoints)
772 {
773 setMin(hueMin, p.hue);
774 setMax(hueMax, p.hue);
775 setMin(autoValues[SAT_MIN], p.sat);
776 setMax(autoValues[SAT_MAX], p.sat);
777 setMin(autoValues[VAL_MIN], p.val);
778 setMax(autoValues[VAL_MAX], p.val);
779 }
780
781 // correct hue mid and tol
782
783 int hueMid = (hueMin + hueMax) / 2;
784 int hueTol = std::max(hueMax - hueMid, hueMid - hueMin);
785
786 autoValues[HUE_MID] = hueMid;
787 autoValues[HUE_TOL] = hueTol;
788
789
790 // add / subtract additional tolerance
791 int tolerance = additionalTolerance();
792
793 auto clampedAdd = [](int& target, int addSub, int maxMin)
794 {
795 if (addSub > 0)
796 {
797 target = std::min(target + addSub, maxMin);
798 }
799 else if (addSub < 0)
800 {
801 target = std::max(target + addSub, maxMin);
802 }
803 };
804
805 clampedAdd(autoValues[HUE_TOL], 2 * tolerance, 179);
806
807 clampedAdd(autoValues[SAT_MIN], -tolerance, 0);
808 clampedAdd(autoValues[SAT_MAX], tolerance, 255);
809
810 clampedAdd(autoValues[VAL_MIN], -tolerance, 0);
811 clampedAdd(autoValues[VAL_MAX], tolerance, 255);
812}
813
814void
815HsvColorSegmentationWidgetController::onSelectedPointsChanged()
816{
817 recomputeAutoValues();
818 updateAutoValuesUI();
819
820 std::stringstream num;
821 num << selectedPoints.size();
822 widget.labelSelectedPointsNum->setText(QString(num.str().c_str()));
823
825}
826
827void
828HsvColorSegmentationWidgetController::drawSelectedPoints()
829{
830 CByteImage** inputVisuImages = segmentation.getInputVisuImages();
831
832 int radius = 20;
833 for (SelectedPoint& sp : selectedPoints)
834 {
835 CByteImage* image = inputVisuImages[sp.imageIndex];
836 PrimitivesDrawer::DrawCircle(image,
837 sp.xRel * image->width,
838 sp.yRel * image->height,
839 radius,
840 sp.red,
841 sp.green,
842 sp.blue,
843 -1); // fill
844
845 PrimitivesDrawer::DrawCircle(
846 image, sp.xRel * image->width, sp.yRel * image->height, radius, 0, 0, 0, 2); // border
847 }
848}
849
850void
851HsvColorSegmentationWidgetController::saveCurrentColorParameters(int colorIndex)
852{
853 std::string colorName = COLOR_PARAMETER_NAMES.at(colorIndex).toStdString();
854
855 ObjectColor objectColor = CColorParameterSet::Translate(colorName.c_str());
856
857 colorParameterSet.SetColorParameters(objectColor,
858 value(HUE_MID),
859 value(HUE_TOL),
860 value(SAT_MIN),
861 value(SAT_MAX),
862 value(VAL_MIN),
863 value(VAL_MAX));
864}
865
866void
867HsvColorSegmentationWidgetController::loadCurrentColorParameters(int colorIndex)
868{
869 // setting the new values will cause the new color to be marked dirty
870 // we have to check beforehand and restore the marker afterwards
871 bool isDirty = dirtyColors.find(colorIndex) != dirtyColors.end();
872
873 std::string colorName = COLOR_PARAMETER_NAMES.at(colorIndex).toStdString();
874
875 ObjectColor objectColor = CColorParameterSet::Translate(colorName.c_str());
876
877 const int* params = colorParameterSet.GetColorParameters(objectColor);
878
879 widget.spinBoxHue->setValue(params[0]);
880 widget.spinBoxHueTol->setValue(params[1]);
881 widget.spinBoxSatMin->setValue(params[2]);
882 widget.spinBoxSatMax->setValue(params[3]);
883 widget.spinBoxValMin->setValue(params[4]);
884 widget.spinBoxValMax->setValue(params[5]);
885
886 widget.checkBoxAutoAll->setChecked(false);
887
888 if (isDirty)
889 {
890 markCurrentColorDirty();
891 }
892 else
893 {
894 markCurrentColorClean();
895 }
896}
897
898void
899HsvColorSegmentationWidgetController::updatePausePlayButtonText()
900{
901 const char* text = isPaused ? "Play" : "Pause";
902 widget.buttonPlayPause->setText(text);
903}
904
905void
907{
908 updatePausePlayButtonText();
909
910 widget.buttonDisconnect->setEnabled(connected);
911 widget.buttonPlayPause->setEnabled(connected);
912
913 QString statusString;
914 if (connected)
915 {
916 std::stringstream ss;
917 ss << "Status: connected to image provider \n" << imageProviderName;
918 ss << " (" << numImages << " imgs, " << imageWidth << "x" << imageHeight << ")";
919
920 if (isPaused)
921 {
922 ss << " - PAUSED";
923 }
924 statusString = QString::fromStdString(ss.str());
925 }
926 else
927 {
928 statusString = "Status: not connected";
929 }
930 widget.labelImageMonitorStatus->setText(statusString);
931}
932
933void
934HsvColorSegmentationWidgetController::setUiParamValue(int param, int value)
935{
936 guiValueSpinBoxes[param]->setValue(value);
937 guiValueSliders[param]->setValue(value);
938}
939
940void
941HsvColorSegmentationWidgetController::updateAutoValuesUI()
942{
943 for (int i = 0; i < NUM_PARAMS; ++i)
944 {
945 if (isAutoEnabled(i))
946 {
947 setUiParamValue(i, autoValues[i]);
948 guiAutoCheckBoxes[i]->setChecked(true);
949 }
950 }
951}
952
953void
954HsvColorSegmentationWidgetController::updateColorVisualization()
955{
956 // mid color preview
957
958 QPalette previewPalette = widget.labelColorPreview->palette();
959 previewPalette.setColor(QPalette::Background,
960 QColor::fromHsv(value(HUE_MID), satMid(), valMid()));
961 widget.labelColorPreview->setPalette(previewPalette);
962
963
964 // gradients
965
966 // create gradians
967 QLinearGradient gradHue = QLinearGradient(0, 0, 0, widget.labelGradHue->height());
968 QLinearGradient gradSat = QLinearGradient(0, 0, 0, widget.labelGradSat->height());
969 QLinearGradient gradVal = QLinearGradient(0, 0, 0, widget.labelGradVal->height());
970
971 // set gradians
972 int numHueSamples = 10;
973 int hMin = hueMin();
974 int hMax = hueMax();
975 for (int i = 0; i <= numHueSamples; ++i)
976 {
977 float interpol = float(i) / numHueSamples;
978 int value = int(hMin * (1 - interpol) + hMax * interpol);
979 // Qt uses a hue range of 0-359
980 gradHue.setColorAt(interpol, QColor::fromHsv(2 * value, 255, 255));
981 }
982
983 gradSat.setColorAt(0, QColor::fromHsv(value(HUE_MID), value(SAT_MIN), 255));
984 gradSat.setColorAt(1, QColor::fromHsv(value(HUE_MID), value(SAT_MAX), 255));
985
986 gradVal.setColorAt(0, QColor::fromHsv(0, 0, value(VAL_MIN)));
987 gradVal.setColorAt(1, QColor::fromHsv(0, 0, value(VAL_MAX)));
988
989
990 // assignGradients
991 auto setGradient = [](QLabel* label, const QLinearGradient& gradient)
992 {
993 QPalette palette = label->palette();
994 palette.setBrush(QPalette::Background, gradient);
995 label->setPalette(palette);
996 };
997
998 setGradient(widget.labelGradHue, gradHue);
999 setGradient(widget.labelGradSat, gradSat);
1000 setGradient(widget.labelGradVal, gradVal);
1001}
1002
1003void
1004HsvColorSegmentationWidgetController::markCurrentColorDirty()
1005{
1006 int idx = widget.comboBoxColor->currentIndex();
1007 QString newText = COLOR_PARAMETER_NAMES.at(idx) + "*";
1008 widget.comboBoxColor->setItemText(idx, newText);
1009
1010 dirtyColors.insert(idx);
1011}
1012
1013void
1014HsvColorSegmentationWidgetController::markCurrentColorClean()
1015{
1016 int idx = widget.comboBoxColor->currentIndex();
1017 widget.comboBoxColor->setItemText(idx, COLOR_PARAMETER_NAMES.at(idx));
1018 dirtyColors.erase(idx);
1019}
1020
1021void
1022HsvColorSegmentationWidgetController::markAllColorsClean()
1023{
1024 for (int i = 0; i < widget.comboBoxColor->count(); ++i)
1025 {
1026 widget.comboBoxColor->setItemText(i, COLOR_PARAMETER_NAMES.at(i));
1027 }
1028 dirtyColors.clear();
1029}
1030
1031void
1032HsvColorSegmentationWidgetController::rgbToHsv(int r, int g, int b, int& h, int& s, int& v)
1033{
1034 // let ivt convert an 1x1 pixel image...
1035
1036 CByteImage rgb(1, 1, CByteImage::eRGB24);
1037 CByteImage hsv(1, 1, CByteImage::eRGB24);
1038
1039 rgb.pixels[0] = r;
1040 rgb.pixels[1] = g;
1041 rgb.pixels[2] = b;
1042
1043 ::ImageProcessor::CalculateHSVImage(&rgb, &hsv);
1044
1045 h = hsv.pixels[0];
1046 s = hsv.pixels[1];
1047 v = hsv.pixels[2];
1048}
1049
1050std::string
1051HsvColorSegmentationWidgetController::getHomeDirectory()
1052{
1053 // check HOME environment variable
1054 char* homeDir = getenv("HOME");
1055
1056 if (!homeDir)
1057 {
1058 // HOME not set
1059 passwd* pw = getpwuid(getuid());
1060 homeDir = pw->pw_dir;
1061 }
1062
1063 return std::string(homeDir);
1064}
1065
1066QString
1067HsvColorSegmentationWidgetController::getDefaultColorParameterFile()
1068{
1069 std::stringstream path;
1070 path << getHomeDirectory();
1071 path << "/" << DEFAULT_COLOR_PARAMETER_FILE;
1072
1073 return QString::fromStdString(path.str());
1074}
#define float
Definition 16_Level.h:22
#define option(type, fn)
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
static bool getAbsolutePath(const std::string &relativeFilename, std::string &storeAbsoluteFilename, const std::vector< std::string > &additionalSearchPaths={}, bool verbose=true)
static void addDataPaths(const std::string &dataPathList)
virtual QPointer< QWidget > getWidget()
getWidget returns a pointer to the a widget of this controller.
The CMakePackageFinder class provides an interface to the CMake Package finder capabilities.
bool packageFound() const
Returns whether or not this package was found with cmake.
virtual void onConnectImageProcessor() override
Implement this method in the ImageProcessor in order execute parts when the component is fully initia...
virtual void onExitImageProcessor() override
Exit the ImapeProcessor component.
virtual void process() override
Process the vision component.
void loadColorParameterSetFromFile(bool showMsgBoxes=true)
Loads the color parameter set from file and update the gui.
virtual void onInitImageProcessor() override
Setup the vision component.
virtual void onDisconnectImageProcessor() override
Implement this method in the ImageProcessor in order execute parts when the component looses network ...
static QString GetWidgetName()
Returns the Widget name displayed in the ArmarXGui to create an instance of this class.
Widget to conveniently retrieve a proxy instance name of a specific interface type (the template para...
std::string getName() const
Retrieve name of object.
IceManagerPtr getIceManager() const
Returns the IceManager.
void setName(std::string name)
Override name of well-known object.
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition TimeUtil.cpp:42
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
void releaseImageProvider(std::string providerName)
#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
double s(double t, double s0, double v0, double a0, double j)
Definition CtrlUtil.h:33
double v(double t, double v0, double a0, double j)
Definition CtrlUtil.h:39
int compare(const T &lhs, const T &rhs)
This file offers overloads of toIce() and fromIce() functions for STL container types.
void handleExceptions()
QColor green()
Definition StyleSheets.h:72
QColor red()
Definition StyleSheets.h:78
Vertex target(const detail::edge_base< Directed, Vertex > &e, const PCG &)
ImageType typeNameToImageType(const std::string &imageTypeName)
Converts an image type name as string into an ImageType integer.