32#include <VisionX/interface/components/Calibration.h>
36#include <Calibration/StereoCalibration.h>
37#include <DataStructures/DynamicArray.h>
38#include <Image/ImageProcessor.h>
39#include <Image/PrimitivesDrawer.h>
46 qRegisterMetaType<CByteImage**>(
"CByteImage**");
48 QPointer<QWidget> widgetPointer =
getWidget();
49 this->widgetPointer = widgetPointer.data();
51 widget.setupUi(widgetPointer);
55 proxyFinder->setSearchMask(
"*Provider|*Result");
57 widget.chooseProviderLayout->addWidget(proxyFinder);
60 QSizePolicy sizePoli(QSizePolicy::Expanding, QSizePolicy::Expanding);
61 sizePoli.setVerticalStretch(15);
62 imageViewer->setSizePolicy(sizePoli);
64 widget.imageViewerLayout_2->addWidget(imageViewer);
86 proxyFinder->getSelectedProxyName().isEmpty());
88 points = Eigen::ArrayX2f::Zero(4, 2);
89 numSelectedPoints = 0;
93 SIGNAL(selected(
int,
float,
float)),
97 connect(widget.loadFeaturesButton,
98 SIGNAL(clicked(
bool)),
101 connect(widget.saveFeaturesButton,
102 SIGNAL(clicked(
bool)),
109 connect(widget.addFeaturesButton,
110 SIGNAL(clicked(
bool)),
113 connect(widget.clearFeaturesButton,
114 SIGNAL(clicked(
bool)),
117 connect(widget.thresholdSpinBox,
118 SIGNAL(valueChanged(
double)),
122 widget.maxFeatureSpinBox, SIGNAL(valueChanged(
int)),
this, SLOT(
maxFeaturesChanged(
int)));
124 widget.levelSpinBox, SIGNAL(valueChanged(
int)),
this, SLOT(
levelChanged(
int)));
125 connect(widget.minDistanceSpinBox,
126 SIGNAL(valueChanged(
double)),
138 objectFeatureSet =
new CTexturedFeatureSet(
"objectFeatureSet");
139 viewFeatureSet =
new CTexturedFeatureSet(
"viewFeatureSet");
141 featureCalculator =
new CHarrisSIFTFeatureCalculator(0.001, 1, 3500);
147FeatureLearningWidgetController::addFeatures()
150 for (
int i = 0; i < viewFeatureSet->GetSize(); i++)
152 CFeatureEntry* copiedEntry = viewFeatureSet->GetFeature(i)->Clone();
153 Math2d::ApplyHomography(homography, copiedEntry->point, copiedEntry->point);
154 bool addedSuccessfully = objectFeatureSet->AddFeature(copiedEntry,
false);
155 if (addedSuccessfully)
164FeatureLearningWidgetController::clearFeatures()
166 objectFeatureSet->Clear();
171FeatureLearningWidgetController::loadFeatureSet(QString filePath)
173 std::string filePathStr = filePath.toStdString();
174 const char* filePathCStr = filePathStr.c_str();
175 if (!objectFeatureSet->LoadFromFile(filePathCStr))
177 ARMARX_ERROR <<
" could not load feature set from file " << filePath;
178 widget.lastActionInfoLabel->setText(
"Loading features failed!");
182 ARMARX_INFO <<
"loaded feature set with " << objectFeatureSet->GetSize() <<
" features";
185 mySettings.setValue(
"default_load_dir", currentDir.absoluteFilePath(filePath));
187 widget.lastActionInfoLabel->setText(
"Loaded feature set with " +
188 QString::number(objectFeatureSet->GetSize()) +
191 float x = fabsf(2.f * objectFeatureSet->m_3dPoint2.x);
192 float y = fabsf(2.f * objectFeatureSet->m_3dPoint2.y);
193 float z = fabsf(2.f * objectFeatureSet->m_3dPoint2.z);
199 widget.widthLineEdit->setText(QString::number(xInt));
200 widget.heightLineEdit->setText(QString::number(yInt));
201 widget.depthLineEdit->setText(QString::number(zInt));
204 points = Eigen::ArrayX2f::Zero(4, 2);
205 numSelectedPoints = 0;
210FeatureLearningWidgetController::saveFeatureSet(QString filePath,
float w,
float h,
float d)
217 Math3d::SetVec(objectFeatureSet->m_3dPoint1, -w / 2.0f, -h / 2.0f, -d / 2.0f);
218 Math3d::SetVec(objectFeatureSet->m_3dPoint2, w / 2.0f, -h / 2.0f, -d / 2.0f);
219 Math3d::SetVec(objectFeatureSet->m_3dPoint3, w / 2.0f, h / 2.0f, -d / 2.0f);
220 Math3d::SetVec(objectFeatureSet->m_3dPoint4, -w / 2.0f, h / 2.0f, -d / 2.0f);
222 std::string filePathStr = filePath.toStdString();
223 const char* filePathCStr = filePathStr.c_str();
226 if (!objectFeatureSet->SaveToFile(filePathCStr))
228 ARMARX_ERROR <<
" could not save feature set to file " << filePath;
229 widget.lastActionInfoLabel->setText(
"Saving features failed!");
233 ARMARX_INFO <<
" saved feature set with " << objectFeatureSet->GetSize()
234 <<
" features to file " << filePathCStr;
237 std::string matPath = filePath.toStdString();
238 const unsigned int n = matPath.find_last_of(
".dat");
239 matPath.resize(n - 2);
242 CFloatMatrix*
object = createCuboid(w, h, d);
243 object->SaveToFile(matPath.c_str());
247 mySettings.setValue(
"default_save_dir", currentDir.absoluteFilePath(filePath));
248 widget.lastActionInfoLabel->setText(
249 "Saved " + QString::number(objectFeatureSet->GetSize()) +
" features into file");
261 points = Eigen::ArrayX2f::Zero(4, 2);
265 for (
int i = 0; i < numImages; i++)
267 delete cameraImages[i];
270 delete[] cameraImages;
272 delete visualizationImage;
276 delete featureCalculator;
278 delete objectFeatureSet;
279 delete viewFeatureSet;
285SameSide(
const Vec2d& p1,
const Vec2d& p2,
const Vec2d& a,
const Vec2d& b)
287 double ba0 = b.x - a.x;
288 double ba1 = b.y - a.y;
290 double p1a0 = p1.x - a.x;
291 double p1a1 = p1.y - a.y;
293 double p2a0 = p2.x - a.x;
294 double p2a1 = p2.y - a.y;
296 double cp1 = ba0 * p1a1 - ba1 * p1a0;
297 double cp2 = ba0 * p2a1 - ba1 * p2a0;
299 return cp1 * cp2 >= 0;
303PointInPoly(
const Vec2d& p,
const Vec2d& a,
const Vec2d& b,
const Vec2d&
c)
305 return SameSide(p, a, b,
c) && SameSide(p, b, a,
c) && SameSide(p,
c, a, b);
309DistancePointStraightLine(
const Vec2d& a,
const Vec2d& b,
const Vec2d p)
312 Math2d::NormalizeVec(n);
314 return std::fabs(Math2d::ScalarProduct(n, p) - Math2d::ScalarProduct(n, a));
319FeatureLearningWidgetController::updateFeatures()
321 if (numSelectedPoints == 0)
323 viewFeatureSet->Clear();
328 if (numSelectedPoints < 4)
333 Vec2d sourcePoints[4];
335 for (
int i = 0; i < numSelectedPoints; i++)
337 sourcePoints[i].x = points(i, 0) * grayImage->width;
338 sourcePoints[i].y = points(i, 1) * grayImage->height;
341 const float w = widget.widthLineEdit->text().toFloat();
342 const float h = widget.heightLineEdit->text().toFloat();
344 Vec2d targetPoints[4];
345 Math2d::SetVec(targetPoints[0], 0, 0);
346 Math2d::SetVec(targetPoints[1], w, 0);
347 Math2d::SetVec(targetPoints[2], w, h);
348 Math2d::SetVec(targetPoints[3], 0, h);
350 LinearAlgebra::DetermineHomography(sourcePoints, targetPoints, 4, homography,
true);
352 objectFeatureSet->SetCornerPoints(
353 targetPoints[0], targetPoints[1], targetPoints[2], targetPoints[3]);
355 featureCalculatorMutex.lock();
356 CDynamicArray dynamic_array(featureCalculator->GetMaxInterestPoints());
357 const int nFeatures = featureCalculator->CalculateFeatures(grayImage, &dynamic_array);
358 featureCalculatorMutex.unlock();
359 viewFeatureSet->Clear();
361 for (
int i = 0; i < nFeatures; i++)
363 CFeatureEntry* pFeatureEntry = (CFeatureEntry*)dynamic_array.GetElement(i);
365 if (PointInPoly(pFeatureEntry->point, sourcePoints[0], sourcePoints[1], sourcePoints[2]) ||
366 PointInPoly(pFeatureEntry->point, sourcePoints[2], sourcePoints[3], sourcePoints[0]))
368 const double dThreshold = 10;
370 if (DistancePointStraightLine(sourcePoints[0], sourcePoints[1], pFeatureEntry->point) >
372 DistancePointStraightLine(sourcePoints[1], sourcePoints[2], pFeatureEntry->point) >
374 DistancePointStraightLine(sourcePoints[2], sourcePoints[3], pFeatureEntry->point) >
376 DistancePointStraightLine(sourcePoints[3], sourcePoints[0], pFeatureEntry->point) >
379 viewFeatureSet->AddFeature(pFeatureEntry->Clone(),
false);
388FeatureLearningWidgetController::updateSelection()
390 Vec2d sourcePoints[4];
395 for (
int i = 0; i < numSelectedPoints; i++)
397 float relativeX = points(i, 0);
398 float relativeY = points(i, 1);
400 sourcePoints[i].x = relativeX * visualizationImage->width;
401 sourcePoints[i].y = relativeY * visualizationImage->height;
406 if (numSelectedPoints >= 1)
408 PrimitivesDrawer::DrawCircle(visualizationImage, sourcePoints[0], 3, 255, 0, 0, -1);
411 if (numSelectedPoints >= 2)
413 PrimitivesDrawer::DrawCircle(visualizationImage, sourcePoints[1], 3, 255, 0, 0, -1);
414 PrimitivesDrawer::DrawLine(visualizationImage, sourcePoints[0], sourcePoints[1], 0, 0, 255);
417 if (numSelectedPoints >= 3)
419 PrimitivesDrawer::DrawCircle(visualizationImage, sourcePoints[2], 3, 255, 0, 0, -1);
420 PrimitivesDrawer::DrawLine(visualizationImage, sourcePoints[1], sourcePoints[2], 0, 0, 255);
423 if (numSelectedPoints >= 4)
425 PrimitivesDrawer::DrawCircle(visualizationImage, sourcePoints[3], 3, 255, 0, 0, -1);
426 PrimitivesDrawer::DrawLine(visualizationImage, sourcePoints[2], sourcePoints[3], 0, 0, 255);
427 PrimitivesDrawer::DrawLine(visualizationImage, sourcePoints[3], sourcePoints[0], 0, 0, 255);
433 if (numSelectedPoints >= 4)
435 for (
int i = 0; i < viewFeatureSet->GetSize(); i++)
437 const CFeatureEntry* pFeatureEntry = viewFeatureSet->GetFeature(i);
438 PrimitivesDrawer::DrawCircle(
439 visualizationImage, pFeatureEntry->point, 2, 0, 255, 0, -1);
449 std::unique_lock lock(imageMutex);
451 if (!lock.owns_lock())
464 armarx::MetaInfoSizeBasePtr info;
465 IceUtil::Time timeReceived;
474 if (
getImages(imageProviderName, cameraImages, info) != numImages)
483 ::ImageProcessor::ConvertImage(cameraImages[0], grayImage);
484 ::ImageProcessor::CopyImage(cameraImages[0], visualizationImage);
493 CByteImage** images =
new CByteImage* {visualizationImage};
494 imageViewer->setImages(
495 1, images, IceUtil::Time::microSeconds(info->timeProvided), timeReceived);
506 if (numSelectedPoints >= 4)
508 numSelectedPoints = 0;
511 points(numSelectedPoints, 0) =
x;
512 points(numSelectedPoints, 1) = y;
527 QString previousLoadDirectory = mySettings.value(
"default_load_dir").toString();
528 if (previousLoadDirectory ==
"")
530 QString previousSaveDirectory = mySettings.value(
"default_save_dir").toString();
531 if (previousSaveDirectory ==
"")
533 previousLoadDirectory =
"~";
537 previousLoadDirectory = previousSaveDirectory;
540 QString filePath = QFileDialog::getOpenFileName(
541 widgetPointer,
"Load Features", previousLoadDirectory,
"(*.dat)");
542 loadFeatureSet(filePath);
549 if (objectFeatureSet->GetSize() < 1)
551 QMessageBox emptyFeatureSetBox;
552 emptyFeatureSetBox.setText(
"Cannot save empty feature set!");
553 emptyFeatureSetBox.setWindowTitle(
"Feature set empty");
554 emptyFeatureSetBox.exec();
557 float width = widget.widthLineEdit->text().toFloat();
558 float height = widget.heightLineEdit->text().toFloat();
559 float depth = widget.depthLineEdit->text().toFloat();
561 if (width <= 0.f || height <= 0.f || depth <= 0.f)
563 QMessageBox invalidDimensionsBox;
564 invalidDimensionsBox.setText(
"Cannot save feature set with object dimensions <= 0!");
565 invalidDimensionsBox.setWindowTitle(
"Invalid object dimensions");
566 invalidDimensionsBox.exec();
570 QString previousSaveDirectory = mySettings.value(
"default_save_dir").toString();
571 if (previousSaveDirectory ==
"")
573 QString previousLoadDirectory = mySettings.value(
"default_load_dir").toString();
574 if (previousLoadDirectory ==
"")
576 previousSaveDirectory =
"~";
580 previousSaveDirectory = previousLoadDirectory;
583 QString filePath = QFileDialog::getSaveFileName(
584 widgetPointer,
"Save Features", previousSaveDirectory,
"(*.dat)");
585 if (filePath.right(4) !=
".dat")
589 saveFeatureSet(filePath, width, height, depth);
601 isPaused = !isPaused;
603 updateImageMonitorUI();
610 std::unique_lock lock(imageMutex);
612 disconnectFromProvider();
627FeatureLearningWidgetController::connectToProvider()
636 ARMARX_INFO <<
"Trying to connect to provider " << imageProviderName;
642 catch (Ice::NotRegisteredException& e)
644 ARMARX_ERROR <<
"Cannot connect to the given image provider called " << imageProviderName;
646 QMessageBox cannotConnectToProviderBox;
647 QString cannotConnectToProviderString =
648 "Cannot connect to the given image provider called " +
649 QString::fromStdString(imageProviderName);
650 cannotConnectToProviderBox.setText(cannotConnectToProviderString);
651 cannotConnectToProviderBox.setWindowTitle(
"Cannot connect to Image Provider");
652 cannotConnectToProviderBox.exec();
655 catch (armarx::LocalException& e)
657 ARMARX_ERROR <<
"Image Provider field is empty, cannot connect!" << imageProviderName;
659 QMessageBox noProviderGivenBox;
660 QString cannotConnectToProviderString =
661 "Cannot connect to an image provider since the field is empty.";
662 noProviderGivenBox.setText(cannotConnectToProviderString);
663 noProviderGivenBox.setWindowTitle(
"No Provider given");
664 noProviderGivenBox.exec();
675 imageProviderPrx = imageProviderInfo.proxy;
676 numImages = imageProviderInfo.numberImages;
678 StereoCalibrationProviderInterfacePrx calibrationProvider =
679 StereoCalibrationProviderInterfacePrx::checkedCast(imageProviderInfo.proxy);
681 if (!calibrationProvider)
683 ARMARX_WARNING <<
"image provider does not have a stereo calibration interface";
687 undistortImages = calibrationProvider->getImagesAreUndistorted();
688 if (!undistortImages)
690 ARMARX_ERROR <<
"Images expected to be undistorted, but the calibration returns that "
691 "the images are distorted";
700 std::unique_lock lock(imageMutex);
701 cameraImages =
new CByteImage*[numImages];
703 for (
int i = 0; i < numImages; i++)
710 grayImage =
new CByteImage(imageProviderInfo.imageFormat.dimension.width,
711 imageProviderInfo.imageFormat.dimension.height,
712 CByteImage::eGrayScale);
715 timeProvided = IceUtil::Time::seconds(0);
719 updateImageMonitorUI();
728FeatureLearningWidgetController::disconnectFromProvider()
736 std::unique_lock lock(imageMutex);
740 for (
int i = 0; i < numImages; i++)
742 delete cameraImages[i];
745 delete[] cameraImages;
747 delete visualizationImage;
753 imageProviderPrx = 0;
757 numSelectedPoints = 0;
759 QString emptyFeaturesInfoText =
"";
760 widget.lastActionInfoLabel->setText(emptyFeaturesInfoText);
762 updateImageMonitorUI();
769FeatureLearningWidgetController::updatePausePlayButtonText()
773 widget.pausePlayButton->setText(
"Play");
776 widget.pausePlayButton->setText(
"Pause");
780FeatureLearningWidgetController::updateImageMonitorUI()
782 updatePausePlayButtonText();
784 widget.disconnectButton->setEnabled(connected);
785 widget.pausePlayButton->setEnabled(connected);
789 QString providerName = imageProviderName.c_str();
790 QString statusString =
"Status: connected to image provider " + providerName;
793 statusString = statusString +
" - PAUSED";
795 widget.imageMonitorStatusLabel->setText(statusString);
799 widget.imageMonitorStatusLabel->setText(
"Status: not connected");
806 disconnectFromProvider();
812 int numFeaturesAdded = addFeatures();
813 QString featuresString =
" features";
814 if (numFeaturesAdded == 1)
816 featuresString =
" feature";
818 QString addedFeaturesText =
819 "Added " + QString::number(numFeaturesAdded) + featuresString +
" to the selection";
820 widget.lastActionInfoLabel->setText(addedFeaturesText);
828 QString clearedFeaturesText =
"Cleared the selected features";
829 widget.lastActionInfoLabel->setText(clearedFeaturesText);
835FeatureLearningWidgetController::updateFeaturesUI()
839 widget.addFeaturesButton->setEnabled(
false);
840 widget.clearFeaturesButton->setEnabled(
false);
841 widget.featuresInRegionLabel->setText(
"");
842 widget.featuresSelectedLabel->setText(
"");
845 widget.addFeaturesButton->setEnabled(
true);
846 widget.clearFeaturesButton->setEnabled(
true);
847 QString featuresInRegionString =
"Features in Region: ";
848 if (numSelectedPoints == 4)
850 featuresInRegionString += QString::number(viewFeatureSet->GetSize());
852 widget.featuresInRegionLabel->setText(featuresInRegionString);
854 QString featuresSelectedString =
855 "Features selected: " + QString::number(objectFeatureSet->GetSize());
856 widget.featuresSelectedLabel->setText(featuresSelectedString);
860FeatureLearningWidgetController::createCuboid(
float w,
float h,
float d)
862 CFloatMatrix*
object =
new CFloatMatrix(6, 36);
865 addRectangle(
object, offset, 0, 0, 0, w, 0, 0, w, h, 0, 0, h, 0, 0, 0, -1);
866 addRectangle(
object, offset, 0, 0, d, w, 0, d, w, h, d, 0, h, d, 0, 0, 1);
867 addRectangle(
object, offset, 0, 0, 0, 0, 0, d, 0, h, d, 0, h, 0, -1, 0, 0);
868 addRectangle(
object, offset, w, 0, 0, w, 0, d, w, h, d, w, h, 0, 1, 0, 0);
869 addRectangle(
object, offset, 0, 0, 0, 0, 0, d, w, 0, d, w, 0, 0, 0, -1, 0);
870 addRectangle(
object, offset, 0, h, 0, 0, h, d, w, h, d, w, h, 0, 0, 1, 0);
872 for (
int i = 0; i < 36; i++)
874 const int offset = 6 * i;
875 object->data[offset + 3] -= w / 2.0;
876 object->data[offset + 4] -= h / 2.0;
877 object->data[offset + 5] -= d / 2.0;
884FeatureLearningWidgetController::addRectangle(CFloatMatrix*
object,
902 addTriangle(
object, offset, x1, y1, z1, x2, y2, z2, x3, y3, z3, n1, n2, n3);
903 addTriangle(
object, offset, x4, y4, z4, x1, y1, z1, x3, y3, z3, n1, n2, n3);
907FeatureLearningWidgetController::addTriangle(CFloatMatrix*
object,
922 float*
data =
object->data;
924 data[offset + 0] = n1;
925 data[offset + 1] = n2;
926 data[offset + 2] = n3;
927 data[offset + 3] = x1;
928 data[offset + 4] = y1;
929 data[offset + 5] = z1;
932 data[offset + 0] = n1;
933 data[offset + 1] = n2;
934 data[offset + 2] = n3;
935 data[offset + 3] = x2;
936 data[offset + 4] = y2;
937 data[offset + 5] = z2;
940 data[offset + 0] = n1;
941 data[offset + 1] = n2;
942 data[offset + 2] = n3;
943 data[offset + 3] = x3;
944 data[offset + 4] = y3;
945 data[offset + 5] = z3;
952 std::lock_guard g{featureCalculatorMutex};
953 featureCalculator->SetThreshold(threshold);
959 std::lock_guard g{featureCalculatorMutex};
960 featureCalculator->SetMaxInterestPoints(maxFeatures);
966 std::lock_guard g{featureCalculatorMutex};
967 featureCalculator->SetMinDistance(minDistance);
973 std::lock_guard g{featureCalculatorMutex};
974 featureCalculator->SetNumberOfLevels(level);
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
QString getSelectedProxyName() const
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.
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
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 releaseImageProvider(std::string providerName)
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_INFO
The normal logging level.
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
VectorXD< 2, double > Vec2d
double a(double t, double a0, double j)
This file offers overloads of toIce() and fromIce() functions for STL container types.
constexpr auto n() noexcept