提交 7a9a3283 编写于 作者: G gineshidalgo99

Added flag 3d_min_views

上级 18266eb8
...@@ -184,8 +184,9 @@ Each flag is divided into flag name, default value, and description. ...@@ -184,8 +184,9 @@ Each flag is divided into flag name, default value, and description.
- DEFINE_bool(hand_tracking, false, "Adding hand tracking might improve hand keypoints detection for webcam (if the frame rate is high enough, i.e. >7 FPS per GPU) and video. This is not person ID tracking, it simply looks for hands in positions at which hands were located in previous frames, but it does not guarantee the same person ID among frames."); - DEFINE_bool(hand_tracking, false, "Adding hand tracking might improve hand keypoints detection for webcam (if the frame rate is high enough, i.e. >7 FPS per GPU) and video. This is not person ID tracking, it simply looks for hands in positions at which hands were located in previous frames, but it does not guarantee the same person ID among frames.");
8. OpenPose 3-D Reconstruction 8. OpenPose 3-D Reconstruction
DEFINE_bool(3d, false, "Running OpenPose 3-D reconstruction demo: 1) Reading from a stereo camera system. 2) Performing 3-D reconstruction from the multiple views. 3) Displaying 3-D reconstruction results. Note that it will only display 1 person. If multiple people is present, it will fail."); - DEFINE_bool(3d, false, "Running OpenPose 3-D reconstruction demo: 1) Reading from a stereo camera system. 2) Performing 3-D reconstruction from the multiple views. 3) Displaying 3-D reconstruction results. Note that it will only display 1 person. If multiple people is present, it will fail.");
DEFINE_int32(3d_views, 1, "Complementary option to `--image_dir` or `--video`. OpenPose will read as many images per iteration, allowing tasks such as stereo camera processing (`--3d`). Note that `--camera_parameters_folder` must be set. OpenPose must find as many `xml` files in the parameter folder as this number indicates."); - DEFINE_int32(3d_min_views, -1, "Minimum number of views required to reconstruct each keypoint. By default (-1), it will require all the cameras to see the keypoint in order to reconstruct it.");
- DEFINE_int32(3d_views, 1, "Complementary option to `--image_dir` or `--video`. OpenPose will read as many images per iteration, allowing tasks such as stereo camera processing (`--3d`). Note that `--camera_parameters_folder` must be set. OpenPose must find as many `xml` files in the parameter folder as this number indicates.");
9. OpenPose Rendering 9. OpenPose Rendering
- DEFINE_int32(part_to_show, 0, "Prediction channel to visualize (default: 0). 0 for all the body parts, 1-18 for each body part heat map, 19 for the background heat map, 20 for all the body part heat maps together, 21 for all the PAFs, 22-40 for each body part pair PAF."); - DEFINE_int32(part_to_show, 0, "Prediction channel to visualize (default: 0). 0 for all the body parts, 1-18 for each body part heat map, 19 for the background heat map, 20 for all the body part heat maps together, 21 for all the PAFs, 22-40 for each body part pair PAF.");
......
...@@ -147,13 +147,20 @@ build\x64\Release\OpenPoseDemo.exe --flir_camera --3d --number_people_max 1 --fa ...@@ -147,13 +147,20 @@ build\x64\Release\OpenPoseDemo.exe --flir_camera --3d --number_people_max 1 --fa
# Ubuntu (same flags for Windows version) # Ubuntu (same flags for Windows version)
# Optionally add `--face` and/or `--hand` to include face and/or hands # Optionally add `--face` and/or `--hand` to include face and/or hands
# Assuming 3 cameras # Assuming 3 cameras
# Note: We highly recommend to reduce `--output_resolution`. E.g. for 3 cameras recording at 1920x1080, the resulting image is (3x1920)x1080, so we recommend e.g. 1920x360 (x3 reduction). # Note: We highly recommend to reduce `--output_resolution`. E.g. for 3 cameras recording at 1920x1080, the resulting image is (3x1920)x1080, so we recommend e.g. 640x360 (x3 reduction).
# Video # Video
./build/examples/openpose/openpose.bin --video output_folder_path/video.avi --3d_views 3 --3d --number_people_max 1 --output_resolution {desired_output_resolution} ./build/examples/openpose/openpose.bin --video output_folder_path/video.avi --3d_views 3 --3d --number_people_max 1 --output_resolution {desired_output_resolution}
# Images # Images
./build/examples/openpose/openpose.bin --image_dir output_folder_path/ --3d_views 3 --3d --number_people_max 1 --output_resolution {desired_output_resolution} ./build/examples/openpose/openpose.bin --image_dir output_folder_path/ --3d_views 3 --3d --number_people_max 1 --output_resolution {desired_output_resolution}
``` ```
5. Reconstruction when at least n visible views
```
# Ubuntu (same flags for Windows version)
# Assuming >=2 cameras and reconstruction when at least 2 visible views
./build/examples/openpose/openpose.bin --flir_camera --3d --number_people_max 1 --3d_min_views 2 --output_resolution {desired_output_resolution}
```
## Expected Visual Results ## Expected Visual Results
......
...@@ -193,7 +193,8 @@ OpenPose Library - Release Notes ...@@ -193,7 +193,8 @@ OpenPose Library - Release Notes
21. VideoSaver (`--write_video`) compatible with multi-camera setting. It will save all the different views concatenated. 21. VideoSaver (`--write_video`) compatible with multi-camera setting. It will save all the different views concatenated.
22. OpenPose small GUI rescale the verbose text to the displayed image, to avoid the text to be either too big or small. 22. OpenPose small GUI rescale the verbose text to the displayed image, to avoid the text to be either too big or small.
23. OpenPose small GUI shows the frame number w.r.t. the original producer, rather than the frame id. E.g., if video is started at frame 30, OpenPose will display 30 rather than 0 in the first frame. 23. OpenPose small GUI shows the frame number w.r.t. the original producer, rather than the frame id. E.g., if video is started at frame 30, OpenPose will display 30 rather than 0 in the first frame.
23. OpenPose GUI: 'l' and 'k' functionality swapped. 24. OpenPose GUI: 'l' and 'k' functionality swapped.
25. 3-D reconstruction module: Added flag `--3d_min_views` to select minimum number of cameras required for 3-D reconstruction.
2. Functions or parameters renamed: 2. Functions or parameters renamed:
1. Flag `no_display` renamed as `display`, able to select between `NoDisplay`, `Display2D`, `Display3D`, and `DisplayAll`. 1. Flag `no_display` renamed as `display`, able to select between `NoDisplay`, `Display2D`, `Display3D`, and `DisplayAll`.
2. 3-D reconstruction demo is now inside the OpenPose demo binary. 2. 3-D reconstruction demo is now inside the OpenPose demo binary.
......
...@@ -147,6 +147,8 @@ DEFINE_bool(3d, false, "Running OpenPose 3-D re ...@@ -147,6 +147,8 @@ DEFINE_bool(3d, false, "Running OpenPose 3-D re
" 2) Performing 3-D reconstruction from the multiple views. 3) Displaying 3-D reconstruction" " 2) Performing 3-D reconstruction from the multiple views. 3) Displaying 3-D reconstruction"
" results. Note that it will only display 1 person. If multiple people is present, it will" " results. Note that it will only display 1 person. If multiple people is present, it will"
" fail."); " fail.");
DEFINE_int32(3d_min_views, -1, "Minimum number of views required to reconstruct each keypoint. By default (-1), it will"
" require all the cameras to see the keypoint in order to reconstruct it.");
DEFINE_int32(3d_views, 1, "Complementary option to `--image_dir` or `--video`. OpenPose will read as many images per" DEFINE_int32(3d_views, 1, "Complementary option to `--image_dir` or `--video`. OpenPose will read as many images per"
" iteration, allowing tasks such as stereo camera processing (`--3d`). Note that" " iteration, allowing tasks such as stereo camera processing (`--3d`). Note that"
" `--camera_parameters_folder` must be set. OpenPose must find as many `xml` files in the" " `--camera_parameters_folder` must be set. OpenPose must find as many `xml` files in the"
...@@ -276,7 +278,8 @@ int openPoseDemo() ...@@ -276,7 +278,8 @@ int openPoseDemo()
(float)FLAGS_alpha_heatmap, FLAGS_part_to_show, FLAGS_model_folder, (float)FLAGS_alpha_heatmap, FLAGS_part_to_show, FLAGS_model_folder,
heatMapTypes, heatMapScale, FLAGS_part_candidates, heatMapTypes, heatMapScale, FLAGS_part_candidates,
(float)FLAGS_render_threshold, FLAGS_number_people_max, (float)FLAGS_render_threshold, FLAGS_number_people_max,
enableGoogleLogging, FLAGS_3d, FLAGS_identification}; enableGoogleLogging, FLAGS_3d, FLAGS_3d_min_views,
FLAGS_identification};
// Face configuration (use op::WrapperStructFace{} to disable it) // Face configuration (use op::WrapperStructFace{} to disable it)
const op::WrapperStructFace wrapperStructFace{FLAGS_face, faceNetInputSize, const op::WrapperStructFace wrapperStructFace{FLAGS_face, faceNetInputSize,
op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose),
......
...@@ -156,6 +156,8 @@ DEFINE_bool(3d, false, "Running OpenPose 3-D re ...@@ -156,6 +156,8 @@ DEFINE_bool(3d, false, "Running OpenPose 3-D re
" 2) Performing 3-D reconstruction from the multiple views. 3) Displaying 3-D reconstruction" " 2) Performing 3-D reconstruction from the multiple views. 3) Displaying 3-D reconstruction"
" results. Note that it will only display 1 person. If multiple people is present, it will" " results. Note that it will only display 1 person. If multiple people is present, it will"
" fail."); " fail.");
DEFINE_int32(3d_min_views, -1, "Minimum number of views required to reconstruct each keypoint. By default (-1), it will"
" require all the cameras to see the keypoint in order to reconstruct it.");
DEFINE_int32(3d_views, 1, "Complementary option to `--image_dir` or `--video`. OpenPose will read as many images per" DEFINE_int32(3d_views, 1, "Complementary option to `--image_dir` or `--video`. OpenPose will read as many images per"
" iteration, allowing tasks such as stereo camera processing (`--3d`). Note that" " iteration, allowing tasks such as stereo camera processing (`--3d`). Note that"
" `--camera_parameters_folder` must be set. OpenPose must find as many `xml` files in the" " `--camera_parameters_folder` must be set. OpenPose must find as many `xml` files in the"
...@@ -278,7 +280,7 @@ int openPoseTutorialWrapper4() ...@@ -278,7 +280,7 @@ int openPoseTutorialWrapper4()
(float)FLAGS_alpha_heatmap, FLAGS_part_to_show, FLAGS_model_folder, (float)FLAGS_alpha_heatmap, FLAGS_part_to_show, FLAGS_model_folder,
heatMapTypes, heatMapScale, FLAGS_part_candidates, heatMapTypes, heatMapScale, FLAGS_part_candidates,
(float)FLAGS_render_threshold, FLAGS_number_people_max, (float)FLAGS_render_threshold, FLAGS_number_people_max,
enableGoogleLogging, FLAGS_3d}; enableGoogleLogging, FLAGS_3d, FLAGS_3d_min_views};
// Face configuration (use op::WrapperStructFace{} to disable it) // Face configuration (use op::WrapperStructFace{} to disable it)
const op::WrapperStructFace wrapperStructFace{FLAGS_face, faceNetInputSize, const op::WrapperStructFace wrapperStructFace{FLAGS_face, faceNetInputSize,
op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose),
......
...@@ -146,6 +146,8 @@ DEFINE_bool(3d, false, "Running OpenPose 3-D re ...@@ -146,6 +146,8 @@ DEFINE_bool(3d, false, "Running OpenPose 3-D re
" 2) Performing 3-D reconstruction from the multiple views. 3) Displaying 3-D reconstruction" " 2) Performing 3-D reconstruction from the multiple views. 3) Displaying 3-D reconstruction"
" results. Note that it will only display 1 person. If multiple people is present, it will" " results. Note that it will only display 1 person. If multiple people is present, it will"
" fail."); " fail.");
DEFINE_int32(3d_min_views, -1, "Minimum number of views required to reconstruct each keypoint. By default (-1), it will"
" require all the cameras to see the keypoint in order to reconstruct it.");
DEFINE_int32(3d_views, 1, "Complementary option to `--image_dir` or `--video`. OpenPose will read as many images per" DEFINE_int32(3d_views, 1, "Complementary option to `--image_dir` or `--video`. OpenPose will read as many images per"
" iteration, allowing tasks such as stereo camera processing (`--3d`). Note that" " iteration, allowing tasks such as stereo camera processing (`--3d`). Note that"
" `--camera_parameters_folder` must be set. OpenPose must find as many `xml` files in the" " `--camera_parameters_folder` must be set. OpenPose must find as many `xml` files in the"
...@@ -353,7 +355,7 @@ int openPoseTutorialWrapper1() ...@@ -353,7 +355,7 @@ int openPoseTutorialWrapper1()
(float)FLAGS_alpha_heatmap, FLAGS_part_to_show, FLAGS_model_folder, (float)FLAGS_alpha_heatmap, FLAGS_part_to_show, FLAGS_model_folder,
heatMapTypes, heatMapScale, FLAGS_part_candidates, heatMapTypes, heatMapScale, FLAGS_part_candidates,
(float)FLAGS_render_threshold, FLAGS_number_people_max, (float)FLAGS_render_threshold, FLAGS_number_people_max,
enableGoogleLogging, FLAGS_3d}; enableGoogleLogging, FLAGS_3d, FLAGS_3d_min_views};
// Face configuration (use op::WrapperStructFace{} to disable it) // Face configuration (use op::WrapperStructFace{} to disable it)
const op::WrapperStructFace wrapperStructFace{FLAGS_face, faceNetInputSize, const op::WrapperStructFace wrapperStructFace{FLAGS_face, faceNetInputSize,
op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose),
......
...@@ -125,6 +125,8 @@ DEFINE_bool(3d, false, "Running OpenPose 3-D re ...@@ -125,6 +125,8 @@ DEFINE_bool(3d, false, "Running OpenPose 3-D re
" 2) Performing 3-D reconstruction from the multiple views. 3) Displaying 3-D reconstruction" " 2) Performing 3-D reconstruction from the multiple views. 3) Displaying 3-D reconstruction"
" results. Note that it will only display 1 person. If multiple people is present, it will" " results. Note that it will only display 1 person. If multiple people is present, it will"
" fail."); " fail.");
DEFINE_int32(3d_min_views, -1, "Minimum number of views required to reconstruct each keypoint. By default (-1), it will"
" require all the cameras to see the keypoint in order to reconstruct it.");
DEFINE_int32(3d_views, 1, "Complementary option to `--image_dir` or `--video`. OpenPose will read as many images per" DEFINE_int32(3d_views, 1, "Complementary option to `--image_dir` or `--video`. OpenPose will read as many images per"
" iteration, allowing tasks such as stereo camera processing (`--3d`). Note that" " iteration, allowing tasks such as stereo camera processing (`--3d`). Note that"
" `--camera_parameters_folder` must be set. OpenPose must find as many `xml` files in the" " `--camera_parameters_folder` must be set. OpenPose must find as many `xml` files in the"
...@@ -443,7 +445,7 @@ int openPoseTutorialWrapper2() ...@@ -443,7 +445,7 @@ int openPoseTutorialWrapper2()
(float)FLAGS_alpha_heatmap, FLAGS_part_to_show, FLAGS_model_folder, (float)FLAGS_alpha_heatmap, FLAGS_part_to_show, FLAGS_model_folder,
heatMapTypes, heatMapScale, FLAGS_part_candidates, heatMapTypes, heatMapScale, FLAGS_part_candidates,
(float)FLAGS_render_threshold, FLAGS_number_people_max, (float)FLAGS_render_threshold, FLAGS_number_people_max,
enableGoogleLogging, FLAGS_3d}; enableGoogleLogging, FLAGS_3d, FLAGS_3d_min_views};
// Face configuration (use op::WrapperStructFace{} to disable it) // Face configuration (use op::WrapperStructFace{} to disable it)
const op::WrapperStructFace wrapperStructFace{FLAGS_face, faceNetInputSize, const op::WrapperStructFace wrapperStructFace{FLAGS_face, faceNetInputSize,
op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose),
......
...@@ -125,6 +125,8 @@ DEFINE_bool(3d, false, "Running OpenPose 3-D re ...@@ -125,6 +125,8 @@ DEFINE_bool(3d, false, "Running OpenPose 3-D re
" 2) Performing 3-D reconstruction from the multiple views. 3) Displaying 3-D reconstruction" " 2) Performing 3-D reconstruction from the multiple views. 3) Displaying 3-D reconstruction"
" results. Note that it will only display 1 person. If multiple people is present, it will" " results. Note that it will only display 1 person. If multiple people is present, it will"
" fail."); " fail.");
DEFINE_int32(3d_min_views, -1, "Minimum number of views required to reconstruct each keypoint. By default (-1), it will"
" require all the cameras to see the keypoint in order to reconstruct it.");
DEFINE_int32(3d_views, 1, "Complementary option to `--image_dir` or `--video`. OpenPose will read as many images per" DEFINE_int32(3d_views, 1, "Complementary option to `--image_dir` or `--video`. OpenPose will read as many images per"
" iteration, allowing tasks such as stereo camera processing (`--3d`). Note that" " iteration, allowing tasks such as stereo camera processing (`--3d`). Note that"
" `--camera_parameters_folder` must be set. OpenPose must find as many `xml` files in the" " `--camera_parameters_folder` must be set. OpenPose must find as many `xml` files in the"
...@@ -384,7 +386,7 @@ int openPoseTutorialWrapper3() ...@@ -384,7 +386,7 @@ int openPoseTutorialWrapper3()
(float)FLAGS_alpha_heatmap, FLAGS_part_to_show, FLAGS_model_folder, (float)FLAGS_alpha_heatmap, FLAGS_part_to_show, FLAGS_model_folder,
heatMapTypes, heatMapScale, FLAGS_part_candidates, heatMapTypes, heatMapScale, FLAGS_part_candidates,
(float)FLAGS_render_threshold, FLAGS_number_people_max, (float)FLAGS_render_threshold, FLAGS_number_people_max,
enableGoogleLogging, FLAGS_3d}; enableGoogleLogging, FLAGS_3d, FLAGS_3d_min_views};
// Face configuration (use op::WrapperStructFace{} to disable it) // Face configuration (use op::WrapperStructFace{} to disable it)
const op::WrapperStructFace wrapperStructFace{FLAGS_face, faceNetInputSize, const op::WrapperStructFace wrapperStructFace{FLAGS_face, faceNetInputSize,
op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose),
......
...@@ -6,8 +6,17 @@ ...@@ -6,8 +6,17 @@
namespace op namespace op
{ {
OP_API Array<float> reconstructArray(const std::vector<Array<float>>& keypointsVector, class OP_API PoseTriangulation
const std::vector<cv::Mat>& matrixEachCamera); {
public:
PoseTriangulation(const int minViews3d);
Array<float> reconstructArray(const std::vector<Array<float>>& keypointsVector,
const std::vector<cv::Mat>& cameraMatrices) const;
private:
const int mMinViews3d;
};
} }
#endif // OPENPOSE_3D_POSE_TRIANGULATION_HPP #endif // OPENPOSE_3D_POSE_TRIANGULATION_HPP
...@@ -11,13 +11,15 @@ namespace op ...@@ -11,13 +11,15 @@ namespace op
class WPoseTriangulation : public Worker<TDatums> class WPoseTriangulation : public Worker<TDatums>
{ {
public: public:
explicit WPoseTriangulation(); explicit WPoseTriangulation(const std::shared_ptr<PoseTriangulation>& poseTriangulation);
void initializationOnThread(); void initializationOnThread();
void work(TDatums& tDatums); void work(TDatums& tDatums);
private: private:
const std::shared_ptr<PoseTriangulation> spPoseTriangulation;
DELETE_COPY(WPoseTriangulation); DELETE_COPY(WPoseTriangulation);
}; };
} }
...@@ -31,7 +33,8 @@ namespace op ...@@ -31,7 +33,8 @@ namespace op
namespace op namespace op
{ {
template<typename TDatums> template<typename TDatums>
WPoseTriangulation<TDatums>::WPoseTriangulation() WPoseTriangulation<TDatums>::WPoseTriangulation(const std::shared_ptr<PoseTriangulation>& poseTriangulation) :
spPoseTriangulation{poseTriangulation}
{ {
} }
...@@ -66,10 +69,12 @@ namespace op ...@@ -66,10 +69,12 @@ namespace op
cameraMatrices.emplace_back(datumsElement.cameraMatrix); cameraMatrices.emplace_back(datumsElement.cameraMatrix);
} }
// Pose 3-D reconstruction // Pose 3-D reconstruction
auto poseKeypoints3D = reconstructArray(poseKeypointVector, cameraMatrices); auto poseKeypoints3D = spPoseTriangulation->reconstructArray(poseKeypointVector, cameraMatrices);
auto faceKeypoints3D = reconstructArray(faceKeypointVector, cameraMatrices); auto faceKeypoints3D = spPoseTriangulation->reconstructArray(faceKeypointVector, cameraMatrices);
auto leftHandKeypoints3D = reconstructArray(leftHandKeypointVector, cameraMatrices); auto leftHandKeypoints3D = spPoseTriangulation->reconstructArray(leftHandKeypointVector,
auto rightHandKeypoints3D = reconstructArray(rightHandKeypointVector, cameraMatrices); cameraMatrices);
auto rightHandKeypoints3D = spPoseTriangulation->reconstructArray(rightHandKeypointVector,
cameraMatrices);
// Assign to all tDatums // Assign to all tDatums
for (auto& datumsElement : *tDatums) for (auto& datumsElement : *tDatums)
{ {
......
...@@ -49,6 +49,11 @@ namespace op ...@@ -49,6 +49,11 @@ namespace op
*/ */
void displayFrame(const cv::Mat& frame, const int waitKeyValue = -1); void displayFrame(const cv::Mat& frame, const int waitKeyValue = -1);
/**
* Analogous to the previous displayFrame, but first it horizontally concatenates all the frames
*/
void displayFrame(const std::vector<cv::Mat>& frames, const int waitKeyValue = -1);
private: private:
const std::string mWindowName; const std::string mWindowName;
Point<int> mWindowedSize; Point<int> mWindowedSize;
......
...@@ -798,8 +798,9 @@ namespace op ...@@ -798,8 +798,9 @@ namespace op
// 3-D reconstruction // 3-D reconstruction
if (wrapperStructPose.reconstruct3d) if (wrapperStructPose.reconstruct3d)
{ {
const auto poseTriangulation = std::make_shared<PoseTriangulation>(wrapperStructPose.minViews3d);
mPostProcessingWs.emplace_back( mPostProcessingWs.emplace_back(
std::make_shared<WPoseTriangulation<TDatumsPtr>>() std::make_shared<WPoseTriangulation<TDatumsPtr>>(poseTriangulation)
); );
} }
// Frames processor (OpenPose format -> cv::Mat format) // Frames processor (OpenPose format -> cv::Mat format)
......
...@@ -21,13 +21,13 @@ namespace op ...@@ -21,13 +21,13 @@ namespace op
* @param threadManagerMode * @param threadManagerMode
*/ */
OP_API void wrapperConfigureSecurityChecks(const WrapperStructPose& wrapperStructPose, OP_API void wrapperConfigureSecurityChecks(const WrapperStructPose& wrapperStructPose,
const WrapperStructFace& wrapperStructFace, const WrapperStructFace& wrapperStructFace,
const WrapperStructHand& wrapperStructHand, const WrapperStructHand& wrapperStructHand,
const WrapperStructInput& wrapperStructInput, const WrapperStructInput& wrapperStructInput,
const WrapperStructOutput& wrapperStructOutput, const WrapperStructOutput& wrapperStructOutput,
const bool renderOutput, const bool renderOutput,
const bool userOutputWsEmpty, const bool userOutputWsEmpty,
const ThreadManagerMode threadManagerMode); const ThreadManagerMode threadManagerMode);
} }
#endif // OPENPOSE_WRAPPER_WRAPPER_AUXILIARY_HPP #endif // OPENPOSE_WRAPPER_WRAPPER_AUXILIARY_HPP
...@@ -175,6 +175,12 @@ namespace op ...@@ -175,6 +175,12 @@ namespace op
*/ */
bool reconstruct3d; bool reconstruct3d;
/**
* Minimum number of views required to reconstruct each keypoint.
* By default (-1), it will require all the cameras to see the keypoint in order to reconstruct it.
*/
int minViews3d;
/** /**
* Whether to return a person ID for each body skeleton, providing temporal consistency. * Whether to return a person ID for each body skeleton, providing temporal consistency.
*/ */
...@@ -198,7 +204,7 @@ namespace op ...@@ -198,7 +204,7 @@ namespace op
const ScaleMode heatMapScale = ScaleMode::ZeroToOne, const bool addPartCandidates = false, const ScaleMode heatMapScale = ScaleMode::ZeroToOne, const bool addPartCandidates = false,
const float renderThreshold = 0.05f, const int numberPeopleMax = -1, const float renderThreshold = 0.05f, const int numberPeopleMax = -1,
const bool enableGoogleLogging = true, const bool reconstruct3d = false, const bool enableGoogleLogging = true, const bool reconstruct3d = false,
const bool identification = false); const int minViews3d = -1, const bool identification = false);
}; };
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace op namespace op
{ {
double calcReprojectionError(const cv::Mat& X, const std::vector<cv::Mat>& M, double calcReprojectionError(const cv::Mat& reconstructedPoint, const std::vector<cv::Mat>& M,
const std::vector<cv::Point2d>& points2d) const std::vector<cv::Point2d>& points2d)
{ {
try try
...@@ -11,7 +11,7 @@ namespace op ...@@ -11,7 +11,7 @@ namespace op
auto averageError = 0.; auto averageError = 0.;
for (auto i = 0u ; i < M.size() ; i++) for (auto i = 0u ; i < M.size() ; i++)
{ {
cv::Mat imageX = M[i] * X; cv::Mat imageX = M[i] * reconstructedPoint;
imageX /= imageX.at<double>(2,0); imageX /= imageX.at<double>(2,0);
const auto error = std::sqrt(std::pow(imageX.at<double>(0,0) - points2d[i].x,2) const auto error = std::sqrt(std::pow(imageX.at<double>(0,0) - points2d[i].x,2)
+ std::pow(imageX.at<double>(1,0) - points2d[i].y,2)); + std::pow(imageX.at<double>(1,0) - points2d[i].y,2));
...@@ -27,30 +27,34 @@ namespace op ...@@ -27,30 +27,34 @@ namespace op
} }
} }
void triangulate(cv::Mat& X, const std::vector<cv::Mat>& matrixEachCamera, void triangulate(cv::Mat& reconstructedPoint, const std::vector<cv::Mat>& cameraMatrices,
const std::vector<cv::Point2d>& pointsOnEachCamera) const std::vector<cv::Point2d>& pointsOnEachCamera)
{ {
try try
{ {
// Security checks // Security checks
if (matrixEachCamera.empty() || matrixEachCamera.size() != pointsOnEachCamera.size()) if (cameraMatrices.size() != pointsOnEachCamera.size())
error("numberCameras.empty() || numberCameras.size() != pointsOnEachCamera.size()", error("numberCameras.size() != pointsOnEachCamera.size() (" + std::to_string(cameraMatrices.size())
__LINE__, __FUNCTION__, __FILE__); + " vs. " + std::to_string(pointsOnEachCamera.size()) + ").",
__LINE__, __FUNCTION__, __FILE__);
if (cameraMatrices.empty())
error("numberCameras.empty()",
__LINE__, __FUNCTION__, __FILE__);
// Create and fill A // Create and fill A
const auto numberCameras = (int)matrixEachCamera.size(); const auto numberCameras = (int)cameraMatrices.size();
cv::Mat A = cv::Mat::zeros(numberCameras*2, 4, CV_64F); cv::Mat A = cv::Mat::zeros(numberCameras*2, 4, CV_64F);
for (auto i = 0 ; i < numberCameras ; i++) for (auto i = 0 ; i < numberCameras ; i++)
{ {
cv::Mat temp = pointsOnEachCamera[i].x*matrixEachCamera[i].rowRange(2,3) cv::Mat temp = pointsOnEachCamera[i].x*cameraMatrices[i].rowRange(2,3)
- matrixEachCamera[i].rowRange(0,1); - cameraMatrices[i].rowRange(0,1);
temp.copyTo(A.rowRange(i*2, i*2+1)); temp.copyTo(A.rowRange(i*2, i*2+1));
temp = pointsOnEachCamera[i].y*matrixEachCamera[i].rowRange(2,3) - matrixEachCamera[i].rowRange(1,2); temp = pointsOnEachCamera[i].y*cameraMatrices[i].rowRange(2,3) - cameraMatrices[i].rowRange(1,2);
temp.copyTo(A.rowRange(i*2+1, i*2+2)); temp.copyTo(A.rowRange(i*2+1, i*2+2));
} }
// SVD on A // SVD on A
cv::SVD svd{A}; cv::SVD svd{A};
svd.solveZ(A,X); svd.solveZ(A,reconstructedPoint);
X /= X.at<double>(3); reconstructedPoint /= reconstructedPoint.at<double>(3);
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
...@@ -59,20 +63,20 @@ namespace op ...@@ -59,20 +63,20 @@ namespace op
} }
// TODO: ask for the missing function: TriangulationOptimization // TODO: ask for the missing function: TriangulationOptimization
double triangulateWithOptimization(cv::Mat& X, const std::vector<cv::Mat>& matrixEachCamera, double triangulateWithOptimization(cv::Mat& reconstructedPoint, const std::vector<cv::Mat>& cameraMatrices,
const std::vector<cv::Point2d>& pointsOnEachCamera) const std::vector<cv::Point2d>& pointsOnEachCamera)
{ {
try try
{ {
triangulate(X, matrixEachCamera, pointsOnEachCamera); triangulate(reconstructedPoint, cameraMatrices, pointsOnEachCamera);
return 0.; return 0.;
// return calcReprojectionError(X, matrixEachCamera, pointsOnEachCamera); // return calcReprojectionError(X, cameraMatrices, pointsOnEachCamera);
// //if (matrixEachCamera.size() >= 3) // //if (cameraMatrices.size() >= 3)
// //double beforeError = calcReprojectionError(&matrixEachCamera, pointsOnEachCamera, X); // //double beforeError = calcReprojectionError(&cameraMatrices, pointsOnEachCamera, X);
// double change = TriangulationOptimization(&matrixEachCamera, pointsOnEachCamera, X); // double change = TriangulationOptimization(&cameraMatrices, pointsOnEachCamera, X);
// //double afterError = calcReprojectionError(&matrixEachCamera,pointsOnEachCamera,X); // //double afterError = calcReprojectionError(&cameraMatrices,pointsOnEachCamera,X);
// //printfLog("!!Mine %.8f , inFunc %.8f \n",beforeError-afterError,change); // //printfLog("!!Mine %.8f , inFunc %.8f \n",beforeError-afterError,change);
// return change; // return change;
} }
...@@ -83,14 +87,30 @@ namespace op ...@@ -83,14 +87,30 @@ namespace op
} }
} }
Array<float> reconstructArray(const std::vector<Array<float>>& keypointsVector, PoseTriangulation::PoseTriangulation(const int minViews3d) :
const std::vector<cv::Mat>& matrixEachCamera) mMinViews3d{minViews3d}
{
try
{
// Security checks
if (0 <= mMinViews3d && mMinViews3d < 2)
error("Minimum number of views must be at least 2 (e.g., `--3d_min_views 2`) or negative.",
__LINE__, __FUNCTION__, __FILE__);
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
Array<float> PoseTriangulation::reconstructArray(const std::vector<Array<float>>& keypointsVector,
const std::vector<cv::Mat>& cameraMatrices) const
{ {
try try
{ {
Array<float> keypoints3D; Array<float> keypoints3D;
// Security checks // Security checks
if (matrixEachCamera.size() < 2) if (cameraMatrices.size() < 2)
error("Only 1 camera detected. The 3-D reconstruction module can only be used with > 1 cameras" error("Only 1 camera detected. The 3-D reconstruction module can only be used with > 1 cameras"
" simultaneously. E.g., using FLIR stereo cameras (`--flir_camera`).", " simultaneously. E.g., using FLIR stereo cameras (`--flir_camera`).",
__LINE__, __FUNCTION__, __FILE__); __LINE__, __FUNCTION__, __FILE__);
...@@ -113,27 +133,33 @@ namespace op ...@@ -113,27 +133,33 @@ namespace op
const auto threshold = 0.2f; const auto threshold = 0.2f;
std::vector<int> indexesUsed; std::vector<int> indexesUsed;
std::vector<std::vector<cv::Point2d>> xyPoints; std::vector<std::vector<cv::Point2d>> xyPoints;
std::vector<std::vector<cv::Mat>> cameraMatricesPerPoint;
for (auto part = 0; part < numberBodyParts; part++) for (auto part = 0; part < numberBodyParts; part++)
{ {
// Create vector of points // Create vector of points
auto missedPoint = false; // auto missedPoint = false;
std::vector<cv::Point2d> xyPointsElement; std::vector<cv::Point2d> xyPointsElement;
std::vector<cv::Mat> cameraMatricesElement;
const auto baseIndex = part * lastChannelLength; const auto baseIndex = part * lastChannelLength;
for (auto& keypoints : keypointsVector) // for (auto& keypoints : keypointsVector)
for (auto i = 0u ; i < keypointsVector.size() ; i++)
{ {
const auto& keypoints = keypointsVector[i];
if (keypoints[baseIndex+2] > threshold) if (keypoints[baseIndex+2] > threshold)
xyPointsElement.emplace_back(cv::Point2d{ keypoints[baseIndex],
keypoints[baseIndex+1]});
else
{ {
missedPoint = true; xyPointsElement.emplace_back(cv::Point2d{keypoints[baseIndex],
break; keypoints[baseIndex+1]});
cameraMatricesElement.emplace_back(cameraMatrices[i]);
} }
} }
if (!missedPoint) // If visible from all views (mMinViews3d < 0)
// or if visible for at least mMinViews3d views
if ((mMinViews3d < 0 && cameraMatricesElement.size() == cameraMatrices.size())
|| (mMinViews3d > 1 && mMinViews3d <= (int)xyPointsElement.size()))
{ {
indexesUsed.emplace_back(part); indexesUsed.emplace_back(part);
xyPoints.emplace_back(xyPointsElement); xyPoints.emplace_back(xyPointsElement);
cameraMatricesPerPoint.emplace_back(cameraMatricesElement);
} }
} }
// 3D reconstruction // 3D reconstruction
...@@ -144,16 +170,17 @@ namespace op ...@@ -144,16 +170,17 @@ namespace op
std::vector<cv::Point3f> xyzPoints(xyPoints.size()); std::vector<cv::Point3f> xyzPoints(xyPoints.size());
for (auto i = 0u; i < xyPoints.size(); i++) for (auto i = 0u; i < xyPoints.size(); i++)
{ {
cv::Mat X; cv::Mat reconstructedPoint;
triangulateWithOptimization(X, matrixEachCamera, xyPoints[i]); triangulateWithOptimization(reconstructedPoint, cameraMatricesPerPoint[i], xyPoints[i]);
xyzPoints[i] = cv::Point3d{ X.at<double>(0), X.at<double>(1), X.at<double>(2) }; xyzPoints[i] = cv::Point3d{reconstructedPoint.at<double>(0), reconstructedPoint.at<double>(1),
reconstructedPoint.at<double>(2)};
} }
// 3D points to pose // 3D points to pose
// OpenCV alternative: // OpenCV alternative:
// http://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#triangulatepoints // http://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#triangulatepoints
// cv::Mat reconstructedPoints{4, firstcv::Points.size(), CV_64F}; // cv::Mat reconstructedPoints{4, firstcv::Points.size(), CV_64F};
// cv::triangulatecv::Points(cv::Mat::eye(3,4, CV_64F), M_3_1, firstcv::Points, secondcv::Points, // cv::triangulatePoints(cv::Mat::eye(3,4, CV_64F), M_3_1, firstcv::Points, secondcv::Points,
// reconstructedcv::Points); // reconstructedcv::Points);
const auto lastChannelLength = keypoints3D.getSize(2); const auto lastChannelLength = keypoints3D.getSize(2);
for (auto index = 0u; index < indexesUsed.size(); index++) for (auto index = 0u; index < indexesUsed.size(); index++)
......
...@@ -87,6 +87,9 @@ namespace op ...@@ -87,6 +87,9 @@ namespace op
{ {
try try
{ {
// Security check
if (frame.empty())
error("Empty frame introduced.", __LINE__, __FUNCTION__, __FILE__);
// If frame > window size --> Resize window // If frame > window size --> Resize window
if (mWindowedSize.x < frame.cols || mWindowedSize.y < frame.rows) if (mWindowedSize.x < frame.cols || mWindowedSize.y < frame.rows)
{ {
...@@ -106,4 +109,33 @@ namespace op ...@@ -106,4 +109,33 @@ namespace op
error(e.what(), __LINE__, __FUNCTION__, __FILE__); error(e.what(), __LINE__, __FUNCTION__, __FILE__);
} }
} }
void FrameDisplayer::displayFrame(const std::vector<cv::Mat>& frames, const int waitKeyValue)
{
try
{
// No frames
if (frames.empty())
displayFrame(cv::Mat(), waitKeyValue);
// 1 frame
else if (frames.size() == 1u)
displayFrame(frames[0], waitKeyValue);
// >= 2 frames
else
{
// Prepare final cvMat
// Concat (0)
cv::Mat cvMat = frames[0].clone();
// Concat (1,size()-1)
for (auto i = 1u; i < frames.size(); i++)
cv::hconcat(cvMat, frames[i], cvMat);
// Display it
displayFrame(cvMat, waitKeyValue);
}
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
} }
...@@ -177,12 +177,7 @@ namespace op ...@@ -177,12 +177,7 @@ namespace op
{ {
try try
{ {
// Check tDatum integrity setImage(std::vector<cv::Mat>{cvMatOutput});
const bool returnedIsValidFrame = ((spIsRunning == nullptr || *spIsRunning) && !cvMatOutput.empty());
// Display
if (returnedIsValidFrame)
mFrameDisplayer.displayFrame(cvMatOutput, -1);
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
...@@ -194,36 +189,20 @@ namespace op ...@@ -194,36 +189,20 @@ namespace op
{ {
try try
{ {
// 0 image // Check tDatum integrity
if (cvMatOutputs.empty()) bool returnedIsValidFrame = ((spIsRunning == nullptr || *spIsRunning) && !cvMatOutputs.empty());
setImage(cvMatOutputs[0]); for (const auto& cvMatOutput : cvMatOutputs)
// 1 image
else if (cvMatOutputs.size() == 1)
setImage(cvMatOutputs[0]);
// > 1 image
else
{ {
// Check tDatum integrity if (cvMatOutput.empty())
bool returnedIsValidFrame = ((spIsRunning == nullptr || *spIsRunning) && !cvMatOutputs.empty());
if (returnedIsValidFrame)
{ {
// Security checks returnedIsValidFrame = false;
for (const auto& cvMatOutput : cvMatOutputs) break;
if (cvMatOutput.empty())
returnedIsValidFrame = false;
// Prepare final cvMat
if (returnedIsValidFrame)
{
// Concat (0)
cv::Mat cvMat = cvMatOutputs[0].clone();
// Concat (1,size()-1)
for (auto i = 1u; i < cvMatOutputs.size(); i++)
cv::hconcat(cvMat, cvMatOutputs[i], cvMat);
// Display
mFrameDisplayer.displayFrame(cvMat, -1);
}
} }
} }
// Display
if (returnedIsValidFrame)
mFrameDisplayer.displayFrame(cvMatOutputs, -1);
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
......
...@@ -175,8 +175,8 @@ namespace op ...@@ -175,8 +175,8 @@ namespace op
const auto thicknessRatio = fastMax(intRound(std::sqrt(area) const auto thicknessRatio = fastMax(intRound(std::sqrt(area)
* thicknessCircleRatio * ratioAreas), 2); * thicknessCircleRatio * ratioAreas), 2);
// Negative thickness in cv::circle means that a filled circle is to be drawn. // Negative thickness in cv::circle means that a filled circle is to be drawn.
const auto thicknessCircle = (ratioAreas > 0.05f ? thicknessRatio : -1); const auto thicknessCircle = fastMax(1, (ratioAreas > 0.05f ? thicknessRatio : -1));
const auto thicknessLine = intRound(thicknessRatio * thicknessLineRatioWRTCircle); const auto thicknessLine = fastMax(1, intRound(thicknessRatio * thicknessLineRatioWRTCircle));
const auto radius = thicknessRatio / 2; const auto radius = thicknessRatio / 2;
// Draw lines // Draw lines
......
...@@ -115,6 +115,14 @@ namespace op ...@@ -115,6 +115,14 @@ namespace op
if (wrapperStructPose.gpuNumber > 0) if (wrapperStructPose.gpuNumber > 0)
error("GPU number must be negative or 0 if CPU_ONLY is enabled.", error("GPU number must be negative or 0 if CPU_ONLY is enabled.",
__LINE__, __FUNCTION__, __FILE__); __LINE__, __FUNCTION__, __FILE__);
// If num_gpu 0 --> output_resolution has no effect
if (wrapperStructPose.gpuNumber == 0 &&
(wrapperStructPose.outputSize.x > 0 || wrapperStructPose.outputSize.y > 0))
error("If `--num_gpu 0`, then `--output_resolution` has no effect, so either disable it or use"
" `--output_resolution -1x-1`. Current output size: ("
+ std::to_string(wrapperStructPose.outputSize.x) + "x"
+ std::to_string(wrapperStructPose.outputSize.y) + ").",
__LINE__, __FUNCTION__, __FILE__);
// Net input resolution cannot be reshaped for Caffe OpenCL and MKL versions, only for CUDA version // Net input resolution cannot be reshaped for Caffe OpenCL and MKL versions, only for CUDA version
#if defined USE_MKL || defined CPU_ONLY #if defined USE_MKL || defined CPU_ONLY
// If image_dir and netInputSize == -1 --> error // If image_dir and netInputSize == -1 --> error
......
...@@ -14,7 +14,7 @@ namespace op ...@@ -14,7 +14,7 @@ namespace op
const ScaleMode heatMapScale_, const bool addPartCandidates_, const ScaleMode heatMapScale_, const bool addPartCandidates_,
const float renderThreshold_, const int numberPeopleMax_, const float renderThreshold_, const int numberPeopleMax_,
const bool enableGoogleLogging_, const bool reconstruct3d_, const bool enableGoogleLogging_, const bool reconstruct3d_,
const bool identification_) : const int minViews3d_, const bool identification_) :
enable{enable_}, enable{enable_},
netInputSize{netInputSize_}, netInputSize{netInputSize_},
outputSize{outputSize_}, outputSize{outputSize_},
...@@ -37,6 +37,7 @@ namespace op ...@@ -37,6 +37,7 @@ namespace op
numberPeopleMax{numberPeopleMax_}, numberPeopleMax{numberPeopleMax_},
enableGoogleLogging{enableGoogleLogging_}, enableGoogleLogging{enableGoogleLogging_},
reconstruct3d{reconstruct3d_}, reconstruct3d{reconstruct3d_},
minViews3d{minViews3d_},
identification{identification_} identification{identification_}
{ {
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册