25 #include <SimoxUtility/algorithm/string.h>
29 #include <VisionX/interface/components/RGBDImageProvider.h>
42 def->topic(
listener3DPrx,
"OpenPoseEstimation3D",
"OpenPoseEstimation3DTopicName");
46 "UseDistortionParameters",
47 "Whether to use distortion parameters when transforming image coordinates into "
50 def->optional(
radius,
"DepthMedianRadius",
"Depth Median Radius");
54 "Pixels with a distance higher than this value are masked out. Only for depth camera mode.",
58 "Allowed difference of depth value for one keypoint to median of all keypoints.",
60 def->optional(
cameraNodeName,
"CameraNodeName",
"The robot node name of the camera");
62 def->optional(
brightnessIncrease,
"BrightnessIncrease",
"Increase brightness of masked pixels");
73 ARMARX_VERBOSE <<
"Trying to get StereoCalibrationInterface proxy: "
75 visionx::StereoCalibrationInterfacePrx calib =
79 ARMARX_ERROR <<
"Image provider does not provide a stereo calibration - 3D will not work - "
85 CStereoCalibration* stereoCalibration =
88 calibration = stereoCalibration->GetLeftCalibration();
138 <<
"Could not render output image for 3d pose estimation";
144 maskOutputImageBasedOnDepth();
153 if (entity.keypointMap.size() == 0)
158 std::map<std::string, int>
160 std::vector<int> depthsCopy;
163 for (
const auto& [kp_name, point] : entity.keypointMap)
165 int depth = getMedianDepthFromImage(
166 static_cast<int>(point.x),
static_cast<int>(point.y),
radius);
167 depthStorage[kp_name] = depth;
168 depthsCopy.push_back(depth);
172 std::sort(depthsCopy.begin(), depthsCopy.end());
173 const int medianDepth = depthsCopy.at(depthsCopy.size() / 2);
174 for (
auto& [storage_name, depth] : depthStorage)
176 if (depth > medianDepth + depthThreshold || depth < medianDepth - depthThreshold)
185 for (
const auto& [kp_name, point] : entity.keypointMap)
188 imagePoint.x = point.x;
189 imagePoint.y = point.y;
194 static_cast<float>(depthStorage.at(kp_name)),
211 openposeResult3D[name].keypointMap[kp_name].dominantColor = point.dominantColor;
228 RGBDOpenPoseEstimationComponentPluginUser::getMedianDepthFromImage(
int x,
int y,
int radius)
const
230 std::vector<int> depths;
231 for (
int xoffset = -
radius; xoffset <
radius; xoffset++)
233 int xo = x + xoffset;
238 for (
int yoffset = -
radius; yoffset <
radius; yoffset++)
240 int yo = y + yoffset;
247 if (xoffset * xoffset + yoffset * yoffset <=
radius *
radius)
249 unsigned int pixelPos =
256 depths.push_back(z_value);
261 std::sort(depths.begin(), depths.end());
263 return depths.empty() ? 0 : depths[depths.size() / 2];
267 RGBDOpenPoseEstimationComponentPluginUser::maskOutputImageBasedOnDepth()
281 CByteImage depthMaskImage(
283 CByteImage brightenMaskImage(
285 ::ImageProcessor::Zero(&depthMaskImage);
286 ::ImageProcessor::Zero(&brightenMaskImage);
288 for (
int i = 0; i < pixelCount; i += 1)
293 depthMaskImage.pixels[i] = z_value > depthThresholdmm || z_value == 0 ? 0 : 255;
296 ::ImageProcessor::Erode(&depthMaskImage, &depthMaskImage, 5);
297 ::ImageProcessor::Dilate(&depthMaskImage, &depthMaskImage, 20);
299 for (
int i = 0; i < pixelCount; i += 1)
301 if (depthMaskImage.pixels[i] == 0)
309 brightenMaskImage.pixels[i] = 255;
316 CByteImage smoothedImageMask(&brightenMaskImage);
317 ::ImageProcessor::GaussianSmooth5x5(&brightenMaskImage, &smoothedImageMask);
319 for (
int i = 0; i < pixelCount; i += 1)
321 if (depthMaskImage.pixels[i] == 0)
323 float perc =
static_cast<float>(smoothedImageMask.pixels[i]) / 255.f;
352 ARMARX_INFO <<
"Starting OpenposeEstimation -- 3D";
363 ARMARX_INFO <<
"Stopping OpenposeEstimation -- 3D";
370 const EnableHumanPoseEstimationInput&
input,
423 RGBDOpenPoseEstimationComponentPluginUser::filterToNearest()
430 std::vector<std::pair<std::string, HumanPose3D>> poses;
433 poses.push_back({key, humanPose});
436 std::sort(poses.begin(),
438 [](std::pair<std::string, HumanPose3D> o1, std::pair<std::string, HumanPose3D> o2)
440 auto humanPose1 = o1.second;
441 auto humanPose2 = o2.second;
442 float humanPose1AverageDepth = std::numeric_limits<float>::quiet_NaN();
443 float humanPose2AverageDepth = std::numeric_limits<float>::quiet_NaN();
444 if (humanPose1.keypointMap.size() == 0)
447 int amountDepths = 0;
448 for (const auto& [k, point] : humanPose1.keypointMap)
453 humanPose1AverageDepth = result / static_cast<float>(amountDepths);
456 if (humanPose2.keypointMap.size() == 0)
459 int amountDepths = 0;
460 for (const auto& [k, point] : humanPose2.keypointMap)
465 humanPose2AverageDepth = result /
static_cast<float>(amountDepths);
468 return humanPose1AverageDepth < humanPose2AverageDepth;
472 openposeResult3D.clear();
473 for (
const auto& p : poses)
475 openposeResult3D[p.first] = p.second;
494 std::string objectName =
"human_" + name;