25 #include <boost/lexical_cast.hpp>
26 #include <pcl/common/colors.h>
38 using namespace Eigen;
42 std::string
str(
const T& t)
44 return boost::lexical_cast<std::string>(t);
50 return QString::fromStdString(boost::lexical_cast<std::string>(t));
56 QString UserAssistedSegmenterGuiWidgetController::GetWidgetName()
58 return "VisionX.UserAssistedSegmenterGui";
62 UserAssistedSegmenterGuiWidgetController::UserAssistedSegmenterGuiWidgetController()
64 widget.setupUi(getWidget());
68 widget.tableSegmentsOverviewLayout->addWidget(segmentsOverviewTable);
69 widget.tableSegmentsOverviewPlaceholder->deleteLater();
73 widget.tableUserGrouping->setColumnCount(3);
74 widget.tableUserGrouping->setRowCount(0);
77 header <<
"C" <<
"ID" <<
"Space seperated segment IDs";
78 widget.tableUserGrouping->setHorizontalHeaderLabels(header);
79 widget.tableUserGrouping->setColumnWidth(0, 30);
80 widget.tableUserGrouping->setColumnWidth(1, 40);
86 UserAssistedSegmenterGuiWidgetController::~UserAssistedSegmenterGuiWidgetController()
91 void UserAssistedSegmenterGuiWidgetController::loadSettings(QSettings* settings)
96 void UserAssistedSegmenterGuiWidgetController::saveSettings(QSettings* settings)
101 QPointer<QDialog> UserAssistedSegmenterGuiWidgetController::getConfigDialog(QWidget* parent)
107 return qobject_cast<UserAssistedSegmenterConfigDialog*>(configDialog);
110 void UserAssistedSegmenterGuiWidgetController::configured()
112 userAssistedSegmenterProxyName = configDialog->getUserAssistedSegmenterProxyName();
113 userAssistedSegmenterTopicName = configDialog->getUserAssistedSegmenterTopicName();
117 void UserAssistedSegmenterGuiWidgetController::onInitComponent()
119 usingTopic(userAssistedSegmenterTopicName);
120 drawer.offeringTopic(*
this);
122 usingProxy(userAssistedSegmenterProxyName);
126 void UserAssistedSegmenterGuiWidgetController::onConnectComponent()
128 drawer.getTopic(*
this);
130 segmenterProxy = getProxy<visionx::UserAssistedSegmenterInterfacePrx>(userAssistedSegmenterProxyName);
133 ARMARX_ERROR <<
"Could not get proxy '" << userAssistedSegmenterProxyName <<
"'.";
136 connect(
this, SIGNAL(newSourcePointCloud()),
137 this, SLOT(onNewSourcePointCloud()));
139 connect(widget.spinBoxFilterSmallSegmentsNum, SIGNAL(editingFinished()),
140 this, SLOT(onFilterSmallSegmentsNumEdited()));
142 connect(widget.checkBoxFilterSegment0, SIGNAL(toggled(
bool)),
143 this, SLOT(updateFilters()));
144 connect(widget.checkBoxFilterSmallSegments, SIGNAL(toggled(
bool)),
145 this, SLOT(updateFilters()));
147 connect(widget.checkBoxShowIDs, SIGNAL(toggled(
bool)),
148 this, SLOT(onShowIDsToggled(
bool)));
149 connect(widget.radioButtonShowInput, SIGNAL(toggled(
bool)),
150 this, SLOT(onRadioButtonShowInputToggled(
bool)));
151 connect(widget.radioButtonShowResult, SIGNAL(toggled(
bool)),
152 this, SLOT(onRadioButtonShowResultToggle(
bool)));
154 connect(widget.spinBoxNumObjects, SIGNAL(valueChanged(
int)),
155 this, SLOT(updateUserGroupingRows(
int)));
156 connect(widget.tableUserGrouping, SIGNAL(cellChanged(
int,
int)),
157 this, SLOT(onUserGroupingChanged(
int,
int)));
159 connect(widget.buttonClearVisu, SIGNAL(released()),
160 this, SLOT(clearVisualization()));
161 connect(widget.buttonPublish, SIGNAL(released()),
162 this, SLOT(publishSegmentation()));
164 connect(widget.tableUserGrouping, SIGNAL(cellChanged(
int,
int)),
165 this, SLOT(onTableGroupingCellChanged(
int,
int)));
170 widget.spinTextSize, widget.spinSphereSize
173 connect(spinBox, SIGNAL(valueChanged(
int)),
this, SLOT(updateSegmentIDs()));
177 void UserAssistedSegmenterGuiWidgetController::reportSegmentation(
178 const visionx::ColoredLabeledPointCloud& receivedPointCloud,
const Ice::Current&)
180 if (!widget.checkBoxListening->isChecked())
190 ARMARX_INFO <<
"Emittinging signal receivedSegmentation().";
191 emit newSourcePointCloud();
194 void UserAssistedSegmenterGuiWidgetController::onNewSourcePointCloud()
198 widget.labelPcStatus->setText(QString(
"Processing..."));
200 this->pointCloud = sourcePointCloud;
202 computeSegmentIndex(pointCloud);
204 applyFilters(pointCloud, segmentIndex);
206 updatePointCloud(pointCloud, segmentIndex);
210 widget.labelPcStatus->setText(QString(
"Current point cloud:"));
213 void UserAssistedSegmenterGuiWidgetController::onFilterSmallSegmentsNumEdited()
215 widget.checkBoxFilterSmallSegments->setChecked(
216 widget.spinBoxFilterSmallSegmentsNum->value() > 0);
219 void UserAssistedSegmenterGuiWidgetController::updateFilters()
221 applyFilters(pointCloud, segmentIndex);
222 updatePointCloud(pointCloud, segmentIndex);
225 void UserAssistedSegmenterGuiWidgetController::onRadioButtonShowInputToggled(
bool checked)
229 drawInputPointCloud(
false);
233 void UserAssistedSegmenterGuiWidgetController::onRadioButtonShowResultToggle(
bool checked)
237 drawResultPointCloud(
false);
241 void UserAssistedSegmenterGuiWidgetController::onShowIDsToggled(
bool checked)
245 drawSegmentIDs(
false);
249 drawer.clearLayer(layerSegmentIDs);
253 void UserAssistedSegmenterGuiWidgetController::updateSegmentIDs()
259 void UserAssistedSegmenterGuiWidgetController::applyFilters(
260 PointCloudT& pointCloud, std::map<uint32_t, pcl::PointIndices>& segmentIndex)
264 if (widget.checkBoxFilterSegment0)
266 auto ifLabelZero = [](
const PointT & p)
270 pointCloud.erase(std::remove_if(pointCloud.begin(), pointCloud.end(), ifLabelZero),
273 computeSegmentIndex(pointCloud);
276 if (widget.checkBoxFilterSmallSegments->isChecked())
278 const int minPoints =
std::max(0, widget.spinBoxFilterSmallSegmentsNum->value());
283 auto ifLessPoints = [&segmentIndex, minPoints](
const PointT & p)
285 return segmentIndex.at(p.label).indices.size() <
static_cast<std::size_t
>(minPoints);
287 pointCloud.erase(std::remove_if(pointCloud.begin(), pointCloud.end(), ifLessPoints),
290 computeSegmentIndex(pointCloud);
296 void UserAssistedSegmenterGuiWidgetController::updatePointCloud(
const PointCloudT& pointCloud,
const std::map<uint32_t, pcl::PointIndices>& segmentIndex)
299 computeCenters(pointCloud, segmentIndex);
301 widget.labelPcPointsNum->setText(
qstr(pointCloud.size()));
302 widget.labelPcSegmentsNum->setText(
qstr(segmentIndex.size()));
304 updateTableOverview();
305 drawInputPointCloud();
306 drawSegmentIDs(
true);
310 void UserAssistedSegmenterGuiWidgetController::computeSegmentIndex(
const PointCloudT& pointCloud)
312 segmentIndex.clear();
313 const bool excludeZero =
false;
318 void UserAssistedSegmenterGuiWidgetController::computeCenters(
319 const PointCloudT& pointCloud,
const std::map<uint32_t, pcl::PointIndices>& segmentIndex)
323 for (
const auto& [segmentID,
indices] : segmentIndex)
325 Vector3f center(0, 0, 0);
328 const PointT& p = pointCloud[
static_cast<std::size_t
>(i)];
329 center += Vector3f(p.x, p.y, p.z);
331 center /= segmentIndex.at(segmentID).indices.size();
332 centers[segmentID] = center;
337 void UserAssistedSegmenterGuiWidgetController::updateTableOverview()
339 segmentsOverviewTable->setData(segmentIndex);
343 void UserAssistedSegmenterGuiWidgetController::drawSegmentIDs(
bool onlyIfChecked)
345 if (onlyIfChecked && !widget.checkBoxShowIDs->isChecked())
350 drawer.clearLayer(layerSegmentIDs,
true);
352 for (
const auto& [segmentID, _] : segmentIndex)
354 const int textSize = widget.spinTextSize->value();
355 const int sphereSize = widget.spinSphereSize->value();
357 const DrawColor segColor = dcolor(segmentID);
358 const DrawColor textColor =
359 (segColor.r + segColor.g + segColor.b) > 1.f
360 ? DrawColor {0, 0, 0, 1}
362 DrawColor {1, 1, 1, 1};
364 drawer.drawText({layerSegmentIDs,
"id" +
str(segmentID)},
365 centers[segmentID],
str(segmentID), textSize, textColor);
366 drawer.drawSphere({layerSegmentIDs,
"sph" +
str(segmentID)},
367 centers[segmentID], sphereSize, segColor);
371 void UserAssistedSegmenterGuiWidgetController::drawInputPointCloud(
bool onlyIfChecked)
373 if (onlyIfChecked && !widget.radioButtonShowInput->isChecked())
381 drawer.drawPointCloud({layerPointCloud,
"PointCloud"}, pointCloud,
384 return dcolor(p.label);
390 void UserAssistedSegmenterGuiWidgetController::drawResultPointCloud(
bool onlyIfChecked)
392 if (onlyIfChecked && !widget.radioButtonShowResult->isChecked())
399 DebugDrawerColoredPointCloud debugPointCloud;
401 for (std::size_t group = 0; group < userGrouping.size(); ++group)
403 for (uint32_t segment : userGrouping[group])
405 for (
int i : segmentIndex.at(segment).indices)
407 PointT& p = pointCloud[
static_cast<std::size_t
>(i)];
408 debugPointCloud.points.push_back(DebugDrawerColoredPointCloudElement
410 p.x, p.y, p.z, dcolor(group)
416 drawer.drawPointCloud({layerPointCloud,
"PointCloud"}, debugPointCloud);
421 DrawColor UserAssistedSegmenterGuiWidgetController::dcolor(std::size_t
id)
const
428 return static_cast<int>(f * 255);
431 QColor UserAssistedSegmenterGuiWidgetController::qcolor(std::size_t
id)
const
433 const DrawColor
c = dcolor(
id);
437 void UserAssistedSegmenterGuiWidgetController::updateUserGroupingRows(
int numRows)
439 int previousNumRows = widget.tableUserGrouping->rowCount();
440 widget.tableUserGrouping->setRowCount(numRows);
442 std::set<uint32_t> segmentIDs;
443 for (
const auto& [segmentID, _] : segmentIndex)
445 segmentIDs.insert(segmentID);
449 for (
int id = previousNumRows;
id < numRows; ++id)
451 QTableWidgetItem* itemColor =
new QTableWidgetItem(QString());
452 itemColor->setBackgroundColor(qcolor(
static_cast<std::size_t
>(
id)));
453 widget.tableUserGrouping->setItem(
id, 0, itemColor);
455 QTableWidgetItem* itemID =
new QTableWidgetItem(
qstr(
id));
456 itemID->setTextAlignment(Qt::AlignCenter);
457 widget.tableUserGrouping->setItem(
id, 1, itemID);
460 connect(itemList, SIGNAL(groupingChanged(uint32_t, std::vector<uint32_t>)),
461 this, SLOT(onUserGroupingChanged(uint32_t, std::vector<uint32_t>)));
462 widget.tableUserGrouping->setCellWidget(
id, 2, itemList);
465 userGrouping.resize(
static_cast<std::size_t
>(numRows));
468 void UserAssistedSegmenterGuiWidgetController::onUserGroupingChanged(
469 uint32_t groupID, std::vector<uint32_t> segmentIDs)
471 if (groupID < userGrouping.size())
473 userGrouping[groupID] = segmentIDs;
475 ARMARX_INFO <<
"Updated user grouping " << groupID <<
": \n"
476 << userGrouping[groupID];
477 drawResultPointCloud(
true);
481 void UserAssistedSegmenterGuiWidgetController::onTableGroupingCellChanged(
int row,
int col)
485 widget.tableUserGrouping->item(row, col)->setText(QString());
489 widget.tableUserGrouping->item(row, col)->setText(
qstr(row));
493 void UserAssistedSegmenterGuiWidgetController::publishSegmentation()
501 visionx::ColoredLabeledPointCloud resultCloud;
503 for (std::size_t groupID = 0; groupID < userGrouping.size(); ++groupID)
505 for (uint32_t segment : userGrouping[groupID])
507 for (
int i : segmentIndex.at(segment).indices)
509 PointT& p = pointCloud.at(
static_cast<std::size_t
>(i));
510 resultCloud.push_back(visionx::ColoredLabeledPoint3D
512 visionx::Point3D { p.x, p.y, p.z },
513 visionx::RGBA { p.r, p.g, p.b, p.a },
514 static_cast<int>(groupID)
519 segmenterProxy->publishSegmentation(resultCloud);
522 void UserAssistedSegmenterGuiWidgetController::clearVisualization()
524 drawer.clearLayer(layerSegmentIDs);
525 drawer.clearLayer(layerPointCloud);
526 drawer.clearColoredPointCloud({layerPointCloud,
"PointCloud"});