FeatureLearningWidgetController.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::FeatureLearningWidgetController
17 * \author Julian Zimmer ( urdbu 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 <mutex>
26#include <string>
27
29
31
32#include <VisionX/interface/components/Calibration.h>
35
36#include <Calibration/StereoCalibration.h>
37#include <DataStructures/DynamicArray.h>
38#include <Image/ImageProcessor.h>
39#include <Image/PrimitivesDrawer.h>
40
41using namespace armarx;
42using namespace visionx;
43
45{
46 qRegisterMetaType<CByteImage**>("CByteImage**");
47
48 QPointer<QWidget> widgetPointer = getWidget();
49 this->widgetPointer = widgetPointer.data();
50
51 widget.setupUi(widgetPointer);
52
53
54 proxyFinder = new armarx::IceProxyFinder<ImageProviderInterfacePrx>(widgetPointer);
55 proxyFinder->setSearchMask("*Provider|*Result");
56 //ui.horizontalLayout->addWidget(proxyFinder);
57 widget.chooseProviderLayout->addWidget(proxyFinder);
58
59 imageViewer = new SelectableImageViewer();
60 QSizePolicy sizePoli(QSizePolicy::Expanding, QSizePolicy::Expanding);
61 sizePoli.setVerticalStretch(15);
62 imageViewer->setSizePolicy(sizePoli);
63
64 widget.imageViewerLayout_2->addWidget(imageViewer);
65 imageViewer->show();
66}
67
71
72void
76
77void
81
82void
84{
85 proxyFinder->setIceManager(this->getIceManager(),
86 proxyFinder->getSelectedProxyName().isEmpty());
87
88 points = Eigen::ArrayX2f::Zero(4, 2);
89 numSelectedPoints = 0;
90
91
92 connect(imageViewer,
93 SIGNAL(selected(int, float, float)),
94 this,
95 SLOT(addPolygonPoint(int, float, float)));
96 connect(widget.connectButton, SIGNAL(clicked(bool)), this, SLOT(connectButtonClicked(bool)));
97 connect(widget.loadFeaturesButton,
98 SIGNAL(clicked(bool)),
99 this,
100 SLOT(loadFeaturesButtonClicked(bool)));
101 connect(widget.saveFeaturesButton,
102 SIGNAL(clicked(bool)),
103 this,
104 SLOT(saveFeaturesButtonClicked(bool)));
105 connect(
106 widget.pausePlayButton, SIGNAL(clicked(bool)), this, SLOT(pausePlayButtonClicked(bool)));
107 connect(
108 widget.disconnectButton, SIGNAL(clicked(bool)), this, SLOT(disconnectButtonClicked(bool)));
109 connect(widget.addFeaturesButton,
110 SIGNAL(clicked(bool)),
111 this,
112 SLOT(addFeaturesButtonClicked(bool)));
113 connect(widget.clearFeaturesButton,
114 SIGNAL(clicked(bool)),
115 this,
116 SLOT(clearFeaturesButtonClicked(bool)));
117 connect(widget.thresholdSpinBox,
118 SIGNAL(valueChanged(double)),
119 this,
120 SLOT(thresholdChanged(double)));
121 connect(
122 widget.maxFeatureSpinBox, SIGNAL(valueChanged(int)), this, SLOT(maxFeaturesChanged(int)));
123 connect(
124 widget.levelSpinBox, SIGNAL(valueChanged(int)), this, SLOT(levelChanged(int)));
125 connect(widget.minDistanceSpinBox,
126 SIGNAL(valueChanged(double)),
127 this,
128 SLOT(minDistanceChanged(double)));
129
130
131 connected = false;
132 isPaused = true;
133}
134
135void
137{
138 objectFeatureSet = new CTexturedFeatureSet("objectFeatureSet");
139 viewFeatureSet = new CTexturedFeatureSet("viewFeatureSet");
140
141 featureCalculator = new CHarrisSIFTFeatureCalculator(0.001, 1, 3500);
142 // featureCalculator->SetNumberOfLevels(1);
143}
144
145//add the features from the current region to the selection
146int
147FeatureLearningWidgetController::addFeatures()
148{
149 int numAdded = 0;
150 for (int i = 0; i < viewFeatureSet->GetSize(); i++)
151 {
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)
156 {
157 numAdded++;
158 }
159 }
160 return numAdded;
161}
162
163void
164FeatureLearningWidgetController::clearFeatures()
165{
166 objectFeatureSet->Clear();
167}
168
169//load a feature set from a .dat file
170void
171FeatureLearningWidgetController::loadFeatureSet(QString filePath)
172{
173 std::string filePathStr = filePath.toStdString();
174 const char* filePathCStr = filePathStr.c_str();
175 if (!objectFeatureSet->LoadFromFile(filePathCStr))
176 {
177 ARMARX_ERROR << " could not load feature set from file " << filePath;
178 widget.lastActionInfoLabel->setText("Loading features failed!");
179 }
180 else
181 {
182 ARMARX_INFO << "loaded feature set with " << objectFeatureSet->GetSize() << " features";
183
184 QDir currentDir;
185 mySettings.setValue("default_load_dir", currentDir.absoluteFilePath(filePath));
186
187 widget.lastActionInfoLabel->setText("Loaded feature set with " +
188 QString::number(objectFeatureSet->GetSize()) +
189 " features");
190
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);
194
195 int xInt = (int)x;
196 int yInt = (int)y;
197 int zInt = (int)z;
198
199 widget.widthLineEdit->setText(QString::number(xInt));
200 widget.heightLineEdit->setText(QString::number(yInt));
201 widget.depthLineEdit->setText(QString::number(zInt));
202 }
203
204 points = Eigen::ArrayX2f::Zero(4, 2);
205 numSelectedPoints = 0;
206}
207
208//save a feature set to a .dat file
209void
210FeatureLearningWidgetController::saveFeatureSet(QString filePath, float w, float h, float d)
211{
212 ARMARX_CHECK_EXPRESSION(objectFeatureSet->GetSize() > 0);
216
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);
221
222 std::string filePathStr = filePath.toStdString();
223 const char* filePathCStr = filePathStr.c_str();
224
225
226 if (!objectFeatureSet->SaveToFile(filePathCStr))
227 {
228 ARMARX_ERROR << " could not save feature set to file " << filePath;
229 widget.lastActionInfoLabel->setText("Saving features failed!");
230 }
231 else
232 {
233 ARMARX_INFO << " saved feature set with " << objectFeatureSet->GetSize()
234 << " features to file " << filePathCStr;
235
236
237 std::string matPath = filePath.toStdString();
238 const unsigned int n = matPath.find_last_of(".dat");
239 matPath.resize(n - 2);
240 matPath += "mat";
241
242 CFloatMatrix* object = createCuboid(w, h, d);
243 object->SaveToFile(matPath.c_str());
244 delete object;
245
246 QDir currentDir;
247 mySettings.setValue("default_save_dir", currentDir.absoluteFilePath(filePath));
248 widget.lastActionInfoLabel->setText(
249 "Saved " + QString::number(objectFeatureSet->GetSize()) + " features into file");
250 }
251}
252
253void
257
258void
260{
261 points = Eigen::ArrayX2f::Zero(4, 2);
262
263 if (connected)
264 {
265 for (int i = 0; i < numImages; i++)
266 {
267 delete cameraImages[i];
268 }
269
270 delete[] cameraImages;
271
272 delete visualizationImage;
273 delete grayImage;
274 }
275
276 delete featureCalculator;
277
278 delete objectFeatureSet;
279 delete viewFeatureSet;
280
281 // releaseImageProvider(imageProviderName);
282}
283
284static bool
285SameSide(const Vec2d& p1, const Vec2d& p2, const Vec2d& a, const Vec2d& b)
286{
287 double ba0 = b.x - a.x;
288 double ba1 = b.y - a.y;
289
290 double p1a0 = p1.x - a.x;
291 double p1a1 = p1.y - a.y;
292
293 double p2a0 = p2.x - a.x;
294 double p2a1 = p2.y - a.y;
295
296 double cp1 = ba0 * p1a1 - ba1 * p1a0;
297 double cp2 = ba0 * p2a1 - ba1 * p2a0;
298
299 return cp1 * cp2 >= 0;
300}
301
302static bool
303PointInPoly(const Vec2d& p, const Vec2d& a, const Vec2d& b, const Vec2d& c)
304{
305 return SameSide(p, a, b, c) && SameSide(p, b, a, c) && SameSide(p, c, a, b);
306}
307
308static double
309DistancePointStraightLine(const Vec2d& a, const Vec2d& b, const Vec2d p)
310{
311 Vec2d n = {b.y - a.y, a.x - b.x};
312 Math2d::NormalizeVec(n);
313
314 return std::fabs(Math2d::ScalarProduct(n, p) - Math2d::ScalarProduct(n, a));
315}
316
317//calculate features for the current region
318void
319FeatureLearningWidgetController::updateFeatures()
320{
321 if (numSelectedPoints == 0)
322 {
323 viewFeatureSet->Clear();
324 return;
325 }
326
327 // wait until region is selected
328 if (numSelectedPoints < 4)
329 {
330 return;
331 }
332
333 Vec2d sourcePoints[4];
334
335 for (int i = 0; i < numSelectedPoints; i++)
336 {
337 sourcePoints[i].x = points(i, 0) * grayImage->width;
338 sourcePoints[i].y = points(i, 1) * grayImage->height;
339 }
340
341 const float w = widget.widthLineEdit->text().toFloat();
342 const float h = widget.heightLineEdit->text().toFloat();
343
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);
349
350 LinearAlgebra::DetermineHomography(sourcePoints, targetPoints, 4, homography, true);
351
352 objectFeatureSet->SetCornerPoints(
353 targetPoints[0], targetPoints[1], targetPoints[2], targetPoints[3]);
354
355 featureCalculatorMutex.lock();
356 CDynamicArray dynamic_array(featureCalculator->GetMaxInterestPoints());
357 const int nFeatures = featureCalculator->CalculateFeatures(grayImage, &dynamic_array);
358 featureCalculatorMutex.unlock();
359 viewFeatureSet->Clear();
360
361 for (int i = 0; i < nFeatures; i++)
362 {
363 CFeatureEntry* pFeatureEntry = (CFeatureEntry*)dynamic_array.GetElement(i);
364
365 if (PointInPoly(pFeatureEntry->point, sourcePoints[0], sourcePoints[1], sourcePoints[2]) ||
366 PointInPoly(pFeatureEntry->point, sourcePoints[2], sourcePoints[3], sourcePoints[0]))
367 {
368 const double dThreshold = 10;
369
370 if (DistancePointStraightLine(sourcePoints[0], sourcePoints[1], pFeatureEntry->point) >
371 dThreshold &&
372 DistancePointStraightLine(sourcePoints[1], sourcePoints[2], pFeatureEntry->point) >
373 dThreshold &&
374 DistancePointStraightLine(sourcePoints[2], sourcePoints[3], pFeatureEntry->point) >
375 dThreshold &&
376 DistancePointStraightLine(sourcePoints[3], sourcePoints[0], pFeatureEntry->point) >
377 dThreshold)
378 {
379 viewFeatureSet->AddFeature(pFeatureEntry->Clone(), false);
380 }
381 }
382 }
383
384 ARMARX_LOG << deactivateSpam(2.f) << "Features in polygon " << viewFeatureSet->GetSize();
385}
386
387void
388FeatureLearningWidgetController::updateSelection()
389{
390 Vec2d sourcePoints[4];
391
392 //Depending on the size of the widget, the image gets scaled up or down
393 //The dimensions of the visualization image have to be regarded, to find the position of the mouse click on the image
394 //Vec2d scaledImageDimensions = imageViewer->getScaledImageDimensions();
395 for (int i = 0; i < numSelectedPoints; i++)
396 {
397 float relativeX = points(i, 0);
398 float relativeY = points(i, 1);
399
400 sourcePoints[i].x = relativeX * visualizationImage->width;
401 sourcePoints[i].y = relativeY * visualizationImage->height;
402 //sourcePoints[i].x = points(i, 0);
403 //sourcePoints[i].y = points(i, 1);
404 }
405
406 if (numSelectedPoints >= 1)
407 {
408 PrimitivesDrawer::DrawCircle(visualizationImage, sourcePoints[0], 3, 255, 0, 0, -1);
409 //ARMARX_INFO << deactivateSpam(2.f) << "DRAWING POINT 1 AT (" << sourcePoints[0].x << ", " << sourcePoints[0].y << ")";
410 }
411 if (numSelectedPoints >= 2)
412 {
413 PrimitivesDrawer::DrawCircle(visualizationImage, sourcePoints[1], 3, 255, 0, 0, -1);
414 PrimitivesDrawer::DrawLine(visualizationImage, sourcePoints[0], sourcePoints[1], 0, 0, 255);
415 //ARMARX_INFO << deactivateSpam(2.f) << "DRAWING POINT 2 AT (" << sourcePoints[1].x << ", " << sourcePoints[1].y << ")";
416 }
417 if (numSelectedPoints >= 3)
418 {
419 PrimitivesDrawer::DrawCircle(visualizationImage, sourcePoints[2], 3, 255, 0, 0, -1);
420 PrimitivesDrawer::DrawLine(visualizationImage, sourcePoints[1], sourcePoints[2], 0, 0, 255);
421 //ARMARX_INFO << deactivateSpam(2.f) << "DRAWING POINT 3 AT (" << sourcePoints[2].x << ", " << sourcePoints[2].y << ")";
422 }
423 if (numSelectedPoints >= 4)
424 {
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);
428 //ARMARX_INFO << deactivateSpam(2.f) << "DRAWING POINT 4 AT (" << sourcePoints[3].x << ", " << sourcePoints[3].y << ")";
429 }
430
431
432 // draw features
433 if (numSelectedPoints >= 4)
434 {
435 for (int i = 0; i < viewFeatureSet->GetSize(); i++)
436 {
437 const CFeatureEntry* pFeatureEntry = viewFeatureSet->GetFeature(i);
438 PrimitivesDrawer::DrawCircle(
439 visualizationImage, pFeatureEntry->point, 2, 0, 255, 0, -1);
440 }
441 }
442}
443
444void
446{
447
448 //std::unique_lock<std::mutex> lock(imageMutex, std::try_to_lock);
449 std::unique_lock lock(imageMutex);
450
451 if (!lock.owns_lock())
452 {
453 ARMARX_INFO << deactivateSpam(3) << "unable to process next image(" << lock.owns_lock()
454 << ")";
455 return;
456 }
457
458 if (!connected)
459 {
460 ARMARX_INFO << deactivateSpam(3) << "Not connected to any image provider";
461 return;
462 }
463
464 armarx::MetaInfoSizeBasePtr info;
465 IceUtil::Time timeReceived;
466 if (!isPaused)
467 {
468 //only update current image, if unpaused
469 if (!waitForImages(imageProviderName))
470 {
471 ARMARX_WARNING << "Timeout while waiting for images";
472 return;
473 }
474 if (getImages(imageProviderName, cameraImages, info) != numImages)
475 {
476 ARMARX_WARNING << "Unable to transfer or read images";
477 return;
478 }
479 timeReceived = TimeUtil::GetTime();
480 }
481
482 //create grayscale image for feature calculation and color image for the visualization
483 ::ImageProcessor::ConvertImage(cameraImages[0], grayImage);
484 ::ImageProcessor::CopyImage(cameraImages[0], visualizationImage);
485
486 updateFeatures();
487 updateSelection();
488
489 //update the availability of the buttons etc.
490 updateFeaturesUI();
491
492
493 CByteImage** images = new CByteImage* {visualizationImage};
494 imageViewer->setImages(
495 1, images, IceUtil::Time::microSeconds(info->timeProvided), timeReceived);
496}
497
498void
500{
501 if (!connected)
502 {
503 return;
504 }
505
506 if (numSelectedPoints >= 4)
507 {
508 numSelectedPoints = 0;
509 }
510
511 points(numSelectedPoints, 0) = x;
512 points(numSelectedPoints, 1) = y;
513
514 numSelectedPoints++;
515}
516
517void
522
523//opens a QDialog with the last used load location and calls the feature loading function
524void
526{
527 QString previousLoadDirectory = mySettings.value("default_load_dir").toString();
528 if (previousLoadDirectory == "")
529 {
530 QString previousSaveDirectory = mySettings.value("default_save_dir").toString();
531 if (previousSaveDirectory == "")
532 {
533 previousLoadDirectory = "~";
534 }
535 else
536 {
537 previousLoadDirectory = previousSaveDirectory;
538 }
539 }
540 QString filePath = QFileDialog::getOpenFileName(
541 widgetPointer, "Load Features", previousLoadDirectory, "(*.dat)");
542 loadFeatureSet(filePath);
543}
544
545//checks if features are selected and opens a QDialog to choose the save location
546void
548{
549 if (objectFeatureSet->GetSize() < 1)
550 {
551 QMessageBox emptyFeatureSetBox;
552 emptyFeatureSetBox.setText("Cannot save empty feature set!");
553 emptyFeatureSetBox.setWindowTitle("Feature set empty");
554 emptyFeatureSetBox.exec();
555 return;
556 }
557 float width = widget.widthLineEdit->text().toFloat();
558 float height = widget.heightLineEdit->text().toFloat();
559 float depth = widget.depthLineEdit->text().toFloat();
560
561 if (width <= 0.f || height <= 0.f || depth <= 0.f)
562 {
563 QMessageBox invalidDimensionsBox;
564 invalidDimensionsBox.setText("Cannot save feature set with object dimensions <= 0!");
565 invalidDimensionsBox.setWindowTitle("Invalid object dimensions");
566 invalidDimensionsBox.exec();
567 return;
568 }
569
570 QString previousSaveDirectory = mySettings.value("default_save_dir").toString();
571 if (previousSaveDirectory == "")
572 {
573 QString previousLoadDirectory = mySettings.value("default_load_dir").toString();
574 if (previousLoadDirectory == "")
575 {
576 previousSaveDirectory = "~";
577 }
578 else
579 {
580 previousSaveDirectory = previousLoadDirectory;
581 }
582 }
583 QString filePath = QFileDialog::getSaveFileName(
584 widgetPointer, "Save Features", previousSaveDirectory, "(*.dat)");
585 if (filePath.right(4) != ".dat")
586 {
587 filePath += ".dat";
588 }
589 saveFeatureSet(filePath, width, height, depth);
590}
591
592void
594{
595 if (!connected)
596 {
597 isPaused = false;
598 }
599 else
600 {
601 isPaused = !isPaused;
602 }
603 updateImageMonitorUI();
604}
605
606//disconncts and connects again
607void
609{
610 std::unique_lock lock(imageMutex);
611
612 disconnectFromProvider();
613
614 // connect to provider
615 try
616 {
617 connectToProvider();
618 }
619 catch (...)
620 {
622 }
623}
624
625//trying to connect to the image provider
626void
627FeatureLearningWidgetController::connectToProvider()
628{
629 if (connected)
630 {
631 return;
632 }
633
634
635 imageProviderName = proxyFinder->getSelectedProxyName().toStdString();
636 ARMARX_INFO << "Trying to connect to provider " << imageProviderName;
637
638 try
639 {
640 usingImageProvider(imageProviderName);
641 }
642 catch (Ice::NotRegisteredException& e)
643 {
644 ARMARX_ERROR << "Cannot connect to the given image provider called " << imageProviderName;
645
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();
653 return;
654 }
655 catch (armarx::LocalException& e)
656 {
657 ARMARX_ERROR << "Image Provider field is empty, cannot connect!" << imageProviderName;
658
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();
665 return;
666 }
667
668 ARMARX_INFO << getName() << " connecting to " << imageProviderName;
669
670 // connect to proxy
671 imageProviderInfo =
672 getImageProvider(imageProviderName, visionx::tools::typeNameToImageType("rgb"));
673
674 // update members
675 imageProviderPrx = imageProviderInfo.proxy;
676 numImages = imageProviderInfo.numberImages;
677
678 StereoCalibrationProviderInterfacePrx calibrationProvider =
679 StereoCalibrationProviderInterfacePrx::checkedCast(imageProviderInfo.proxy);
680
681 if (!calibrationProvider)
682 {
683 ARMARX_WARNING << "image provider does not have a stereo calibration interface";
684 }
685 else
686 {
687 undistortImages = calibrationProvider->getImagesAreUndistorted();
688 if (!undistortImages)
689 {
690 ARMARX_ERROR << "Images expected to be undistorted, but the calibration returns that "
691 "the images are distorted";
692 }
693 // visionx::StereoCalibration stereoCalibration = calibrationProvider->getStereoCalibration();
694 // CStereoCalibration* ivtStereoCalibration = visionx::tools::convert(stereoCalibration);
695 }
696
697
698 // create images
699 {
700 std::unique_lock lock(imageMutex);
701 cameraImages = new CByteImage*[numImages];
702
703 for (int i = 0; i < numImages; i++)
704 {
705 cameraImages[i] = visionx::tools::createByteImage(imageProviderInfo);
706 }
707 }
708
709 visualizationImage = visionx::tools::createByteImage(imageProviderInfo);
710 grayImage = new CByteImage(imageProviderInfo.imageFormat.dimension.width,
711 imageProviderInfo.imageFormat.dimension.height,
712 CByteImage::eGrayScale);
713
714
715 timeProvided = IceUtil::Time::seconds(0);
716
717 isPaused = false;
718 connected = true;
719 updateImageMonitorUI();
720 updateFeaturesUI();
721
722
723 emit imageProviderConnected(true);
724}
725
726//disconnecting the image provider
727void
728FeatureLearningWidgetController::disconnectFromProvider()
729{
730 if (!connected)
731 {
732 return;
733 }
734 ARMARX_INFO << "Disconnecting from provider";
735 {
736 std::unique_lock lock(imageMutex);
737 // clear images
738 if (cameraImages)
739 {
740 for (int i = 0; i < numImages; i++)
741 {
742 delete cameraImages[i];
743 }
744
745 delete[] cameraImages;
746 }
747 delete visualizationImage;
748 delete grayImage;
749 }
750
751 releaseImageProvider(imageProviderName);
752
753 imageProviderPrx = 0;
754
755 connected = false;
756 isPaused = true;
757 numSelectedPoints = 0;
758
759 QString emptyFeaturesInfoText = "";
760 widget.lastActionInfoLabel->setText(emptyFeaturesInfoText);
761
762 updateImageMonitorUI();
763 updateFeaturesUI();
764
765 emit imageProviderConnected(false);
766}
767
768void
769FeatureLearningWidgetController::updatePausePlayButtonText()
770{
771 if (isPaused)
772 {
773 widget.pausePlayButton->setText("Play");
774 return;
775 }
776 widget.pausePlayButton->setText("Pause");
777}
778
779void
780FeatureLearningWidgetController::updateImageMonitorUI()
781{
782 updatePausePlayButtonText();
783
784 widget.disconnectButton->setEnabled(connected);
785 widget.pausePlayButton->setEnabled(connected);
786
787 if (connected)
788 {
789 QString providerName = imageProviderName.c_str();
790 QString statusString = "Status: connected to image provider " + providerName;
791 if (isPaused)
792 {
793 statusString = statusString + " - PAUSED";
794 }
795 widget.imageMonitorStatusLabel->setText(statusString);
796 }
797 else
798 {
799 widget.imageMonitorStatusLabel->setText("Status: not connected");
800 }
801}
802
803void
805{
806 disconnectFromProvider();
807}
808
809void
811{
812 int numFeaturesAdded = addFeatures();
813 QString featuresString = " features";
814 if (numFeaturesAdded == 1)
815 {
816 featuresString = " feature";
817 }
818 QString addedFeaturesText =
819 "Added " + QString::number(numFeaturesAdded) + featuresString + " to the selection";
820 widget.lastActionInfoLabel->setText(addedFeaturesText);
821 updateFeaturesUI();
822}
823
824void
826{
827 clearFeatures();
828 QString clearedFeaturesText = "Cleared the selected features";
829 widget.lastActionInfoLabel->setText(clearedFeaturesText);
830 updateFeaturesUI();
831}
832
833//updates the information about the features on the right part of the ui
834void
835FeatureLearningWidgetController::updateFeaturesUI()
836{
837 if (!connected)
838 {
839 widget.addFeaturesButton->setEnabled(false);
840 widget.clearFeaturesButton->setEnabled(false);
841 widget.featuresInRegionLabel->setText("");
842 widget.featuresSelectedLabel->setText("");
843 return;
844 }
845 widget.addFeaturesButton->setEnabled(true);
846 widget.clearFeaturesButton->setEnabled(true);
847 QString featuresInRegionString = "Features in Region: ";
848 if (numSelectedPoints == 4)
849 {
850 featuresInRegionString += QString::number(viewFeatureSet->GetSize());
851 }
852 widget.featuresInRegionLabel->setText(featuresInRegionString);
853
854 QString featuresSelectedString =
855 "Features selected: " + QString::number(objectFeatureSet->GetSize());
856 widget.featuresSelectedLabel->setText(featuresSelectedString);
857}
858
859CFloatMatrix*
860FeatureLearningWidgetController::createCuboid(float w, float h, float d)
861{
862 CFloatMatrix* object = new CFloatMatrix(6, 36);
863
864 int offset = 0;
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);
871
872 for (int i = 0; i < 36; i++)
873 {
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;
878 }
879
880 return object;
881}
882
883void
884FeatureLearningWidgetController::addRectangle(CFloatMatrix* object,
885 int& offset,
886 float x1,
887 float y1,
888 float z1,
889 float x2,
890 float y2,
891 float z2,
892 float x3,
893 float y3,
894 float z3,
895 float x4,
896 float y4,
897 float z4,
898 float n1,
899 float n2,
900 float n3)
901{
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);
904}
905
906void
907FeatureLearningWidgetController::addTriangle(CFloatMatrix* object,
908 int& offset,
909 float x1,
910 float y1,
911 float z1,
912 float x2,
913 float y2,
914 float z2,
915 float x3,
916 float y3,
917 float z3,
918 float n1,
919 float n2,
920 float n3)
921{
922 float* data = object->data;
923
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;
930 offset += 6;
931
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;
938 offset += 6;
939
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;
946 offset += 6;
947}
948
949void
951{
952 std::lock_guard g{featureCalculatorMutex};
953 featureCalculator->SetThreshold(threshold);
954}
955
956void
958{
959 std::lock_guard g{featureCalculatorMutex};
960 featureCalculator->SetMaxInterestPoints(maxFeatures);
961}
962
963void
965{
966 std::lock_guard g{featureCalculatorMutex};
967 featureCalculator->SetMinDistance(minDistance);
968}
969
970void
972{
973 std::lock_guard g{featureCalculatorMutex};
974 featureCalculator->SetNumberOfLevels(level);
975}
uint8_t data[1]
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
constexpr T c
virtual QPointer< QWidget > getWidget()
getWidget returns a pointer to the a widget of this controller.
void imageProviderConnected(bool connected)
virtual ~FeatureLearningWidgetController()
Controller destructor.
virtual void loadSettings(QSettings *settings) override
virtual void saveSettings(QSettings *settings) override
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.
Definition TimeUtil.cpp:42
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.
Definition Logging.h:181
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_LOG
Definition Logging.h:165
VectorXD< 2, double > Vec2d
Definition VectorXD.h:736
double a(double t, double a0, double j)
Definition CtrlUtil.h:45
This file offers overloads of toIce() and fromIce() functions for STL container types.
void handleExceptions()
constexpr auto n() noexcept
ImageType typeNameToImageType(const std::string &imageTypeName)
Converts an image type name as string into an ImageType integer.
CByteImage * createByteImage(const ImageFormatInfo &imageFormat, const ImageType imageType)
Creates a ByteImage for the destination type specified in the given imageProviderInfo.
ArmarX headers.