-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathextract_from_image.cpp
175 lines (149 loc) · 9.52 KB
/
extract_from_image.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// ------------------------- OpenPose Library Tutorial - Pose - Example 1 - Extract from Image -------------------------
// This first example shows the user how to:
// 1. Load an image (`filestream` module)
// 2. Extract the pose of that image (`pose` module)
// 3. Render the pose on a resized copy of the input image (`pose` module)
// 4. Display the rendered pose (`gui` module)
// In addition to the previous OpenPose modules, we also need to use:
// 1. `core` module: for the Array<float> class that the `pose` module needs
// 2. `utilities` module: for the error & logging functions, i.e. op::error & op::log respectively
// 3rdparty dependencies
// GFlags: DEFINE_bool, _int32, _int64, _uint64, _double, _string
#include <gflags/gflags.h>
#include <iostream>
// Allow Google Flags in Ubuntu 14
#ifndef GFLAGS_GFLAGS_H_
namespace gflags = google;
#endif
// OpenPose dependencies
#include <openpose/core/headers.hpp>
#include <openpose/filestream/headers.hpp>
#include <openpose/gui/headers.hpp>
#include <openpose/pose/headers.hpp>
#include <openpose/utilities/headers.hpp>
#include <UpperBodyRaisedHandPredictor.h>
#include "extract_utils.h"
#include "keras_model.h"
// See all the available parameter options withe the `--help` flag. E.g. `build/examples/openpose/openpose.bin --help`
// Note: Thfind `pwd` -name .htaccessommand will show you flags for other unnecessary 3rdparty files. Check only the flags for the OpenPose
// executable. E.g. for `openpose.bin`, look for `Flags from examples/openpose/openpose.cpp:`.
// Debugging/Other
DEFINE_int32(logging_level, 3, "The logging level. Integer in the range [0, 255]. 0 will output any log() message, while"
" 255 will not output any. Current OpenPose library messages are in the range 0-4: 1 for"
" low priority messages and 4 for important ones.");
// Producer
DEFINE_string(image_path, "/Users/npahucki/Projects/Edmodo/gestures/images/training/NONE/4.jpg", "Process the desired image.");
// OpenPose
DEFINE_string(model_pose, "BODY_25", "Model to be used. E.g. `COCO` (18 keypoints), `MPI` (15 keypoints, ~10% faster), "
"`MPI_4_layers` (15 keypoints, even faster but less accurate).");
DEFINE_string(model_folder, "models/", "Folder path (absolute or relative) where the models (pose, face, ...) are located.");
DEFINE_string(net_resolution, "-1x368", "Multiples of 16. If it is increased, the accuracy potentially increases. If it is"
" decreased, the speed increases. For maximum speed-accuracy balance, it should keep the"
" closest aspect ratio possible to the images or videos to be processed. Using `-1` in"
" any of the dimensions, OP will choose the optimal aspect ratio depending on the user's"
" input value. E.g. the default `-1x368` is equivalent to `656x368` in 16:9 resolutions,"
" e.g. full HD (1980x1080) and HD (1280x720) resolutions.");
DEFINE_string(output_resolution, "-1x-1", "The image resolution (display and output). Use \"-1x-1\" to force the program to use the"
" input image resolution.");
DEFINE_int32(num_gpu_start, 0, "GPU device start number.");
// OpenPose Rendering
DEFINE_bool(disable_display, false, "If enabled, it will not show a window, and only output the distances to the console");
DEFINE_bool(disable_blending, false, "If enabled, it will render the results (keypoint skeletons or heatmaps) on a black"
" background, instead of being rendered into the original image. Related: `part_to_show`,"
" `alpha_pose`, and `alpha_pose`.");
DEFINE_double(render_threshold, 0.05, "Only estimated keypoints whose score confidences are higher than this threshold will be"
" rendered. Generally, a high threshold (> 0.5) will only render very clear body parts;"
" while small thresholds (~0.1) will also output guessed and occluded keypoints, but also"
" more false positives (i.e. wrong detections).");
DEFINE_double(alpha_pose, 0.6, "Blending factor (range 0-1) for the body part rendering. 1 will show it completely, 0 will"
" hide it. Only valid for GPU rendering.");
int processInputs()
{
try
{
if (!FLAGS_disable_display) {
op::log("Starting Conversion...", op::Priority::High);
}
op::check(0 <= FLAGS_logging_level && FLAGS_logging_level <= 255, "Wrong logging_level value.", __LINE__, __FUNCTION__, __FILE__);
op::ConfigureLog::setPriorityThreshold((op::Priority)FLAGS_logging_level);
op::log("", op::Priority::Low, __LINE__, __FUNCTION__, __FILE__);
// Read Google flags (user defined configuration)
// outputSize
const auto outputSize = op::flagsToPoint(FLAGS_output_resolution, "-1x-1");
// netInputSize
const auto netInputSize = op::flagsToPoint(FLAGS_net_resolution, "-1x368");
// poseModel
const auto poseModel = op::flagsToPoseModel(FLAGS_model_pose);
// Check no contradictory flags enabled
if (FLAGS_alpha_pose < 0. || FLAGS_alpha_pose > 1.)
op::error("Alpha value for blending must be in the range [0,1].", __LINE__, __FUNCTION__, __FILE__);
// Logging
op::log("", op::Priority::Low, __LINE__, __FUNCTION__, __FILE__);
// Step 3 - Initialize all required classes
op::ScaleAndSizeExtractor scaleAndSizeExtractor(netInputSize, outputSize, 1, 0.3);
op::CvMatToOpInput cvMatToOpInput{poseModel};
op::CvMatToOpOutput cvMatToOpOutput;
op::PoseExtractorCaffe poseExtractorCaffe{poseModel, FLAGS_model_folder, FLAGS_num_gpu_start};
op::PoseCpuRenderer poseRenderer{poseModel, (float)FLAGS_render_threshold, !FLAGS_disable_blending,
(float)FLAGS_alpha_pose};
op::OpOutputToCvMat opOutputToCvMat;
op::FrameDisplayer frameDisplayer{"Edmodo OpenPose Point Extractor", outputSize};
UpperBodyRaisedHandPredictor predictor{FLAGS_model_folder};
poseExtractorCaffe.initializationOnThread();
poseRenderer.initializationOnThread();
// ------------------------- POSE ESTIMATION AND RENDERING -------------------------
// Step 1 - Read and load image, error if empty (possibly wrong path)
// Alternative: cv::imread(FLAGS_image_path, CV_LOAD_IMAGE_COLOR);
cv::Mat inputImage = op::loadImage(FLAGS_image_path, CV_LOAD_IMAGE_COLOR);
if(inputImage.empty())
op::error("Could not open or find the image: " + FLAGS_image_path, __LINE__, __FUNCTION__, __FILE__);
const op::Point<int> imageSize{inputImage.cols, inputImage.rows};
// Step 2 - Get desired scale sizes
std::vector<double> scaleInputToNetInputs;
std::vector<op::Point<int>> netInputSizes;
double scaleInputToOutput;
op::Point<int> outputResolution;
std::tie(scaleInputToNetInputs, netInputSizes, scaleInputToOutput, outputResolution)
= scaleAndSizeExtractor.extract(imageSize);
// Step 3 - Format input image to OpenPose input and output formats
const auto netInputArray = cvMatToOpInput.createArray(inputImage, scaleInputToNetInputs, netInputSizes);
auto outputArray = cvMatToOpOutput.createArray(inputImage, scaleInputToOutput, outputResolution);
poseExtractorCaffe.forwardPass(netInputArray, imageSize, scaleInputToNetInputs);
const auto poseKeypoints = poseExtractorCaffe.getPoseKeypoints();
std::cout << keypointsAsNumpyTextString(poseKeypoints, {0,1,2,3,4,5,6,7}) << std::endl;
const ArmRaised prediction = predictor.predictRasiedArm(poseKeypoints, 0);
switch(prediction) {
std::cerr << "PREDICTION: ";
case ArmRaised::NONE:
std::cerr << "No Arm Raised" << std::endl;
break;
case ArmRaised::RIGHT:
std::cerr << "Right Arm Raised" << std::endl;
break;
case ArmRaised::LEFT:
std::cerr << "Left Arm Raised" << std::endl;
break;
default:
std::cerr << "Unknown!!" << std::endl;
break;
}
if(!FLAGS_disable_display) {
poseRenderer.renderPose(outputArray, poseKeypoints, scaleInputToOutput);
auto outputImage = opOutputToCvMat.formatToCvMat(outputArray);
frameDisplayer.displayFrame(outputImage, 0); // Alternative: cv::imshow(outputImage) + cv::waitKey(0)
}
return 0;
}
catch (const std::exception& e)
{
op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return -1;
}
}
int main(int argc, char *argv[])
{
// Parsing command line flags
gflags::ParseCommandLineFlags(&argc, &argv, true);
// Running processInputs
return processInputs();
}