30 #include <QFileDialog>
31 #include <QMessageBox>
34 #include <Image/PrimitivesDrawer.h>
36 #include <VisionX/interface/core/ImageProviderInterface.h>
43 const QStringList HsvColorSegmentationWidgetController::COLOR_PARAMETER_NAMES =
45 "none",
"blue",
"blue2",
"blue3",
"colored",
"green",
"green2",
"green3",
46 "orange",
"orange2",
"orange3",
"red",
"red2",
"red3",
"skin",
"white",
47 "yellow",
"yellow2",
"yellow3"
50 const std::string HsvColorSegmentationWidgetController::DEFAULT_COLOR_PARAMETER_FILE =
52 "armarx/VisionX/data/VisionX/examples/cebit-colors.txt";
60 widget.comboBoxColor->addItems(COLOR_PARAMETER_NAMES);
61 widget.comboBoxColor->setCurrentIndex(0);
62 currentColorIndex = 0;
64 autoValues.resize(NUM_PARAMS, 0);
67 guiAutoCheckBoxes.resize(NUM_PARAMS);
68 guiAutoCheckBoxes[HUE_MID] = widget.checkBoxAutoHue;
69 guiAutoCheckBoxes[HUE_TOL] = widget.checkBoxAutoHueTol;
70 guiAutoCheckBoxes[SAT_MIN] = widget.checkBoxAutoSatMin;
71 guiAutoCheckBoxes[SAT_MAX] = widget.checkBoxAutoSatMax;
72 guiAutoCheckBoxes[VAL_MIN] = widget.checkBoxAutoValMin;
73 guiAutoCheckBoxes[VAL_MAX] = widget.checkBoxAutoValMax;
75 guiValueSpinBoxes.resize(NUM_PARAMS);
76 guiValueSpinBoxes[HUE_MID] = widget.spinBoxHue;
77 guiValueSpinBoxes[HUE_TOL] = widget.spinBoxHueTol;
78 guiValueSpinBoxes[SAT_MIN] = widget.spinBoxSatMin;
79 guiValueSpinBoxes[SAT_MAX] = widget.spinBoxSatMax;
80 guiValueSpinBoxes[VAL_MIN] = widget.spinBoxValMin;
81 guiValueSpinBoxes[VAL_MAX] = widget.spinBoxValMax;
83 guiValueSliders.resize(NUM_PARAMS);
84 guiValueSliders[HUE_MID] = widget.sliderHue;
85 guiValueSliders[HUE_TOL] = widget.sliderHueTol;
86 guiValueSliders[SAT_MIN] = widget.sliderSatMin;
87 guiValueSliders[SAT_MAX] = widget.sliderSatMax;
88 guiValueSliders[VAL_MIN] = widget.sliderValMin;
89 guiValueSliders[VAL_MAX] = widget.sliderValMax;
94 proxyFinder->setSearchMask(
"*Provider|*Result");
95 widget.layoutChooseProvider->addWidget(proxyFinder);
100 QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
101 imageViewerInput->setSizePolicy(sizePolicy);
103 widget.layoutImageViewerInput->addWidget(imageViewerInput);
104 imageViewerInput->show();
110 imageViewerOutput->setSizePolicy(sizePolicy);
112 widget.layoutImageViewerOutput->addWidget(imageViewerOutput);
113 imageViewerOutput->show();
133 widget.lineEditColorParameterFile->setText(settings->value(
"ColorParameterFile", getDefaultColorParameterFile()).
toString());
139 settings->setValue(
"ColorParameterFile", widget.lineEditColorParameterFile->text());
145 proxyFinder->setIceManager(this->
getIceManager(), proxyFinder->getSelectedProxyName().isEmpty());
155 connect(imageViewerInput, SIGNAL(selected(
int,
float,
float)),
this, SLOT(
addColorSelection(
int,
float,
float)));
156 connect(widget.buttonClearSelectedPoints, SIGNAL(pressed()),
this, SLOT(
clearColorSelection()));
163 connect(widget.sliderHue, SIGNAL(valueChanged(
int)),
this, SLOT(
setManualHueMid(
int)));
164 connect(widget.sliderHueTol, SIGNAL(valueChanged(
int)),
this, SLOT(
setManualHueTol(
int)));
165 connect(widget.sliderSatMin, SIGNAL(valueChanged(
int)),
this, SLOT(
setManualSatMin(
int)));
166 connect(widget.sliderSatMax, SIGNAL(valueChanged(
int)),
this, SLOT(
setManualSatMax(
int)));
167 connect(widget.sliderValMin, SIGNAL(valueChanged(
int)),
this, SLOT(
setManualValMin(
int)));
168 connect(widget.sliderValMax, SIGNAL(valueChanged(
int)),
this, SLOT(
setManualValMax(
int)));
171 connect(widget.spinBoxHue, SIGNAL(valueChanged(
int)),
this, SLOT(
setManualHueMid(
int)));
172 connect(widget.spinBoxHueTol, SIGNAL(valueChanged(
int)),
this, SLOT(
setManualHueTol(
int)));
173 connect(widget.spinBoxSatMin, SIGNAL(valueChanged(
int)),
this, SLOT(
setManualSatMin(
int)));
174 connect(widget.spinBoxSatMax, SIGNAL(valueChanged(
int)),
this, SLOT(
setManualSatMax(
int)));
175 connect(widget.spinBoxValMin, SIGNAL(valueChanged(
int)),
this, SLOT(
setManualValMin(
int)));
176 connect(widget.spinBoxValMax, SIGNAL(valueChanged(
int)),
this, SLOT(
setManualValMax(
int)));
192 connect(widget.comboBoxColor, SIGNAL(currentIndexChanged(
int)),
this, SLOT(
onColorIndexChanged(
int)));
223 void HsvColorSegmentationWidgetController::reconnect()
225 std::unique_lock lock(imageMutex);
227 disconnectFromProvider();
240 void HsvColorSegmentationWidgetController::connectToProvider()
247 std::unique_lock lock(imageMutex);
249 imageProviderName = proxyFinder->getSelectedProxyName().toStdString();
250 ARMARX_INFO <<
"Trying to connect to provider " << imageProviderName;
259 int width = imageProviderInfo.
imageFormat.dimension.width;
260 int height = imageProviderInfo.
imageFormat.dimension.height;
264 bool makeResultImageNamePretty =
false;
265 std::string managedIceObjectName;
266 if (makeResultImageNamePretty)
268 managedIceObjectName =
getName();
273 enableResultImages(numImages, visionx::ImageDimension(width, height), visionx::ImageType::eRgb);
275 if (makeResultImageNamePretty)
286 void HsvColorSegmentationWidgetController::disconnectFromProvider()
293 ARMARX_WARNING <<
"ImageProcessor does not allow re-enabling result images. "
294 "If you connect to another image provider, there might be "
295 "errors in the result images due to different image formats.";
297 ARMARX_INFO <<
"Disconnecting from provider " << imageProviderName;
299 std::unique_lock lock(imageMutex);
304 imageProviderPrx = 0;
315 std::unique_lock lock(imageMutex);
317 if (!lock.owns_lock())
329 armarx::MetaInfoSizeBasePtr info;
350 value(SAT_MAX), value(VAL_MIN), value(VAL_MAX));
353 drawSelectedPoints();
356 imageViewerInput->
setImages(numImages, segmentation.
getInputVisuImages(), IceUtil::Time::microSeconds(info->timeProvided), timeReceived);
357 imageViewerOutput->
setImages(numImages, segmentation.
getOutputImagesRgb(), IceUtil::Time::microSeconds(info->timeProvided), timeReceived);
373 disconnectFromProvider();
384 isPaused = !isPaused;
400 std::unique_lock lock(imageMutex);
403 int col = image->width * x;
404 int row = image->height * y;
406 if (image->type != CByteImage::eRGB24)
408 ARMARX_WARNING <<
"Input image type is not eRGB24 (is " << image->type
409 <<
" instead of " << CByteImage::eRGB24 <<
")";
413 pixelIndex += row * image->width * image->bytesPerPixel;
414 pixelIndex += col * image->bytesPerPixel;
416 red = image->pixels[pixelIndex];
417 green = image->pixels[pixelIndex + 1];
418 blue = image->pixels[pixelIndex + 2];
424 SelectedPoint sp(imageIndex, x, y,
red,
green, blue);
426 selectedPoints.push_back(sp);
429 onSelectedPointsChanged();
435 selectedPoints.clear();
436 onSelectedPointsChanged();
441 if (dirtyColors.find(widget.comboBoxColor->currentIndex()) == dirtyColors.end())
443 markCurrentColorDirty();
446 updateColorVisualization();
448 widget.buttonColorParametersSave->setText(
"Save");
453 saveCurrentColorParameters(currentColorIndex);
454 loadCurrentColorParameters(value);
455 currentColorIndex = value;
461 guiAutoCheckBoxes[HUE_MID]->setChecked(
false);
467 guiAutoCheckBoxes[HUE_TOL]->setChecked(
false);
473 guiAutoCheckBoxes[SAT_MIN]->setChecked(
false);
479 guiAutoCheckBoxes[SAT_MAX]->setChecked(
false);
485 guiAutoCheckBoxes[VAL_MIN]->setChecked(
false);
491 guiAutoCheckBoxes[VAL_MAX]->setChecked(
false);
497 widget.checkBoxAutoHue->setChecked(
enabled);
498 widget.checkBoxAutoHueTol->setChecked(
enabled);
499 widget.checkBoxAutoSatMin->setChecked(
enabled);
500 widget.checkBoxAutoSatMax->setChecked(
enabled);
501 widget.checkBoxAutoValMin->setChecked(
enabled);
502 widget.checkBoxAutoValMax->setChecked(
enabled);
511 updateAutoValuesUI();
518 recomputeAutoValues();
519 updateAutoValuesUI();
524 loadCurrentColorParameters(widget.comboBoxColor->currentIndex());
529 if (showMsgBoxes && !dirtyColors.empty())
532 msgBox.setText(
"Unsaved changes");
533 std::stringstream infText;
534 infText <<
"There are colors with unsaved changes: \n\n";
535 for (
int i : dirtyColors)
537 infText << COLOR_PARAMETER_NAMES.at(i).toStdString() <<
" ";
539 infText <<
"\n\nAre you sure to discard these changes?";
541 msgBox.setInformativeText(QString::fromStdString(infText.str()));
542 msgBox.setIcon(QMessageBox::Question);
543 msgBox.setStandardButtons(QMessageBox::Discard | QMessageBox::Cancel);
544 msgBox.setDefaultButton(QMessageBox::Discard);
545 int option = msgBox.exec();
546 if (
option == QMessageBox::Cancel)
552 std::string fileName = colorParameterFile();
555 ARMARX_WARNING <<
"Could not find color parameter file in ArmarXDataPath: " << fileName;
558 bool success = colorParameterSet.LoadFromFile(fileName.c_str());
563 std::stringstream text;
564 text <<
"Failed to load color parameters from file:\n\n"
565 <<
"" << fileName <<
"\n\n"
566 <<
"Please check whether the file exists and is readable.";
569 msgBox.setText(
"Could not load color parameters.");
570 msgBox.setInformativeText(QString::fromStdString(text.str()));
571 msgBox.setIcon(QMessageBox::Warning);
579 widget.lineEditColorParameterFile->setText(QString::fromStdString(fileName));
580 loadCurrentColorParameters(widget.comboBoxColor->currentIndex());
582 markAllColorsClean();
587 saveCurrentColorParameters(widget.comboBoxColor->currentIndex());
589 bool success = colorParameterSet.SaveToFile(colorParameterFile().c_str());
592 std::stringstream text;
593 text <<
"Failed to save color parameters to file:\n\n"
594 <<
"" << colorParameterFile() <<
"\n\n"
595 <<
"Please check whether the file is writable.";
598 msgBox.setText(
"Could not save color parameters.");
599 msgBox.setInformativeText(QString::fromStdString(text.str()));
600 msgBox.setIcon(QMessageBox::Warning);
606 markAllColorsClean();
607 widget.buttonColorParametersSave->setText(
"Saved");
612 QString selectedFile = QFileDialog::getOpenFileName(
613 widget.buttonColorParameterFileSearch,
614 tr(
"Choose Color Parameter File"),
615 widget.lineEditColorParameterFile->text());
617 if (!selectedFile.isNull())
619 widget.lineEditColorParameterFile->setText(selectedFile);
625 widget.lineEditColorParameterFile->setText(getDefaultColorParameterFile());
629 int HsvColorSegmentationWidgetController::value(
int param)
631 return guiValueSpinBoxes[param]->value();
634 int HsvColorSegmentationWidgetController::hueMin()
636 return std::max(0, value(HUE_MID) - value(HUE_TOL));
639 int HsvColorSegmentationWidgetController::hueMax()
641 return std::min(179, value(HUE_MID) + value(HUE_TOL));
644 int HsvColorSegmentationWidgetController::satMid()
646 return 0.5 * (value(SAT_MIN) + value(SAT_MAX));
649 int HsvColorSegmentationWidgetController::valMid()
651 return 0.5 * (value(VAL_MIN) + value(VAL_MAX));
654 bool HsvColorSegmentationWidgetController::isAutoEnabled(
int param)
656 return guiAutoCheckBoxes[param]->isChecked();
659 int HsvColorSegmentationWidgetController::additionalTolerance()
661 return widget.spinBoxAddTol->value();
664 std::string HsvColorSegmentationWidgetController::colorParameterFile()
666 return widget.lineEditColorParameterFile->text().toStdString();
669 void HsvColorSegmentationWidgetController::recomputeAutoValues()
671 for (
int i = 0; i < NUM_PARAMS; ++i)
676 if (selectedPoints.empty())
686 autoValues[SAT_MIN] = 255;
687 autoValues[VAL_MIN] = 255;
698 for (SelectedPoint& p : selectedPoints)
700 setMin(hueMin, p.hue);
701 setMax(hueMax, p.hue);
702 setMin(autoValues[SAT_MIN], p.sat);
703 setMax(autoValues[SAT_MAX], p.sat);
704 setMin(autoValues[VAL_MIN], p.val);
705 setMax(autoValues[VAL_MAX], p.val);
710 int hueMid = (hueMin + hueMax) / 2;
711 int hueTol =
std::max(hueMax - hueMid, hueMid - hueMin);
713 autoValues[HUE_MID] = hueMid;
714 autoValues[HUE_TOL] = hueTol;
718 int tolerance = additionalTolerance();
720 auto clampedAdd = [](
int&
target,
int addSub,
int maxMin)
732 clampedAdd(autoValues[HUE_TOL], 2 * tolerance, 179);
734 clampedAdd(autoValues[SAT_MIN], - tolerance, 0);
735 clampedAdd(autoValues[SAT_MAX], tolerance, 255);
737 clampedAdd(autoValues[VAL_MIN], - tolerance, 0);
738 clampedAdd(autoValues[VAL_MAX], tolerance, 255);
742 void HsvColorSegmentationWidgetController::onSelectedPointsChanged()
744 recomputeAutoValues();
745 updateAutoValuesUI();
747 std::stringstream num;
748 num << selectedPoints.size();
749 widget.labelSelectedPointsNum->setText(QString(num.str().c_str()));
754 void HsvColorSegmentationWidgetController::drawSelectedPoints()
759 for (SelectedPoint& sp : selectedPoints)
761 CByteImage* image = inputVisuImages[sp.imageIndex];
762 PrimitivesDrawer::DrawCircle(
763 image, sp.xRel * image->width, sp.yRel * image->height, radius,
764 sp.red, sp.green, sp.blue, -1);
766 PrimitivesDrawer::DrawCircle(
767 image, sp.xRel * image->width, sp.yRel * image->height, radius,
773 void HsvColorSegmentationWidgetController::saveCurrentColorParameters(
int colorIndex)
775 std::string colorName = COLOR_PARAMETER_NAMES.at(colorIndex).toStdString();
777 ObjectColor objectColor = CColorParameterSet::Translate(colorName.c_str());
779 colorParameterSet.SetColorParameters(objectColor,
780 value(HUE_MID), value(HUE_TOL),
781 value(SAT_MIN), value(SAT_MAX),
782 value(VAL_MIN), value(VAL_MAX));
785 void HsvColorSegmentationWidgetController::loadCurrentColorParameters(
int colorIndex)
789 bool isDirty = dirtyColors.find(colorIndex) != dirtyColors.end();
791 std::string colorName = COLOR_PARAMETER_NAMES.at(colorIndex).toStdString();
793 ObjectColor objectColor = CColorParameterSet::Translate(colorName.c_str());
795 const int* params = colorParameterSet.GetColorParameters(objectColor);
797 widget.spinBoxHue->setValue(params[0]);
798 widget.spinBoxHueTol->setValue(params[1]);
799 widget.spinBoxSatMin->setValue(params[2]);
800 widget.spinBoxSatMax->setValue(params[3]);
801 widget.spinBoxValMin->setValue(params[4]);
802 widget.spinBoxValMax->setValue(params[5]);
804 widget.checkBoxAutoAll->setChecked(
false);
808 markCurrentColorDirty();
812 markCurrentColorClean();
817 void HsvColorSegmentationWidgetController::updatePausePlayButtonText()
819 const char* text = isPaused ?
"Play" :
"Pause";
820 widget.buttonPlayPause->setText(text);
825 updatePausePlayButtonText();
827 widget.buttonDisconnect->setEnabled(connected);
828 widget.buttonPlayPause->setEnabled(connected);
830 QString statusString;
833 std::stringstream ss;
834 ss <<
"Status: connected to image provider \n" << imageProviderName;
835 ss <<
" (" << numImages <<
" imgs, " << imageWidth <<
"x" << imageHeight <<
")";
841 statusString = QString::fromStdString(ss.str());
845 statusString =
"Status: not connected";
847 widget.labelImageMonitorStatus->setText(statusString);
850 void HsvColorSegmentationWidgetController::setUiParamValue(
int param,
int value)
852 guiValueSpinBoxes[param]->setValue(value);
853 guiValueSliders[param]->setValue(value);
856 void HsvColorSegmentationWidgetController::updateAutoValuesUI()
858 for (
int i = 0; i < NUM_PARAMS; ++i)
860 if (isAutoEnabled(i))
862 setUiParamValue(i, autoValues[i]);
863 guiAutoCheckBoxes[i]->setChecked(
true);
868 void HsvColorSegmentationWidgetController::updateColorVisualization()
872 QPalette previewPalette = widget.labelColorPreview->palette();
873 previewPalette.setColor(QPalette::Background, QColor::fromHsv(
value(HUE_MID), satMid(), valMid()));
874 widget.labelColorPreview->setPalette(previewPalette);
880 QLinearGradient gradHue = QLinearGradient(0, 0, 0, widget.labelGradHue->height());
881 QLinearGradient gradSat = QLinearGradient(0, 0, 0, widget.labelGradSat->height());
882 QLinearGradient gradVal = QLinearGradient(0, 0, 0, widget.labelGradVal->height());
885 int numHueSamples = 10;
888 for (
int i = 0; i <= numHueSamples; ++i)
890 float interpol =
float(i) / numHueSamples;
891 int value = int(hMin * (1 - interpol) + hMax * interpol);
893 gradHue.setColorAt(interpol, QColor::fromHsv(2 * value, 255, 255));
896 gradSat.setColorAt(0, QColor::fromHsv(
value(HUE_MID),
value(SAT_MIN), 255));
897 gradSat.setColorAt(1, QColor::fromHsv(
value(HUE_MID),
value(SAT_MAX), 255));
899 gradVal.setColorAt(0, QColor::fromHsv(0, 0,
value(VAL_MIN)));
900 gradVal.setColorAt(1, QColor::fromHsv(0, 0,
value(VAL_MAX)));
904 auto setGradient = [](QLabel * label,
const QLinearGradient & gradient)
906 QPalette palette = label->palette();
907 palette.setBrush(QPalette::Background, gradient);
908 label->setPalette(palette);
911 setGradient(widget.labelGradHue, gradHue);
912 setGradient(widget.labelGradSat, gradSat);
913 setGradient(widget.labelGradVal, gradVal);
916 void HsvColorSegmentationWidgetController::markCurrentColorDirty()
918 int idx = widget.comboBoxColor->currentIndex();
919 QString newText = COLOR_PARAMETER_NAMES.at(idx) +
"*";
920 widget.comboBoxColor->setItemText(idx, newText);
922 dirtyColors.insert(idx);
925 void HsvColorSegmentationWidgetController::markCurrentColorClean()
927 int idx = widget.comboBoxColor->currentIndex();
928 widget.comboBoxColor->setItemText(idx, COLOR_PARAMETER_NAMES.at(idx));
929 dirtyColors.erase(idx);
932 void HsvColorSegmentationWidgetController::markAllColorsClean()
934 for (
int i = 0; i < widget.comboBoxColor->count(); ++i)
936 widget.comboBoxColor->setItemText(i, COLOR_PARAMETER_NAMES.at(i));
941 void HsvColorSegmentationWidgetController::rgbToHsv(
int r,
int g,
int b,
int& h,
int&
s,
int&
v)
945 CByteImage rgb(1, 1, CByteImage::eRGB24);
946 CByteImage hsv(1, 1, CByteImage::eRGB24);
952 ::ImageProcessor::CalculateHSVImage(&rgb, &hsv);
959 std::string HsvColorSegmentationWidgetController::getHomeDirectory()
962 char* homeDir = getenv(
"HOME");
967 passwd* pw = getpwuid(getuid());
968 homeDir = pw->pw_dir;
971 return std::string(homeDir);
974 QString HsvColorSegmentationWidgetController::getDefaultColorParameterFile()
976 std::stringstream path;
977 path << getHomeDirectory();
978 path <<
"/" << DEFAULT_COLOR_PARAMETER_FILE;
980 return QString::fromStdString(path.str());