OpenPoseEstimation.h
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::ArmarXObjects::OpenPoseEstimation
17 * @author Stefan Reither ( stef dot reither at web dot de )
18 * @date 2018
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22#pragma once
23
24#include <VirtualRobot/Robot.h>
25
28
30#include <RobotAPI/interface/visualization/DebugDrawerInterface.h>
32
33#include <VisionX/components/image_processor/OpenPoseEstimation/ImageKeypointBuffer.h>
34#include <VisionX/components/image_processor/OpenPoseEstimation/KeypointManager.h>
35#include <VisionX/components/image_processor/OpenPoseEstimation/Util.h>
37#include <VisionX/interface/components/OpenPoseEstimationInterface.h>
38#include <VisionX/interface/components/PointCloudAndImageAndCalibrationProviderInterface.h>
40
41#include <Calibration/Calibration.h>
42#include <Calibration/StereoCalibration.h>
43
44// OpenPose
45#include <openpose/core/headers.hpp>
46#include <openpose/pose/headers.hpp>
47#include <openpose/utilities/headers.hpp>
48
49//#ifdef OPENPOSE_MODELS
50//#define MODEL_FOLDER OPENPOSE_MODELS
51//#else
52//#define MODEL_FOLDER ""
53//#endif
54
55
56namespace armarx
57{
64
65 /**
66 * @class OpenPoseEstimationPropertyDefinitions
67 * @brief
68 */
70 {
71 public:
74 {
75 defineOptionalProperty<std::string>("OpenPoseEstimation2DTopicName",
76 "OpenPoseEstimation2D");
77 defineOptionalProperty<std::string>("OpenPoseEstimation3DTopicName",
78 "OpenPoseEstimation3D");
80 "DepthMedianRadius",
81 10,
82 "Radius of the circle around a target pixel in the depth image, which is used to "
83 "calculate the median around that pixel.");
84 defineOptionalProperty<bool>("UseDistortionParameters",
85 false,
86 "Whether to use distortion parameters when transforming "
87 "image coordinates into world coordinates");
88
89 defineRequiredProperty<std::string>("ImageProviderName",
90 "Name of the ImageProviderComponent");
92 "DebugDrawerTopicName",
93 "DebugDrawerUpdates",
94 "Name of the debug drawer topic that should be used");
95
97 "Mode",
99 "Sets the mode of this instance of OpenPoseEstiamtion. There are currently three "
100 "support modes:"
101 "'FromDepthImage', which lets the image processor expect a rgb-image and a "
102 "depth-image,"
103 "'FromStereoImage', which lets the image processor expect two images as a stereo "
104 "input "
105 "which will be used for calculating the 3D-values and"
106 "'FromTopic', which lets the image processor listen on a topic which provides "
107 "openpose-keypoints.")
108 .setMatchRegex("FromDepthImage|FromStereoImage|FromTopic")
109 .map("FromDepthImage", OpenPoseEstimationMode::FromDepthImage)
110 .map("FromStereoImage", OpenPoseEstimationMode::FromStereoImage)
111 .map("FromTopic", OpenPoseEstimationMode::FromTopic);
112
114 "OP_net_resolution",
115 "-1x368",
116 "Multiples of 16. If it is increased, the accuracy potentially increases. If it is "
117 "decreased, the speed increases. For maximum speed-accuracy balance, it should "
118 "keep the "
119 "closest aspect ratio possible to the images or videos to be processed.\n Using "
120 "`-1` in "
121 "any of the dimensions, OP will choose the optimal aspect ratio depending on the "
122 "user's "
123 "input value.\n E.g. the default `-1x368` is equivalent to `656x368` in 16:9 "
124 "resolutions, "
125 "e.g. full HD (1980x1080) and HD (1280x720) resolutions.");
126 defineOptionalProperty<std::string>("OP_output_resolution",
127 "-1x-1",
128 "The image resolution (display and output). Use "
129 "\"-1x-1\" to force the program to use the"
130 " input image resolution.");
131 defineOptionalProperty<double>("OP_scale_gap",
132 0.3,
133 "Scale gap between scales. No effect unless "
134 "scale_number > 1. Initial scale is always 1. "
135 "If you want to change the initial calib->get scale, "
136 "you actually want to multiply the "
137 "`net_resolution` by your desired initial scale.");
138 defineOptionalProperty<int>("OP_scale_number", 1, "Number of scales to average.");
140 "OP_model_pose",
142 "Model to be used. E.g. `BODY_25` (25 keypoints, best model), `COCO` (18 "
143 "keypoints), `MPI` (15 keypoints, ~10% faster), "
144 "MPI_4_layers` (15 keypoints, even faster but less accurate).");
145 defineOptionalProperty<std::string>("OP_model_folder",
146 "models/",
147 "Folder path (absolute or relative) where the "
148 "models (pose, face, ...) are located.");
149 defineOptionalProperty<int>("OP_num_gpu_start", 0, "GPU device start number.");
150 defineOptionalProperty<float>("OP_render_threshold",
151 0.05f,
152 "Only estimated keypoints whose score confidences are "
153 "higher than this threshold will be"
154 " rendered.\n Generally, a high threshold (> 0.5) will "
155 "only render very clear body parts;"
156 " while small thresholds (~0.1) will also output guessed "
157 "and occluded keypoints, but also"
158 " more false positives (i.e. wrong detections).");
160 3000,
161 "Pixels with a distance higher than this value are masked "
162 "out. Only for depth camera mode.",
165 "MaxDepthDifference",
166 700,
167 "Allowed difference of depth value for one keypoint to median of all keypoints.",
170 "MaskBrightnessIncrease",
171 100,
172 "All masked pixels will be increased by this brightness for visualization. If "
173 "value is <0, the original mask is shown.",
175
176 defineOptionalProperty<std::string>("RobotStateComponentName", "RobotStateComponent");
178 "CameraNodeName", "DepthCamera", "Name of the robot node for the input camera");
180 "FilterWithWorkspacePolygonActive",
181 true,
182 "Whether to use the WorkspacePolygon for filtering keypoints.");
184 "WorkspacePolygon",
185 "-5000,-5000;5000,-5000;5000,5000;-5000,5000;-5000,-5000",
186 "A string that describes a polygon which represents the workspace of the robot.\n"
187 "Every keypoint outside of this polygon will be masked out.\n"
188 "Every point is seperated by a ';' (semicolon) and every point is described as "
189 "'x-value, y-value' (comma-seperated).\n"
190 "The last point must be identical to the first point.");
191 defineOptionalProperty<int>("MinimalAmountKeypoints",
192 5,
193 "Minimal amount of keypoints per person. Detected persons "
194 "with less valid keypoints will be discarded.");
195 defineOptionalProperty<bool>("ReportOnlyNearestPerson",
196 false,
197 "If true, only one person is reported in the 3DTopic. The "
198 "reported person is the nearest person to the robot.");
199 defineOptionalProperty<bool>("ActivateOnStartup",
200 true,
201 "If true, poseEstimation-tasks are started after starting "
202 "the component. If false, the component idles.");
203
205 "Topic_Dimensions",
206 "480x360",
207 "Only for: 'Mode'='FromTopic'!! The dimensions of the image whose keypoints are "
208 "reported over the topic.");
209 }
210 };
211
212 /**
213 * @defgroup Component-OpenPoseEstimation OpenPoseEstimation
214 * @ingroup VisionX-Components
215 * A description of the component OpenPoseEstimation.
216 *
217 * @class OpenPoseEstimation
218 * @ingroup Component-OpenPoseEstimation
219 * @brief Brief description of class OpenPoseEstimation.
220 *
221 * Detailed description of class OpenPoseEstimation.
222 */
225 public OpenPoseEstimationInterface,
227 {
228 public:
229 using PoseKeypoints = op::Array<float>;
230
231 /**
232 * @see armarx::ManagedIceObject::getDefaultName()
233 */
234 std::string
235 getDefaultName() const override
236 {
237 return "OpenPoseEstimation";
238 }
239
240 void start(const Ice::Current& = Ice::emptyCurrent) override;
241 void stop(const Ice::Current& = Ice::emptyCurrent) override;
242 void start3DPoseEstimation(const Ice::Current& = Ice::emptyCurrent) override;
243 void stop3DPoseEstimation(const Ice::Current& = Ice::emptyCurrent) override;
244
245 /**
246 * @see PropertyUser::createPropertyDefinitions()
247 */
249 static void Render2DResultImage(const CByteImage& inputImage,
250 const CByteImage& maskedInputImage,
251 KeypointManagerPtr keypointManager,
252 CByteImage& resultImage,
253 op::PoseModel poseModel,
254 float renderThreshold,
255 int brightnessIncrease = 100);
256 static void Render2DResultImage(const CByteImage& inputImage,
257 const CByteImage& maskedInputImage,
258 PoseKeypoints& keypoints,
259 CByteImage& resultImage,
260 op::PoseModel poseModel,
261 float renderThreshold,
262 int brightnessIncrease = 100);
263 static void VisualizeTransparentImageMask(CByteImage& resultImage,
264 const CByteImage& maskedInputImage,
265 int brightnessIncrease,
266 const CByteImage& inputImage);
267
268 protected:
269 // ImageProcessor interface
270 void onInitImageProcessor() override;
271 void onConnectImageProcessor() override;
272 void onDisconnectImageProcessor() override;
273 void onExitImageProcessor() override;
274 void process() override;
275
277 const CByteImage& rgbImage) const;
283 void filterToNearest();
285
286 int getMedianDepthFromImage(int x, int y, int radius) const;
287 void maskOutBasedOnDepth(CByteImage& image, int maxDepth);
288 DrawColor24Bit getDominantColorOfPatch(const CByteImage& image,
289 const Vec2d& point,
290 int windowSize = 10) const;
291
292 //Texting interface
293 void onMessage(const Texting::TextMessage& text,
294 const Ice::Current& = Ice::emptyCurrent) override;
295
296 private:
297 // Meta (Properties)
299 std::string providerName;
300 int radius;
301 bool useDistortionParameters;
302 bool reportOnlyNearestPerson;
303 bool filterWithWorkspacePolygonActive;
304 std::string cameraNodeName;
305 Polygon2D workspacePolygon;
306 int minimalValidKeypoints;
307 float renderThreshold;
308
309 // Robot
310 RobotStateComponentInterfacePrx robotStateInterface;
311 VirtualRobot::RobotPtr localRobot;
312
313 // Keypoints
314 KeypointManagerPtr keypointManager;
315 std::mutex keypointManagerMutex;
316
317 // ImageBuffer und ImageInformations
318 CByteImage** imageBuffer;
319 CByteImage *rgbImageBuffer, *maskedrgbImageBuffer;
320 std::mutex rgbImageBufferMutex;
321 CByteImage* depthImageBuffer;
322 std::mutex depthImageBufferMutex;
323 CByteImage** openPoseResultImage;
324 std::mutex resultImageBufferMutex;
325 visionx::ImageProviderInfo imageProviderInfo;
326 armarx::MetaInfoSizeBasePtr imageMetaInfo;
327 unsigned int numImages;
328
329 // SecondHandsTopic
330 ImageKeypointBufferPtr imageKeypointBuffer;
331 visionx::ImageDimension incomingKeypointDimensions;
332
333 // Calibrations (IVT-Objects)
334 const CCalibration* calibration = nullptr;
335 CStereoCalibration* stereoCalibration = nullptr;
336
337 // Visualization
338 armarx::DebugDrawerInterfacePrx debugDrawerTopic;
339 std::string layerName;
340 int layerCounter = 0;
341
342 // Topics
343 OpenPose2DListenerPrx listener2DPrx;
344 OpenPose3DListenerPrx listener3DPrx;
345
346 // Threads and program flow information
349 bool running2D;
350 bool running3D;
351 void run();
352 bool
353 imageUpdated; // Is true, if new images are available (when mode is 'FromTopic' this also means that corresponding keypoints are available)
354 long
355 timeProvidedImage; // Contains the timestamp of the currently available images (when mode is 'FromTopic' this is also the timestamp of the corresponding keypoints)
356
357 // OpenPose
358 std::shared_ptr<op::ScaleAndSizeExtractor> scaleAndSizeExtractor;
359 std::shared_ptr<op::CvMatToOpInput> cvMatToOpInput;
360 std::shared_ptr<op::CvMatToOpOutput> cvMatToOpOutput;
361 std::shared_ptr<op::PoseExtractorCaffe> poseExtractorCaffe;
362 std::shared_ptr<op::OpOutputToCvMat> opOutputToCvMat;
363 void setupOpenPoseEnvironment();
364 PoseKeypoints getPoseKeypoints(CByteImage* imageBuffer);
365 op::PoseModel poseModel;
366
367 // ErrorCounters
368 std::uint64_t timeoutCounter2d{0};
369 std::uint64_t readErrorCounter2d{0};
370 std::uint64_t sucessCounter2d{0};
371 };
372} // namespace armarx
Provides a ready-to-use ArViz client arviz as member variable.
Brief description of class OpenPoseEstimation.
void start3DPoseEstimation(const Ice::Current &=Ice::emptyCurrent) override
void onConnectImageProcessor() override
Implement this method in the ImageProcessor in order execute parts when the component is fully initia...
void stop(const Ice::Current &=Ice::emptyCurrent) override
void onExitImageProcessor() override
Exit the ImapeProcessor component.
DrawColor24Bit getDominantColorOfPatch(const CByteImage &image, const Vec2d &point, int windowSize=10) const
void start(const Ice::Current &=Ice::emptyCurrent) override
void stop3DPoseEstimation(const Ice::Current &=Ice::emptyCurrent) override
void calculate3DFromStereoImage(KeypointManagerPtr manager)
static void VisualizeTransparentImageMask(CByteImage &resultImage, const CByteImage &maskedInputImage, int brightnessIncrease, const CByteImage &inputImage)
int getMedianDepthFromImage(int x, int y, int radius) const
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void process() override
Process the vision component.
KeypointManagerPtr generate2DKeypoints(PoseKeypoints &keypoints, const CByteImage &rgbImage) const
static void Render2DResultImage(const CByteImage &inputImage, const CByteImage &maskedInputImage, KeypointManagerPtr keypointManager, CByteImage &resultImage, op::PoseModel poseModel, float renderThreshold, int brightnessIncrease=100)
void onInitImageProcessor() override
Setup the vision component.
void calculate3DFromDepthImage(KeypointManagerPtr manager)
void maskOutBasedOnDepth(CByteImage &image, int maxDepth)
void onMessage(const Texting::TextMessage &text, const Ice::Current &=Ice::emptyCurrent) override
void onDisconnectImageProcessor() override
Implement this method in the ImageProcessor in order execute parts when the component looses network ...
void filterKeypointsBasedOnWorkspacePolygon(KeypointObjectPtr object)
std::string getDefaultName() const override
std::string prefix
Prefix of the properties such as namespace, domain, component name, etc.
PropertyDefinition< PropertyType > & defineOptionalProperty(const std::string &name, PropertyType defaultValue, const std::string &description="", PropertyDefinitionBase::PropertyConstness constness=PropertyDefinitionBase::eConstant)
PropertyDefinition< PropertyType > & defineRequiredProperty(const std::string &name, const std::string &description="", PropertyDefinitionBase::PropertyConstness constness=PropertyDefinitionBase::eConstant)
IceUtil::Handle< RunningTask< T > > pointer_type
Shared pointer type for convenience.
ImageProcessorPropertyDefinitions(std::string prefix)
The ImageProcessor class provides an interface for access to ImageProviders via Ice and shared memory...
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
std::shared_ptr< ImageKeypointBuffer > ImageKeypointBufferPtr
std::shared_ptr< KeypointManager > KeypointManagerPtr
::IceInternal::ProxyHandle<::IceProxy::armarx::RobotStateComponentInterface > RobotStateComponentInterfacePrx
std::shared_ptr< KeypointObject > KeypointObjectPtr
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugDrawerInterface > DebugDrawerInterfacePrx
ArmarX headers.