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 
56 namespace armarx
57 {
59  {
63  };
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");
79  defineOptionalProperty<int>(
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");
91  defineOptionalProperty<std::string>(
92  "DebugDrawerTopicName",
93  "DebugDrawerUpdates",
94  "Name of the debug drawer topic that should be used");
95 
96  defineOptionalProperty<OpenPoseEstimationMode>(
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 
113  defineOptionalProperty<std::string>(
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.");
139  defineOptionalProperty<std::string>(
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).");
159  defineOptionalProperty<int>("MaxDepth",
160  3000,
161  "Pixels with a distance higher than this value are masked "
162  "out. Only for depth camera mode.",
164  defineOptionalProperty<int>(
165  "MaxDepthDifference",
166  700,
167  "Allowed difference of depth value for one keypoint to median of all keypoints.",
169  defineOptionalProperty<int>(
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");
177  defineOptionalProperty<std::string>(
178  "CameraNodeName", "DepthCamera", "Name of the robot node for the input camera");
179  defineOptionalProperty<bool>(
180  "FilterWithWorkspacePolygonActive",
181  true,
182  "Whether to use the WorkspacePolygon for filtering keypoints.");
183  defineOptionalProperty<std::string>(
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 
204  defineOptionalProperty<std::string>(
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,
226  virtual public armarx::ArVizComponentPluginUser
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;
279  void calculate2DFromTopic();
283  void filterToNearest();
284  void visualize3DKeypoints();
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
ArVizComponentPlugin.h
armarx::OpenPoseEstimation::Render2DResultImage
static void Render2DResultImage(const CByteImage &inputImage, const CByteImage &maskedInputImage, KeypointManagerPtr keypointManager, CByteImage &resultImage, op::PoseModel poseModel, float renderThreshold, int brightnessIncrease=100)
Definition: OpenPoseEstimation.cpp:502
armarx::OpenPoseEstimation::start3DPoseEstimation
void start3DPoseEstimation(const Ice::Current &=Ice::emptyCurrent) override
Definition: OpenPoseEstimation.cpp:747
visionx
ArmarX headers.
Definition: OpenPoseStressTest.h:38
armarx::FromStereoImage
@ FromStereoImage
Definition: OpenPoseEstimation.h:61
visionx::ImageProcessor
The ImageProcessor class provides an interface for access to ImageProviders via Ice and shared memory...
Definition: ImageProcessor.h:98
armarx::OpenPoseEstimation::stop
void stop(const Ice::Current &=Ice::emptyCurrent) override
Definition: OpenPoseEstimation.cpp:735
armarx::OpenPoseEstimation::PoseKeypoints
op::Array< float > PoseKeypoints
Definition: OpenPoseEstimation.h:229
armarx::OpenPoseEstimation::onInitImageProcessor
void onInitImageProcessor() override
Setup the vision component.
Definition: OpenPoseEstimation.cpp:76
armarx::KeypointManagerPtr
std::shared_ptr< KeypointManager > KeypointManagerPtr
Definition: KeypointManager.h:184
armarx::PropertyDefinitionContainer::prefix
std::string prefix
Prefix of the properties such as namespace, domain, component name, etc.
Definition: PropertyDefinitionContainer.h:345
armarx::KeypointObjectPtr
std::shared_ptr< KeypointObject > KeypointObjectPtr
Definition: KeypointManager.h:143
armarx::OpenPoseEstimation::process
void process() override
Process the vision component.
Definition: OpenPoseEstimation.cpp:266
armarx::OpenPoseEstimation::onExitImageProcessor
void onExitImageProcessor() override
Exit the ImapeProcessor component.
Definition: OpenPoseEstimation.cpp:261
armarx::ImageKeypointBufferPtr
std::shared_ptr< ImageKeypointBuffer > ImageKeypointBufferPtr
Definition: ImageKeypointBuffer.h:96
visionx::ImageProcessorPropertyDefinitions::ImageProcessorPropertyDefinitions
ImageProcessorPropertyDefinitions(std::string prefix)
Definition: ImageProcessor.h:64
RunningTask.h
armarx::OpenPoseEstimation::generate2DKeypoints
KeypointManagerPtr generate2DKeypoints(PoseKeypoints &keypoints, const CByteImage &rgbImage) const
Definition: OpenPoseEstimation.cpp:922
armarx::OpenPoseEstimationMode
OpenPoseEstimationMode
Definition: OpenPoseEstimation.h:58
armarx::OpenPoseEstimation::start
void start(const Ice::Current &=Ice::emptyCurrent) override
Definition: OpenPoseEstimation.cpp:719
armarx::OpenPoseEstimation
Brief description of class OpenPoseEstimation.
Definition: OpenPoseEstimation.h:223
armarx::OpenPoseEstimation::getDefaultName
std::string getDefaultName() const override
Definition: OpenPoseEstimation.h:235
visionx::ImageProviderInfo
Definition: ImageProcessor.h:479
armarx::OpenPoseEstimation::VisualizeTransparentImageMask
static void VisualizeTransparentImageMask(CByteImage &resultImage, const CByteImage &maskedInputImage, int brightnessIncrease, const CByteImage &inputImage)
Definition: OpenPoseEstimation.cpp:557
armarx::OpenPoseEstimation::onConnectImageProcessor
void onConnectImageProcessor() override
Implement this method in the ImageProcessor in order execute parts when the component is fully initia...
Definition: OpenPoseEstimation.cpp:137
armarx::ArVizComponentPluginUser
Provides a ready-to-use ArViz client arviz as member variable.
Definition: ArVizComponentPlugin.h:35
ImageProcessor.h
armarx::OpenPoseEstimation::filterKeypointsBasedOnWorkspacePolygon
void filterKeypointsBasedOnWorkspacePolygon(KeypointObjectPtr object)
Definition: OpenPoseEstimation.cpp:975
armarx::FromTopic
@ FromTopic
Definition: OpenPoseEstimation.h:62
armarx::Polygon2D
Definition: Util.h:47
armarx::OpenPoseEstimation::getDominantColorOfPatch
DrawColor24Bit getDominantColorOfPatch(const CByteImage &image, const Vec2d &point, int windowSize=10) const
Definition: OpenPoseEstimation.cpp:811
Component.h
GfxTL::Vec2d
VectorXD< 2, double > Vec2d
Definition: VectorXD.h:736
armarx::OpenPoseEstimation::calculate2DFromOpenPose
void calculate2DFromOpenPose()
Definition: OpenPoseEstimation.cpp:1004
openpose_body_25.h
armarx::OpenPoseEstimation::onDisconnectImageProcessor
void onDisconnectImageProcessor() override
Implement this method in the ImageProcessor in order execute parts when the component looses network ...
Definition: OpenPoseEstimation.cpp:244
armarx::OpenPoseEstimationPropertyDefinitions::OpenPoseEstimationPropertyDefinitions
OpenPoseEstimationPropertyDefinitions(std::string prefix)
Definition: OpenPoseEstimation.h:72
armarx::OpenPoseEstimation::calculate3DFromDepthImage
void calculate3DFromDepthImage(KeypointManagerPtr manager)
Definition: OpenPoseEstimation.cpp:1087
armarx::OpenPoseEstimation::createPropertyDefinitions
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Definition: OpenPoseEstimation.cpp:69
armarx::human::pose::model::openpose_body_25::ModelId
const std::string ModelId
Definition: openpose_body_25.h:29
IceUtil::Handle< class PropertyDefinitionContainer >
armarx::OpenPoseEstimation::visualize3DKeypoints
void visualize3DKeypoints()
Definition: OpenPoseEstimation.cpp:1191
visionx::ImageProcessorPropertyDefinitions
Definition: ImageProcessor.h:61
armarx::OpenPoseEstimation::onMessage
void onMessage(const Texting::TextMessage &text, const Ice::Current &=Ice::emptyCurrent) override
Definition: OpenPoseEstimation.cpp:863
IceInternal::ProxyHandle<::IceProxy::armarx::RobotStateComponentInterface >
armarx::OpenPoseEstimationPropertyDefinitions
Definition: OpenPoseEstimation.h:69
armarx::OpenPoseEstimation::calculate3DFromStereoImage
void calculate3DFromStereoImage(KeypointManagerPtr manager)
Definition: OpenPoseEstimation.cpp:1158
armarx::OpenPoseEstimation::getMedianDepthFromImage
int getMedianDepthFromImage(int x, int y, int radius) const
Definition: OpenPoseEstimation.cpp:1280
armarx::OpenPoseEstimation::filterToNearest
void filterToNearest()
Definition: OpenPoseEstimation.cpp:998
armarx::OpenPoseEstimation::maskOutBasedOnDepth
void maskOutBasedOnDepth(CByteImage &image, int maxDepth)
Definition: OpenPoseEstimation.cpp:779
armarx::PropertyDefinitionBase::eModifiable
@ eModifiable
Definition: PropertyDefinitionInterface.h:57
armarx::OpenPoseEstimation::stop3DPoseEstimation
void stop3DPoseEstimation(const Ice::Current &=Ice::emptyCurrent) override
Definition: OpenPoseEstimation.cpp:763
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
VirtualRobot::RobotPtr
std::shared_ptr< class Robot > RobotPtr
Definition: Bus.h:19
armarx::FromDepthImage
@ FromDepthImage
Definition: OpenPoseEstimation.h:60
armarx::OpenPoseEstimation::calculate2DFromTopic
void calculate2DFromTopic()
Definition: OpenPoseEstimation.cpp:1060
RobotStateComponent.h