25 #include <boost/lexical_cast.hpp>
27 #include <pcl/common/colors.h>
39 using namespace Eigen;
45 return boost::lexical_cast<std::string>(t);
52 return QString::fromStdString(boost::lexical_cast<std::string>(t));
59 UserAssistedSegmenterGuiWidgetController::GetWidgetName()
61 return "VisionX.UserAssistedSegmenterGui";
64 UserAssistedSegmenterGuiWidgetController::UserAssistedSegmenterGuiWidgetController()
66 widget.setupUi(getWidget());
70 widget.tableSegmentsOverviewLayout->addWidget(segmentsOverviewTable);
71 widget.tableSegmentsOverviewPlaceholder->deleteLater();
75 widget.tableUserGrouping->setColumnCount(3);
76 widget.tableUserGrouping->setRowCount(0);
81 <<
"Space seperated segment IDs";
82 widget.tableUserGrouping->setHorizontalHeaderLabels(header);
83 widget.tableUserGrouping->setColumnWidth(0, 30);
84 widget.tableUserGrouping->setColumnWidth(1, 40);
88 UserAssistedSegmenterGuiWidgetController::~UserAssistedSegmenterGuiWidgetController()
93 UserAssistedSegmenterGuiWidgetController::loadSettings(QSettings* settings)
99 UserAssistedSegmenterGuiWidgetController::saveSettings(QSettings* settings)
105 UserAssistedSegmenterGuiWidgetController::getConfigDialog(QWidget* parent)
111 return qobject_cast<UserAssistedSegmenterConfigDialog*>(configDialog);
115 UserAssistedSegmenterGuiWidgetController::configured()
117 userAssistedSegmenterProxyName = configDialog->getUserAssistedSegmenterProxyName();
118 userAssistedSegmenterTopicName = configDialog->getUserAssistedSegmenterTopicName();
122 UserAssistedSegmenterGuiWidgetController::onInitComponent()
124 usingTopic(userAssistedSegmenterTopicName);
125 drawer.offeringTopic(*
this);
127 usingProxy(userAssistedSegmenterProxyName);
131 UserAssistedSegmenterGuiWidgetController::onConnectComponent()
133 drawer.getTopic(*
this);
136 getProxy<visionx::UserAssistedSegmenterInterfacePrx>(userAssistedSegmenterProxyName);
139 ARMARX_ERROR <<
"Could not get proxy '" << userAssistedSegmenterProxyName <<
"'.";
142 connect(
this, SIGNAL(newSourcePointCloud()),
this, SLOT(onNewSourcePointCloud()));
144 connect(widget.spinBoxFilterSmallSegmentsNum,
145 SIGNAL(editingFinished()),
147 SLOT(onFilterSmallSegmentsNumEdited()));
149 connect(widget.checkBoxFilterSegment0, SIGNAL(toggled(
bool)),
this, SLOT(updateFilters()));
151 widget.checkBoxFilterSmallSegments, SIGNAL(toggled(
bool)),
this, SLOT(updateFilters()));
153 connect(widget.checkBoxShowIDs, SIGNAL(toggled(
bool)),
this, SLOT(onShowIDsToggled(
bool)));
154 connect(widget.radioButtonShowInput,
155 SIGNAL(toggled(
bool)),
157 SLOT(onRadioButtonShowInputToggled(
bool)));
158 connect(widget.radioButtonShowResult,
159 SIGNAL(toggled(
bool)),
161 SLOT(onRadioButtonShowResultToggle(
bool)));
163 connect(widget.spinBoxNumObjects,
164 SIGNAL(valueChanged(
int)),
166 SLOT(updateUserGroupingRows(
int)));
167 connect(widget.tableUserGrouping,
168 SIGNAL(cellChanged(
int,
int)),
170 SLOT(onUserGroupingChanged(
int,
int)));
172 connect(widget.buttonClearVisu, SIGNAL(released()),
this, SLOT(clearVisualization()));
173 connect(widget.buttonPublish, SIGNAL(released()),
this, SLOT(publishSegmentation()));
175 connect(widget.tableUserGrouping,
176 SIGNAL(cellChanged(
int,
int)),
178 SLOT(onTableGroupingCellChanged(
int,
int)));
181 for (
auto& spinBox : {widget.spinTextSize, widget.spinSphereSize})
183 connect(spinBox, SIGNAL(valueChanged(
int)),
this, SLOT(updateSegmentIDs()));
188 UserAssistedSegmenterGuiWidgetController::reportSegmentation(
189 const visionx::ColoredLabeledPointCloud& receivedPointCloud,
192 if (!widget.checkBoxListening->isChecked())
202 ARMARX_INFO <<
"Emittinging signal receivedSegmentation().";
203 emit newSourcePointCloud();
207 UserAssistedSegmenterGuiWidgetController::onNewSourcePointCloud()
211 widget.labelPcStatus->setText(QString(
"Processing..."));
213 this->pointCloud = sourcePointCloud;
215 computeSegmentIndex(pointCloud);
217 applyFilters(pointCloud, segmentIndex);
219 updatePointCloud(pointCloud, segmentIndex);
223 widget.labelPcStatus->setText(QString(
"Current point cloud:"));
227 UserAssistedSegmenterGuiWidgetController::onFilterSmallSegmentsNumEdited()
229 widget.checkBoxFilterSmallSegments->setChecked(
230 widget.spinBoxFilterSmallSegmentsNum->value() > 0);
234 UserAssistedSegmenterGuiWidgetController::updateFilters()
236 applyFilters(pointCloud, segmentIndex);
237 updatePointCloud(pointCloud, segmentIndex);
241 UserAssistedSegmenterGuiWidgetController::onRadioButtonShowInputToggled(
bool checked)
245 drawInputPointCloud(
false);
250 UserAssistedSegmenterGuiWidgetController::onRadioButtonShowResultToggle(
bool checked)
254 drawResultPointCloud(
false);
259 UserAssistedSegmenterGuiWidgetController::onShowIDsToggled(
bool checked)
263 drawSegmentIDs(
false);
267 drawer.clearLayer(layerSegmentIDs);
272 UserAssistedSegmenterGuiWidgetController::updateSegmentIDs()
278 UserAssistedSegmenterGuiWidgetController::applyFilters(
280 std::map<uint32_t, pcl::PointIndices>& segmentIndex)
284 if (widget.checkBoxFilterSegment0)
286 auto ifLabelZero = [](
const PointT& p) {
return p.label == 0; };
287 pointCloud.erase(std::remove_if(pointCloud.begin(), pointCloud.end(), ifLabelZero),
290 computeSegmentIndex(pointCloud);
293 if (widget.checkBoxFilterSmallSegments->isChecked())
295 const int minPoints =
std::max(0, widget.spinBoxFilterSmallSegmentsNum->value());
300 auto ifLessPoints = [&segmentIndex, minPoints](
const PointT& p) {
301 return segmentIndex.at(p.label).indices.size() <
302 static_cast<std::size_t
>(minPoints);
304 pointCloud.erase(std::remove_if(pointCloud.begin(), pointCloud.end(), ifLessPoints),
307 computeSegmentIndex(pointCloud);
313 UserAssistedSegmenterGuiWidgetController::updatePointCloud(
315 const std::map<uint32_t, pcl::PointIndices>& segmentIndex)
318 computeCenters(pointCloud, segmentIndex);
320 widget.labelPcPointsNum->setText(
qstr(pointCloud.size()));
321 widget.labelPcSegmentsNum->setText(
qstr(segmentIndex.size()));
323 updateTableOverview();
324 drawInputPointCloud();
325 drawSegmentIDs(
true);
329 UserAssistedSegmenterGuiWidgetController::computeSegmentIndex(
const PointCloudT& pointCloud)
331 segmentIndex.clear();
332 const bool excludeZero =
false;
337 UserAssistedSegmenterGuiWidgetController::computeCenters(
339 const std::map<uint32_t, pcl::PointIndices>& segmentIndex)
343 for (
const auto& [segmentID,
indices] : segmentIndex)
348 const PointT& p = pointCloud[
static_cast<std::size_t
>(i)];
349 center += Vector3f(p.x, p.y, p.z);
351 center /= segmentIndex.at(segmentID).indices.size();
352 centers[segmentID] =
center;
357 UserAssistedSegmenterGuiWidgetController::updateTableOverview()
359 segmentsOverviewTable->setData(segmentIndex);
363 UserAssistedSegmenterGuiWidgetController::drawSegmentIDs(
bool onlyIfChecked)
365 if (onlyIfChecked && !widget.checkBoxShowIDs->isChecked())
370 drawer.clearLayer(layerSegmentIDs,
true);
372 for (
const auto& [segmentID, _] : segmentIndex)
374 const int textSize = widget.spinTextSize->value();
375 const int sphereSize = widget.spinSphereSize->value();
377 const DrawColor segColor = dcolor(segmentID);
378 const DrawColor textColor = (segColor.r + segColor.g + segColor.b) > 1.f
379 ? DrawColor{0, 0, 0, 1}
380 : DrawColor{1, 1, 1, 1};
382 drawer.drawText({layerSegmentIDs,
"id" +
str(segmentID)},
387 drawer.drawSphere({layerSegmentIDs,
"sph" +
str(segmentID)},
395 UserAssistedSegmenterGuiWidgetController::drawInputPointCloud(
bool onlyIfChecked)
397 if (onlyIfChecked && !widget.radioButtonShowInput->isChecked())
405 drawer.drawPointCloud({layerPointCloud,
"PointCloud"},
407 [
this](
const PointT& p) {
return dcolor(p.label); });
413 UserAssistedSegmenterGuiWidgetController::drawResultPointCloud(
bool onlyIfChecked)
415 if (onlyIfChecked && !widget.radioButtonShowResult->isChecked())
422 DebugDrawerColoredPointCloud debugPointCloud;
424 for (std::size_t group = 0; group < userGrouping.size(); ++group)
426 for (uint32_t segment : userGrouping[group])
428 for (
int i : segmentIndex.at(segment).indices)
430 PointT& p = pointCloud[
static_cast<std::size_t
>(i)];
431 debugPointCloud.points.push_back(
432 DebugDrawerColoredPointCloudElement{p.x, p.y, p.z, dcolor(group)});
437 drawer.drawPointCloud({layerPointCloud,
"PointCloud"}, debugPointCloud);
443 UserAssistedSegmenterGuiWidgetController::dcolor(std::size_t
id)
const
451 return static_cast<int>(f * 255);
455 UserAssistedSegmenterGuiWidgetController::qcolor(std::size_t
id)
const
457 const DrawColor
c = dcolor(
id);
462 UserAssistedSegmenterGuiWidgetController::updateUserGroupingRows(
int numRows)
464 int previousNumRows = widget.tableUserGrouping->rowCount();
465 widget.tableUserGrouping->setRowCount(numRows);
467 std::set<uint32_t> segmentIDs;
468 for (
const auto& [segmentID, _] : segmentIndex)
470 segmentIDs.insert(segmentID);
474 for (
int id = previousNumRows;
id < numRows; ++id)
476 QTableWidgetItem* itemColor =
new QTableWidgetItem(QString());
477 itemColor->setBackgroundColor(qcolor(
static_cast<std::size_t
>(
id)));
478 widget.tableUserGrouping->setItem(
id, 0, itemColor);
480 QTableWidgetItem* itemID =
new QTableWidgetItem(
qstr(
id));
481 itemID->setTextAlignment(Qt::AlignCenter);
482 widget.tableUserGrouping->setItem(
id, 1, itemID);
487 SIGNAL(groupingChanged(uint32_t, std::vector<uint32_t>)),
489 SLOT(onUserGroupingChanged(uint32_t, std::vector<uint32_t>)));
490 widget.tableUserGrouping->setCellWidget(
id, 2, itemList);
493 userGrouping.resize(
static_cast<std::size_t
>(numRows));
497 UserAssistedSegmenterGuiWidgetController::onUserGroupingChanged(
499 std::vector<uint32_t> segmentIDs)
501 if (groupID < userGrouping.size())
503 userGrouping[groupID] = segmentIDs;
505 ARMARX_INFO <<
"Updated user grouping " << groupID <<
": \n" << userGrouping[groupID];
506 drawResultPointCloud(
true);
511 UserAssistedSegmenterGuiWidgetController::onTableGroupingCellChanged(
int row,
int col)
515 widget.tableUserGrouping->item(row, col)->setText(QString());
519 widget.tableUserGrouping->item(row, col)->setText(
qstr(row));
524 UserAssistedSegmenterGuiWidgetController::publishSegmentation()
532 visionx::ColoredLabeledPointCloud resultCloud;
534 for (std::size_t groupID = 0; groupID < userGrouping.size(); ++groupID)
536 for (uint32_t segment : userGrouping[groupID])
538 for (
int i : segmentIndex.at(segment).indices)
540 PointT& p = pointCloud.at(
static_cast<std::size_t
>(i));
541 resultCloud.push_back(
542 visionx::ColoredLabeledPoint3D{visionx::Point3D{p.x, p.y, p.z},
543 visionx::RGBA{p.r, p.g, p.b, p.a},
544 static_cast<int>(groupID)});
548 segmenterProxy->publishSegmentation(resultCloud);
552 UserAssistedSegmenterGuiWidgetController::clearVisualization()
554 drawer.clearLayer(layerSegmentIDs);
555 drawer.clearLayer(layerPointCloud);
556 drawer.clearColoredPointCloud({layerPointCloud,
"PointCloud"});