diff --git a/doc/demo_overview.md b/doc/demo_overview.md index f27ce606..88420d10 100644 --- a/doc/demo_overview.md +++ b/doc/demo_overview.md @@ -62,9 +62,9 @@ The following example runs the demo video `video.avi`, renders image frames on ` # Best results found with 6 scales ./build/examples/openpose/openpose.bin --hand --hand_scale_number 6 --hand_scale_range 0.4 # Adding tracking to Webcam (if FPS per GPU > 10 FPS) and Video -./build/examples/openpose/openpose.bin --video examples/media/video.avi --hand --hand_tracking +./build/examples/openpose/openpose.bin --video examples/media/video.avi --hand --hand_detector 3 # Multi-scale + tracking is also possible -./build/examples/openpose/openpose.bin --video examples/media/video.avi --hand --hand_scale_number 6 --hand_scale_range 0.4 --hand_tracking +./build/examples/openpose/openpose.bin --video examples/media/video.avi --hand --hand_scale_number 6 --hand_scale_range 0.4 --hand_detector 3 ``` @@ -181,14 +181,15 @@ Each flag is divided into flag name, default value, and description. 6. OpenPose Face - DEFINE_bool(face, false, "Enables face keypoint detection. It will share some parameters from the body pose, e.g. `model_folder`. Note that this will considerable slow down the performance and increse the required GPU memory. In addition, the greater number of people on the image, the slower OpenPose will be."); +- DEFINE_int32(face_detector, 0, "Kind of face rectangle detector. Select 0 (default) to select OpenPose body detector (most accurate one and fastest one if body is enabled), 1 to select OpenCV face detector (not implemented for hands), 2 to indicate that it will be provided by the user, or 3 to also apply hand tracking (only for hand). Hand tracking might improve hand keypoint 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_string(face_net_resolution, "368x368", "Multiples of 16 and squared. Analogous to `net_resolution` but applied to the face keypoint detector. 320x320 usually works fine while giving a substantial speed up when multiple faces on the image."); 7. OpenPose Hand - DEFINE_bool(hand, false, "Enables hand keypoint detection. It will share some parameters from the body pose, e.g. `model_folder`. Analogously to `--face`, it will also slow down the performance, increase the required GPU memory and its speed depends on the number of people."); +- DEFINE_int32(hand_detector, 0, "Kind of hand rectangle detector. Analogous to `--face_detector`."); - DEFINE_string(hand_net_resolution, "368x368", "Multiples of 16 and squared. Analogous to `net_resolution` but applied to the hand keypoint detector."); - DEFINE_int32(hand_scale_number, 1, "Analogous to `scale_number` but applied to the hand keypoint detector. Our best results were found with `hand_scale_number` = 6 and `hand_scale_range` = 0.4."); - DEFINE_double(hand_scale_range, 0.4, "Analogous purpose than `scale_gap` but applied to the hand keypoint detector. Total range between smallest and biggest scale. The scales will be centered in ratio 1. E.g., if scaleRange = 0.4 and scalesNumber = 2, then there will be 2 scales, 0.8 and 1.2."); -- 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 - 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."); diff --git a/doc/faq.md b/doc/faq.md index 9e2807bc..de8790e3 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -20,6 +20,7 @@ OpenPose - Frequently Asked Question (FAQ) 15. [3D OpenPose Returning Wrong Results: 0, NaN, Infinity, etc.](#3d-openpose-returning-wrong-results-0-nan-infinity-etc) 16. [Protobuf Clip Param Caffe Error](#protobuf-clip-param-caffe-error) 17. [The Human Skeleton Looks like Dotted Lines Rather than Solid Lines](#the-human-skeleton-looks-like-dotted-lines-rather-than-solid-lines) + 18. [Huge RAM Usage](#huge-ram-usage) @@ -151,6 +152,13 @@ If you wanna use your custom Caffe and it has this error: This error only happen ### The Human Skeleton Looks like Dotted Lines Rather than Solid Lines -**Q:** When I use the demo to handle my images,the skeletons are dotted lines. I want to know how to make them to be solid lines. +**Q**: When I use the demo to handle my images,the skeletons are dotted lines. I want to know how to make them to be solid lines. **A**: The reason is that your input image size is too small. You can either 1) manually rescale your images up or 2) use a bigger `--output_resolution` so OpenPose will resize them up. + + + +### Huge RAM Usage +**Q**: During the execution of the demo, the CPU usage oscillates between 50 and 99%, but the RAM is almost at 100%. + +**A**: Highly reducing the `--net_resolution` and following the tips in the [Speed Up, Memory Reduction, and Benchmark](#speed-up-memory-reduction-and-benchmark) section are the only way to reduce the RAM usage. Alternatively, you can disable `USE_MKL` in CMake, which will highly reduce the RAM usage of the Caffe version, but it might also reduce the program speed. diff --git a/doc/release_notes.md b/doc/release_notes.md index a38fc956..eca43aa4 100644 --- a/doc/release_notes.md +++ b/doc/release_notes.md @@ -267,13 +267,14 @@ OpenPose Library - Release Notes 5. Wrapper classes simplified and renamed. Wrapper renamed as WrapperT, and created Wrapper as the non-templated class equivalent. 6. API and examples improved: 1. New header file `flags.hpp` that includes all OpenPose flags, removing the need to copy them repeatedly on each OpenPose example file. - 2. `tutorial_wrapper` renamed as `tutorial_api_cpp` as well as new examples were added. - 2. `tutorial_python` renamed as `tutorial_api_python` as well as new examples were added. - 3. `tutorial_pose` and `tutorial_thread` renamed as `tutorial_developer`, not meant to be used by users, but rather for OpenPose developers. - 4. Examples do not end in core dumped if an OpenPose exception occurred during initialization, but they are rather closed returning -1. However, it will still results in core dumped if the exception occurs during multi-threading execution. - 5. Added new examples, including examples to extract face and/or hand from images. - 6. Added `--no_display` flag for the examples that does not use OpenPose output. - 7. Given that display can be disabled in all examples, they all have been added to the Travis build so they can be tested. + 2. Renamed `tutorial_wrapper` as `tutorial_api_cpp` as well as new examples were added. + 2. Renamed `tutorial_python` as `tutorial_api_python` as well as new examples were added. + 3. Renamed `tutorial_thread` as `tutorial_api_thread`, focused in the multi-thread mechanism. + 4. Removed `tutorial_pose`, the folder `tutorial_api_cpp` includes much cleaner and commented examples. + 5. Examples do not end in core dumped if an OpenPose exception occurred during initialization, but they are rather closed returning -1. However, it will still results in core dumped if the exception occurs during multi-threading execution. + 6. Added new examples, including examples to extract face and/or hand from images. + 7. Added `--no_display` flag for the examples that does not use OpenPose output. + 8. Given that display can be disabled in all examples, they all have been added to the Travis build so they can be tested. 7. Added a virtual destructor to almost all clases, so they can be inherited. Exceptions (for performance reasons): Array, Point, Rectangle, CvMatToOpOutput, OpOutputToCvMat. 8. Auxiliary classes in errorAndLog turned into namespaces (Profiler must be kept as class to allow static parameters). 9. Added flag `--frame_step` to allow the user to select the step or gap between processed frames. E.g., `--frame_step 5` would read and process frames 0, 5, 10, etc. @@ -312,6 +313,7 @@ OpenPose Library - Release Notes 30. Added the flags `--prototxt_path` and `--caffemodel_path` to allow custom ProtoTxt and CaffeModel paths. 31. Replaced the old Python wrapper for an updated Pybind11 wrapper version, that includes all the functionality of the C++ API. 32. Function getFilesOnDirectory() can extra all basic image file types at once without requiring to manually enumerate them. + 33. Added the flags `--face_detector` and `--hand_detector`, that enable the user to select the face/hand rectangle detector that is used for the later face/hand keypoint detection. It includes OpenCV (for face), and also allows the user to provide its own input. Flag `--hand_tracking` is removed and integrated into this flag too. 2. Functions or parameters renamed: 1. By default, python example `tutorial_developer/python_2_pose_from_heatmaps.py` was using 2 scales starting at -1x736, changed to 1 scale at -1x368. 2. WrapperStructPose default parameters changed to match those of the OpenPose demo binary. @@ -327,6 +329,7 @@ OpenPose Library - Release Notes 12. Moved most sh scripts into the `scripts/` folder. Only models/getModels.sh and the `*.bat` files are kept under `models/` and `3rdparty/windows`. 13. For Python compatibility and scalability increase, template `TDatums` used for `include/openpose/wrapper/wrapper.hpp` has changed from `std::vector` to `std::vector>`, including the respective changes in all the worker classes. In addition, some template classes have been simplified to only take 1 template parameter for user simplicity. 14. Renamed intRound, charRound, etc. by positiveIntRound, positiveCharRound, etc. so that people can realize it is not safe for negative numbers. + 15. Flag `--hand_tracking` is a subcase of `--hand_detector`, so it has been removed and incorporated as `--hand_detector 3`. 3. Main bugs fixed: 1. CMake-GUI was forcing to Release mode, allowed Debug modes too. 2. NMS returns in index 0 the number of found peaks. However, while the number of peaks was truncated to a maximum of 127, this index 0 was saving the real number instead of the truncated one. diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 167ec367..67090647 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,9 +1,9 @@ add_subdirectory(calibration) add_subdirectory(openpose) add_subdirectory(tutorial_add_module) -add_subdirectory(tutorial_api_python) add_subdirectory(tutorial_api_cpp) -add_subdirectory(tutorial_developer) +add_subdirectory(tutorial_api_python) +add_subdirectory(tutorial_api_thread) add_subdirectory(user_code) if (UNIX OR APPLE) add_subdirectory(tests) diff --git a/examples/calibration/calibration.cpp b/examples/calibration/calibration.cpp index 2bbab845..3ce4d51b 100644 --- a/examples/calibration/calibration.cpp +++ b/examples/calibration/calibration.cpp @@ -37,7 +37,7 @@ int openPoseDemo() try { op::log("Starting OpenPose calibration toolbox...", op::Priority::High); - const auto timerBegin = std::chrono::high_resolution_clock::now(); + const auto opTimer = op::getTimerInit(); // logging_level op::check(0 <= FLAGS_logging_level && FLAGS_logging_level <= 255, "Wrong logging_level value.", @@ -114,12 +114,9 @@ int openPoseDemo() op::error("Unknown `--mode " + std::to_string(FLAGS_mode) + "`.", __LINE__, __FUNCTION__, __FILE__); // Measuring total time - const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; - const auto message = "OpenPose calibration toolbox successfully finished. Total time: " - + std::to_string(totalTimeSec) + " seconds."; - op::log(message, op::Priority::High); + op::printTime( + opTimer, "OpenPose calibration toolbox successfully finished. Total time: ", " seconds.", + op::Priority::High); return 0; } diff --git a/examples/openpose/openpose.cpp b/examples/openpose/openpose.cpp index 38ad6812..dd92efb5 100755 --- a/examples/openpose/openpose.cpp +++ b/examples/openpose/openpose.cpp @@ -25,6 +25,11 @@ void configureWrapper(op::Wrapper& opWrapper) op::Profiler::setDefaultX(FLAGS_profile_speed); // Applying user defined configuration - GFlags to program variables + // producerType + op::ProducerType producerType; + std::string producerString; + std::tie(producerType, producerString) = op::flagsToProducer( + FLAGS_image_dir, FLAGS_video, FLAGS_ip_camera, FLAGS_camera, FLAGS_flir_camera, FLAGS_flir_camera_index); // cameraSize const auto cameraSize = op::flagsToPoint(FLAGS_camera_resolution, "-1x-1"); // outputSize @@ -35,11 +40,6 @@ void configureWrapper(op::Wrapper& opWrapper) const auto faceNetInputSize = op::flagsToPoint(FLAGS_face_net_resolution, "368x368 (multiples of 16)"); // handNetInputSize const auto handNetInputSize = op::flagsToPoint(FLAGS_hand_net_resolution, "368x368 (multiples of 16)"); - // producerType - op::ProducerType producerType; - std::string producerString; - std::tie(producerType, producerString) = op::flagsToProducer( - FLAGS_image_dir, FLAGS_video, FLAGS_ip_camera, FLAGS_camera, FLAGS_flir_camera, FLAGS_flir_camera_index); // poseModel const auto poseModel = op::flagsToPoseModel(FLAGS_model_pose); // JSON saving @@ -54,6 +54,9 @@ void configureWrapper(op::Wrapper& opWrapper) const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); // >1 camera view? const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1 || FLAGS_flir_camera); + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); // Enabling Google Logging const bool enableGoogleLogging = true; @@ -68,12 +71,13 @@ void configureWrapper(op::Wrapper& opWrapper) opWrapper.configure(wrapperStructPose); // Face configuration (use op::WrapperStructFace{} to disable it) const op::WrapperStructFace wrapperStructFace{ - FLAGS_face, faceNetInputSize, op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; opWrapper.configure(wrapperStructFace); // Hand configuration (use op::WrapperStructHand{} to disable it) const op::WrapperStructHand wrapperStructHand{ - FLAGS_hand, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, FLAGS_hand_tracking, + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; opWrapper.configure(wrapperStructHand); @@ -114,7 +118,7 @@ int openPoseDemo() try { op::log("Starting OpenPose demo...", op::Priority::High); - const auto timerBegin = std::chrono::high_resolution_clock::now(); + const auto opTimer = op::getTimerInit(); // Configure OpenPose op::log("Configuring OpenPose...", op::Priority::High); @@ -126,12 +130,7 @@ int openPoseDemo() opWrapper.exec(); // Measuring total time - const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; - const auto message = "OpenPose demo successfully finished. Total time: " - + std::to_string(totalTimeSec) + " seconds."; - op::log(message, op::Priority::High); + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); // Return successful message return 0; diff --git a/examples/tests/handFromJsonTest.cpp b/examples/tests/handFromJsonTest.cpp index acd763c5..15ef4cc9 100644 --- a/examples/tests/handFromJsonTest.cpp +++ b/examples/tests/handFromJsonTest.cpp @@ -21,7 +21,6 @@ DEFINE_bool(hand, true, ""); DEFINE_string(hand_net_resolution, "368x368", ""); DEFINE_int32(hand_scale_number, 1, ""); DEFINE_double(hand_scale_range, 0.4, ""); -DEFINE_bool(hand_tracking, false, ""); // Display DEFINE_int32(display, -1, ""); // Result Saving @@ -51,16 +50,15 @@ int handFromJsonTest() op::log("Configuring OpenPose...", op::Priority::High); op::WrapperHandFromJsonTest opWrapper; // Pose configuration (use WrapperStructPose{} for default and recommended configuration) - op::WrapperStructPose wrapperStructPose{false, op::flagsToPoint("656x368"), op::flagsToPoint("1280x720"), - op::ScaleMode::InputResolution, FLAGS_num_gpu, FLAGS_num_gpu_start, - 1, 0.15f, op::RenderMode::None, op::PoseModel::BODY_25, - true, 0.f, 0.f, 0, "models/", {}, op::ScaleMode::ZeroToOne, false, - 0.05f, -1, false, enableGoogleLogging}; + op::WrapperStructPose wrapperStructPose{ + false, op::flagsToPoint("656x368"), op::flagsToPoint("1280x720"), op::ScaleMode::InputResolution, + FLAGS_num_gpu, FLAGS_num_gpu_start, 1, 0.15f, op::RenderMode::None, op::PoseModel::BODY_25, true, 0.f, 0.f, + 0, "models/", {}, op::ScaleMode::ZeroToOne, false, 0.05f, -1, false, enableGoogleLogging}; wrapperStructPose.modelFolder = FLAGS_model_folder; // Hand configuration (use op::WrapperStructHand{} to disable it) - const op::WrapperStructHand wrapperStructHand{FLAGS_hand, handNetInputSize, FLAGS_hand_scale_number, - (float)FLAGS_hand_scale_range, FLAGS_hand_tracking, - op::flagsToRenderMode(1)}; + const op::WrapperStructHand wrapperStructHand{ + FLAGS_hand, op::Detector::Provided, handNetInputSize, FLAGS_hand_scale_number, + (float)FLAGS_hand_scale_range, op::flagsToRenderMode(1)}; // Configure wrapper opWrapper.configure(wrapperStructPose, wrapperStructHand, producerSharedPtr, FLAGS_hand_ground_truth, FLAGS_write_json, op::flagsToDisplayMode(FLAGS_display, false)); @@ -71,8 +69,8 @@ int handFromJsonTest() // Measuring total time const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; + const auto totalTimeSec = double( + std::chrono::duration_cast(now-timerBegin).count()* 1e-9); const auto message = "OpenPose demo successfully finished. Total time: " + std::to_string(totalTimeSec) + " seconds."; op::log(message, op::Priority::High); diff --git a/examples/tests/wrapperHandFromJsonTest.hpp b/examples/tests/wrapperHandFromJsonTest.hpp index 61caf645..368bdb31 100644 --- a/examples/tests/wrapperHandFromJsonTest.hpp +++ b/examples/tests/wrapperHandFromJsonTest.hpp @@ -202,7 +202,7 @@ namespace op { // Hand detector // If tracking - if (wrapperStructHand.tracking) + if (wrapperStructHand.detector == Detector::BodyWithTracking) error("Tracking not valid for hand detector from JSON files.", __LINE__, __FUNCTION__, __FILE__); // If detection else diff --git a/examples/tutorial_add_module/1_custom_post_processing.cpp b/examples/tutorial_add_module/1_custom_post_processing.cpp index ccd929dc..13e3eb20 100644 --- a/examples/tutorial_add_module/1_custom_post_processing.cpp +++ b/examples/tutorial_add_module/1_custom_post_processing.cpp @@ -30,12 +30,11 @@ #include "userDatum.hpp" #include "wUserPostProcessing.hpp" -int tutorialAddModule1() +void configureWrapper(op::WrapperT& opWrapperT) { - try - { - op::log("Starting OpenPose demo...", op::Priority::High); - const auto timerBegin = std::chrono::high_resolution_clock::now(); + try + { + // Configuring OpenPose // logging_level op::check(0 <= FLAGS_logging_level && FLAGS_logging_level <= 255, "Wrong logging_level value.", @@ -44,6 +43,11 @@ int tutorialAddModule1() op::Profiler::setDefaultX(FLAGS_profile_speed); // Applying user defined configuration - GFlags to program variables + // producerType + op::ProducerType producerType; + std::string producerString; + std::tie(producerType, producerString) = op::flagsToProducer( + FLAGS_image_dir, FLAGS_video, FLAGS_ip_camera, FLAGS_camera, FLAGS_flir_camera, FLAGS_flir_camera_index); // cameraSize const auto cameraSize = op::flagsToPoint(FLAGS_camera_resolution, "-1x-1"); // outputSize @@ -54,11 +58,6 @@ int tutorialAddModule1() const auto faceNetInputSize = op::flagsToPoint(FLAGS_face_net_resolution, "368x368 (multiples of 16)"); // handNetInputSize const auto handNetInputSize = op::flagsToPoint(FLAGS_hand_net_resolution, "368x368 (multiples of 16)"); - // producerType - op::ProducerType producerType; - std::string producerString; - std::tie(producerType, producerString) = op::flagsToProducer( - FLAGS_image_dir, FLAGS_video, FLAGS_ip_camera, FLAGS_camera, FLAGS_flir_camera, FLAGS_flir_camera_index); // poseModel const auto poseModel = op::flagsToPoseModel(FLAGS_model_pose); // JSON saving @@ -73,12 +72,12 @@ int tutorialAddModule1() const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); // >1 camera view? const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1 || FLAGS_flir_camera); + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); // Enabling Google Logging const bool enableGoogleLogging = true; - // OpenPose wrapper - op::log("Configuring OpenPose...", op::Priority::High); - op::WrapperT opWrapperT; // Pose configuration (use WrapperStructPose{} for default and recommended configuration) const op::WrapperStructPose wrapperStructPose{ !FLAGS_body_disable, netInputSize, outputSize, keypointScaleMode, FLAGS_num_gpu, FLAGS_num_gpu_start, @@ -90,12 +89,13 @@ int tutorialAddModule1() opWrapperT.configure(wrapperStructPose); // Face configuration (use op::WrapperStructFace{} to disable it) const op::WrapperStructFace wrapperStructFace{ - FLAGS_face, faceNetInputSize, op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; opWrapperT.configure(wrapperStructFace); // Hand configuration (use op::WrapperStructHand{} to disable it) const op::WrapperStructHand wrapperStructHand{ - FLAGS_hand, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, FLAGS_hand_tracking, + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; opWrapperT.configure(wrapperStructHand); @@ -134,18 +134,31 @@ int tutorialAddModule1() // Set to single-thread (for sequential processing and/or debugging and/or reducing latency) if (FLAGS_disable_multi_thread) opWrapperT.disableMultiThreading(); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +int tutorialAddModule1() +{ + try + { + op::log("Starting OpenPose demo...", op::Priority::High); + const auto opTimer = op::getTimerInit(); + + // Configure OpenPose + op::log("Configuring OpenPose...", op::Priority::High); + op::WrapperT opWrapperT; + configureWrapper(opWrapperT); op::log("Starting thread(s)...", op::Priority::High); // Start, run & stop threads - it blocks this thread until all others have finished opWrapperT.exec(); // Measuring total time - const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; - const auto message = "OpenPose demo successfully finished. Total time: " - + std::to_string(totalTimeSec) + " seconds."; - op::log(message, op::Priority::High); + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); // Return successful message return 0; diff --git a/examples/tutorial_api_cpp/1_body_from_image.cpp b/examples/tutorial_api_cpp/01_body_from_image_default.cpp similarity index 93% rename from examples/tutorial_api_cpp/1_body_from_image.cpp rename to examples/tutorial_api_cpp/01_body_from_image_default.cpp index 93e4ad1a..430bdd34 100644 --- a/examples/tutorial_api_cpp/1_body_from_image.cpp +++ b/examples/tutorial_api_cpp/01_body_from_image_default.cpp @@ -80,11 +80,12 @@ void printKeypoints(const std::shared_ptr } } -int tutorialApiCpp1() +int tutorialApiCpp() { try { op::log("Starting OpenPose demo...", op::Priority::High); + const auto opTimer = op::getTimerInit(); // Configuring OpenPose op::log("Configuring OpenPose...", op::Priority::High); @@ -109,8 +110,10 @@ int tutorialApiCpp1() else op::log("Image could not be processed.", op::Priority::High); - // Return successful message - op::log("Stopping OpenPose...", op::Priority::High); + // Measuring total time + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); + + // Return return 0; } catch (const std::exception& e) @@ -124,6 +127,6 @@ int main(int argc, char *argv[]) // Parsing command line flags gflags::ParseCommandLineFlags(&argc, &argv, true); - // Running tutorialApiCpp1 - return tutorialApiCpp1(); + // Running tutorialApiCpp + return tutorialApiCpp(); } diff --git a/examples/tutorial_api_cpp/2_whole_body_from_image.cpp b/examples/tutorial_api_cpp/02_whole_body_from_image_default.cpp similarity index 92% rename from examples/tutorial_api_cpp/2_whole_body_from_image.cpp rename to examples/tutorial_api_cpp/02_whole_body_from_image_default.cpp index 002030f2..4d8139aa 100644 --- a/examples/tutorial_api_cpp/2_whole_body_from_image.cpp +++ b/examples/tutorial_api_cpp/02_whole_body_from_image_default.cpp @@ -59,11 +59,12 @@ void printKeypoints(const std::shared_ptr } } -int tutorialApiCpp2() +int tutorialApiCpp() { try { op::log("Starting OpenPose demo...", op::Priority::High); + const auto opTimer = op::getTimerInit(); // Configuring OpenPose op::log("Configuring OpenPose...", op::Priority::High); @@ -91,8 +92,10 @@ int tutorialApiCpp2() else op::log("Image could not be processed.", op::Priority::High); - // Return successful message - op::log("Stopping OpenPose...", op::Priority::High); + // Measuring total time + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); + + // Return return 0; } catch (const std::exception& e) @@ -106,6 +109,6 @@ int main(int argc, char *argv[]) // Parsing command line flags gflags::ParseCommandLineFlags(&argc, &argv, true); - // Running tutorialApiCpp2 - return tutorialApiCpp2(); + // Running tutorialApiCpp + return tutorialApiCpp(); } diff --git a/examples/tutorial_api_cpp/3_keypoints_from_image_configurable.cpp b/examples/tutorial_api_cpp/03_keypoints_from_image.cpp similarity index 91% rename from examples/tutorial_api_cpp/3_keypoints_from_image_configurable.cpp rename to examples/tutorial_api_cpp/03_keypoints_from_image.cpp index 084d05ac..ad5f4b47 100644 --- a/examples/tutorial_api_cpp/3_keypoints_from_image_configurable.cpp +++ b/examples/tutorial_api_cpp/03_keypoints_from_image.cpp @@ -67,6 +67,12 @@ void configureWrapper(op::Wrapper& opWrapper) { // Configuring OpenPose + // logging_level + 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::Profiler::setDefaultX(FLAGS_profile_speed); + // Applying user defined configuration - GFlags to program variables // outputSize const auto outputSize = op::flagsToPoint(FLAGS_output_resolution, "-1x-1"); @@ -90,6 +96,9 @@ void configureWrapper(op::Wrapper& opWrapper) const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); // >1 camera view? const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1); + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); // Enabling Google Logging const bool enableGoogleLogging = true; @@ -104,12 +113,13 @@ void configureWrapper(op::Wrapper& opWrapper) opWrapper.configure(wrapperStructPose); // Face configuration (use op::WrapperStructFace{} to disable it) const op::WrapperStructFace wrapperStructFace{ - FLAGS_face, faceNetInputSize, op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; opWrapper.configure(wrapperStructFace); // Hand configuration (use op::WrapperStructHand{} to disable it) const op::WrapperStructHand wrapperStructHand{ - FLAGS_hand, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, FLAGS_hand_tracking, + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; opWrapper.configure(wrapperStructHand); @@ -136,17 +146,12 @@ void configureWrapper(op::Wrapper& opWrapper) } } -int tutorialApiCpp3() +int tutorialApiCpp() { try { op::log("Starting OpenPose demo...", op::Priority::High); - - // logging_level - 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::Profiler::setDefaultX(FLAGS_profile_speed); + const auto opTimer = op::getTimerInit(); // Configuring OpenPose op::log("Configuring OpenPose...", op::Priority::High); @@ -169,8 +174,10 @@ int tutorialApiCpp3() else op::log("Image could not be processed.", op::Priority::High); - // Return successful message - op::log("Stopping OpenPose...", op::Priority::High); + // Measuring total time + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); + + // Return return 0; } catch (const std::exception& e) @@ -184,6 +191,6 @@ int main(int argc, char *argv[]) // Parsing command line flags gflags::ParseCommandLineFlags(&argc, &argv, true); - // Running tutorialApiCpp3 - return tutorialApiCpp3(); + // Running tutorialApiCpp + return tutorialApiCpp(); } diff --git a/examples/tutorial_api_cpp/04_keypoints_from_images.cpp b/examples/tutorial_api_cpp/04_keypoints_from_images.cpp new file mode 100644 index 00000000..80ee3354 --- /dev/null +++ b/examples/tutorial_api_cpp/04_keypoints_from_images.cpp @@ -0,0 +1,212 @@ +// ----------------------- OpenPose C++ API Tutorial - Example 4 - Body from images configurable ---------------------- +// It reads images, process them, and display them with the pose (and optionally hand and face) keypoints. In addition, +// it includes all the OpenPose configuration flags (enable/disable hand, face, output saving, etc.). + +// Command-line user intraface +#define OPENPOSE_FLAGS_DISABLE_PRODUCER +#define OPENPOSE_FLAGS_DISABLE_DISPLAY +#include +// OpenPose dependencies +#include + +// Custom OpenPose flags +// Producer +DEFINE_string(image_dir, "examples/media/", + "Process a directory of images. Read all standard formats (jpg, png, bmp, etc.)."); +// Display +DEFINE_bool(no_display, false, + "Enable to disable the visual display."); + +// This worker will just read and return all the jpg files in a directory +bool display(const std::shared_ptr>>& datumsPtr) +{ + try + { + // User's displaying/saving/other processing here + // datum.cvOutputData: rendered frame with pose or heatmaps + // datum.poseKeypoints: Array with the estimated pose + char key = ' '; + if (datumsPtr != nullptr && !datumsPtr->empty()) + { + // Display image and sleeps at least 1 ms (it usually sleeps ~5-10 msec to display the image) + cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + key = (char)cv::waitKey(1); + } + else + op::log("Nullptr or empty datumsPtr found.", op::Priority::High); + return (key == 27); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + return true; + } +} + +void printKeypoints(const std::shared_ptr>>& datumsPtr) +{ + try + { + // Example: How to use the pose keypoints + if (datumsPtr != nullptr && !datumsPtr->empty()) + { + op::log("Body keypoints: " + datumsPtr->at(0)->poseKeypoints.toString()); + op::log("Face keypoints: " + datumsPtr->at(0)->faceKeypoints.toString()); + op::log("Left hand keypoints: " + datumsPtr->at(0)->handKeypoints[0].toString()); + op::log("Right hand keypoints: " + datumsPtr->at(0)->handKeypoints[1].toString()); + } + else + op::log("Nullptr or empty datumsPtr found.", op::Priority::High); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +void configureWrapper(op::Wrapper& opWrapper) +{ + try + { + // Configuring OpenPose + + // logging_level + 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::Profiler::setDefaultX(FLAGS_profile_speed); + + // Applying user defined configuration - GFlags to program variables + // outputSize + const auto outputSize = op::flagsToPoint(FLAGS_output_resolution, "-1x-1"); + // netInputSize + const auto netInputSize = op::flagsToPoint(FLAGS_net_resolution, "-1x368"); + // faceNetInputSize + const auto faceNetInputSize = op::flagsToPoint(FLAGS_face_net_resolution, "368x368 (multiples of 16)"); + // handNetInputSize + const auto handNetInputSize = op::flagsToPoint(FLAGS_hand_net_resolution, "368x368 (multiples of 16)"); + // poseModel + const auto poseModel = op::flagsToPoseModel(FLAGS_model_pose); + // JSON saving + if (!FLAGS_write_keypoint.empty()) + op::log("Flag `write_keypoint` is deprecated and will eventually be removed." + " Please, use `write_json` instead.", op::Priority::Max); + // keypointScaleMode + const auto keypointScaleMode = op::flagsToScaleMode(FLAGS_keypoint_scale); + // heatmaps to add + const auto heatMapTypes = op::flagsToHeatMaps(FLAGS_heatmaps_add_parts, FLAGS_heatmaps_add_bkg, + FLAGS_heatmaps_add_PAFs); + const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); + // >1 camera view? + const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1); + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); + // Enabling Google Logging + const bool enableGoogleLogging = true; + + // Pose configuration (use WrapperStructPose{} for default and recommended configuration) + const op::WrapperStructPose wrapperStructPose{ + !FLAGS_body_disable, netInputSize, outputSize, keypointScaleMode, FLAGS_num_gpu, FLAGS_num_gpu_start, + FLAGS_scale_number, (float)FLAGS_scale_gap, op::flagsToRenderMode(FLAGS_render_pose, multipleView), + poseModel, !FLAGS_disable_blending, (float)FLAGS_alpha_pose, (float)FLAGS_alpha_heatmap, + FLAGS_part_to_show, FLAGS_model_folder, heatMapTypes, heatMapScaleMode, FLAGS_part_candidates, + (float)FLAGS_render_threshold, FLAGS_number_people_max, FLAGS_maximize_positives, FLAGS_fps_max, + FLAGS_prototxt_path, FLAGS_caffemodel_path, enableGoogleLogging}; + opWrapper.configure(wrapperStructPose); + // Face configuration (use op::WrapperStructFace{} to disable it) + const op::WrapperStructFace wrapperStructFace{ + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; + opWrapper.configure(wrapperStructFace); + // Hand configuration (use op::WrapperStructHand{} to disable it) + const op::WrapperStructHand wrapperStructHand{ + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, + op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, + (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; + opWrapper.configure(wrapperStructHand); + // Extra functionality configuration (use op::WrapperStructExtra{} to disable it) + const op::WrapperStructExtra wrapperStructExtra{ + FLAGS_3d, FLAGS_3d_min_views, FLAGS_identification, FLAGS_tracking, FLAGS_ik_threads}; + opWrapper.configure(wrapperStructExtra); + // Output (comment or use default argument to disable any output) + const op::WrapperStructOutput wrapperStructOutput{ + FLAGS_cli_verbose, FLAGS_write_keypoint, op::stringToDataFormat(FLAGS_write_keypoint_format), + FLAGS_write_json, FLAGS_write_coco_json, FLAGS_write_coco_foot_json, FLAGS_write_coco_json_variant, + FLAGS_write_images, FLAGS_write_images_format, FLAGS_write_video, FLAGS_write_video_fps, + FLAGS_write_video_with_audio, FLAGS_write_heatmaps, FLAGS_write_heatmaps_format, FLAGS_write_video_3d, + FLAGS_write_video_adam, FLAGS_write_bvh, FLAGS_udp_host, FLAGS_udp_port}; + opWrapper.configure(wrapperStructOutput); + // No GUI. Equivalent to: opWrapper.configure(op::WrapperStructGui{}); + // Set to single-thread (for sequential processing and/or debugging and/or reducing latency) + if (FLAGS_disable_multi_thread) + opWrapper.disableMultiThreading(); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +int tutorialApiCpp() +{ + try + { + op::log("Starting OpenPose demo...", op::Priority::High); + const auto opTimer = op::getTimerInit(); + + // Configuring OpenPose + op::log("Configuring OpenPose...", op::Priority::High); + op::Wrapper opWrapper{op::ThreadManagerMode::Asynchronous}; + configureWrapper(opWrapper); + + // Starting OpenPose + op::log("Starting thread(s)...", op::Priority::High); + opWrapper.start(); + + // Read frames on directory + const auto imagePaths = op::getFilesOnDirectory(FLAGS_image_dir, op::Extensions::Images); + + // Process and display images + for (const auto& imagePath : imagePaths) + { + const auto imageToProcess = cv::imread(imagePath); + auto datumProcessed = opWrapper.emplaceAndPop(imageToProcess); + if (datumProcessed != nullptr) + { + printKeypoints(datumProcessed); + if (!FLAGS_no_display) + { + const auto userWantsToExit = display(datumProcessed); + if (userWantsToExit) + { + op::log("User pressed Esc to exit demo.", op::Priority::High); + break; + } + } + } + else + op::log("Image " + imagePath + " could not be processed.", op::Priority::High); + } + + // Measuring total time + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); + + // Return + return 0; + } + catch (const std::exception& e) + { + return -1; + } +} + +int main(int argc, char *argv[]) +{ + // Parsing command line flags + gflags::ParseCommandLineFlags(&argc, &argv, true); + + // Running tutorialApiCpp + return tutorialApiCpp(); +} diff --git a/examples/tutorial_api_cpp/05_keypoints_from_images_multi_gpu.cpp b/examples/tutorial_api_cpp/05_keypoints_from_images_multi_gpu.cpp new file mode 100644 index 00000000..1e2749b8 --- /dev/null +++ b/examples/tutorial_api_cpp/05_keypoints_from_images_multi_gpu.cpp @@ -0,0 +1,235 @@ +// --------------- OpenPose C++ API Tutorial - Example 5 - Body from images configurable and multi GPU --------------- +// It reads images, process them, and display them with the pose (and optionally hand and face) keypoints. In addition, +// it includes all the OpenPose configuration flags (enable/disable hand, face, output saving, etc.). + +// Command-line user intraface +#define OPENPOSE_FLAGS_DISABLE_PRODUCER +#define OPENPOSE_FLAGS_DISABLE_DISPLAY +#include +// OpenPose dependencies +#include + +// Custom OpenPose flags +// Producer +DEFINE_string(image_dir, "examples/media/", + "Process a directory of images. Read all standard formats (jpg, png, bmp, etc.)."); +// Display +DEFINE_bool(no_display, false, + "Enable to disable the visual display."); + +// This worker will just read and return all the jpg files in a directory +bool display(const std::shared_ptr>>& datumsPtr) +{ + try + { + // User's displaying/saving/other processing here + // datum.cvOutputData: rendered frame with pose or heatmaps + // datum.poseKeypoints: Array with the estimated pose + char key = ' '; + if (datumsPtr != nullptr && !datumsPtr->empty()) + { + // Display image and sleeps at least 1 ms (it usually sleeps ~5-10 msec to display the image) + cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + key = (char)cv::waitKey(1); + } + else + op::log("Nullptr or empty datumsPtr found.", op::Priority::High); + return (key == 27); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + return true; + } +} + +void printKeypoints(const std::shared_ptr>>& datumsPtr) +{ + try + { + // Example: How to use the pose keypoints + if (datumsPtr != nullptr && !datumsPtr->empty()) + { + op::log("Body keypoints: " + datumsPtr->at(0)->poseKeypoints.toString()); + op::log("Face keypoints: " + datumsPtr->at(0)->faceKeypoints.toString()); + op::log("Left hand keypoints: " + datumsPtr->at(0)->handKeypoints[0].toString()); + op::log("Right hand keypoints: " + datumsPtr->at(0)->handKeypoints[1].toString()); + } + else + op::log("Nullptr or empty datumsPtr found.", op::Priority::High); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +void configureWrapper(op::Wrapper& opWrapper) +{ + try + { + // Configuring OpenPose + + // logging_level + 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::Profiler::setDefaultX(FLAGS_profile_speed); + + // Applying user defined configuration - GFlags to program variables + // outputSize + const auto outputSize = op::flagsToPoint(FLAGS_output_resolution, "-1x-1"); + // netInputSize + const auto netInputSize = op::flagsToPoint(FLAGS_net_resolution, "-1x368"); + // faceNetInputSize + const auto faceNetInputSize = op::flagsToPoint(FLAGS_face_net_resolution, "368x368 (multiples of 16)"); + // handNetInputSize + const auto handNetInputSize = op::flagsToPoint(FLAGS_hand_net_resolution, "368x368 (multiples of 16)"); + // poseModel + const auto poseModel = op::flagsToPoseModel(FLAGS_model_pose); + // JSON saving + if (!FLAGS_write_keypoint.empty()) + op::log("Flag `write_keypoint` is deprecated and will eventually be removed." + " Please, use `write_json` instead.", op::Priority::Max); + // keypointScaleMode + const auto keypointScaleMode = op::flagsToScaleMode(FLAGS_keypoint_scale); + // heatmaps to add + const auto heatMapTypes = op::flagsToHeatMaps(FLAGS_heatmaps_add_parts, FLAGS_heatmaps_add_bkg, + FLAGS_heatmaps_add_PAFs); + const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); + // >1 camera view? + const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1); + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); + // Enabling Google Logging + const bool enableGoogleLogging = true; + + // Pose configuration (use WrapperStructPose{} for default and recommended configuration) + const op::WrapperStructPose wrapperStructPose{ + !FLAGS_body_disable, netInputSize, outputSize, keypointScaleMode, FLAGS_num_gpu, FLAGS_num_gpu_start, + FLAGS_scale_number, (float)FLAGS_scale_gap, op::flagsToRenderMode(FLAGS_render_pose, multipleView), + poseModel, !FLAGS_disable_blending, (float)FLAGS_alpha_pose, (float)FLAGS_alpha_heatmap, + FLAGS_part_to_show, FLAGS_model_folder, heatMapTypes, heatMapScaleMode, FLAGS_part_candidates, + (float)FLAGS_render_threshold, FLAGS_number_people_max, FLAGS_maximize_positives, FLAGS_fps_max, + FLAGS_prototxt_path, FLAGS_caffemodel_path, enableGoogleLogging}; + opWrapper.configure(wrapperStructPose); + // Face configuration (use op::WrapperStructFace{} to disable it) + const op::WrapperStructFace wrapperStructFace{ + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; + opWrapper.configure(wrapperStructFace); + // Hand configuration (use op::WrapperStructHand{} to disable it) + const op::WrapperStructHand wrapperStructHand{ + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, + op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, + (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; + opWrapper.configure(wrapperStructHand); + // Extra functionality configuration (use op::WrapperStructExtra{} to disable it) + const op::WrapperStructExtra wrapperStructExtra{ + FLAGS_3d, FLAGS_3d_min_views, FLAGS_identification, FLAGS_tracking, FLAGS_ik_threads}; + opWrapper.configure(wrapperStructExtra); + // Output (comment or use default argument to disable any output) + const op::WrapperStructOutput wrapperStructOutput{ + FLAGS_cli_verbose, FLAGS_write_keypoint, op::stringToDataFormat(FLAGS_write_keypoint_format), + FLAGS_write_json, FLAGS_write_coco_json, FLAGS_write_coco_foot_json, FLAGS_write_coco_json_variant, + FLAGS_write_images, FLAGS_write_images_format, FLAGS_write_video, FLAGS_write_video_fps, + FLAGS_write_video_with_audio, FLAGS_write_heatmaps, FLAGS_write_heatmaps_format, FLAGS_write_video_3d, + FLAGS_write_video_adam, FLAGS_write_bvh, FLAGS_udp_host, FLAGS_udp_port}; + opWrapper.configure(wrapperStructOutput); + // No GUI. Equivalent to: opWrapper.configure(op::WrapperStructGui{}); + // Set to single-thread (for sequential processing and/or debugging and/or reducing latency) + if (FLAGS_disable_multi_thread) + opWrapper.disableMultiThreading(); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +int tutorialApiCpp() +{ + try + { + op::log("Starting OpenPose demo...", op::Priority::High); + const auto opTimer = op::getTimerInit(); + + // Configuring OpenPose + op::log("Configuring OpenPose...", op::Priority::High); + op::Wrapper opWrapper{op::ThreadManagerMode::Asynchronous}; + configureWrapper(opWrapper); + + // Starting OpenPose + op::log("Starting thread(s)...", op::Priority::High); + opWrapper.start(); + + // Read frames on directory + const auto imagePaths = op::getFilesOnDirectory(FLAGS_image_dir, op::Extensions::Images); + + // Read number of GPUs in your system + const auto numberGPUs = op::getGpuNumber(); + + // Process and display images + // Option a) Harder to implement but the fastest method + // Create 2 different threads: + // 1. One pushing images to OpenPose all the time. + // 2. A second one retrieving those frames. + // Option b) Much easier and faster to implement but slightly slower runtime performance + for (auto imageId = 0u ; imageId < imagePaths.size() ; imageId+=numberGPUs) + { + // Read and push images into OpenPose wrapper + for (auto gpuId = 0 ; gpuId < numberGPUs ; gpuId++) + { + const auto& imagePath = imagePaths.at(imageId+gpuId); + // Faster alternative that moves imageToProcess + auto imageToProcess = cv::imread(imagePath); + opWrapper.waitAndEmplace(imageToProcess); + // // Slower but safer alternative that copies imageToProcess + // const auto imageToProcess = cv::imread(imagePath); + // opWrapper.waitAndPush(imageToProcess); + } + // Retrieve processed results from OpenPose wrapper + for (auto gpuId = 0 ; gpuId < numberGPUs ; gpuId++) + { + std::shared_ptr>> datumProcessed; + const auto status = opWrapper.waitAndPop(datumProcessed); + if (status && datumProcessed != nullptr) + { + printKeypoints(datumProcessed); + if (!FLAGS_no_display) + { + const auto userWantsToExit = display(datumProcessed); + if (userWantsToExit) + { + op::log("User pressed Esc to exit demo.", op::Priority::High); + break; + } + } + } + else + op::log("Image could not be processed.", op::Priority::High); + } + } + + // Measuring total time + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); + + // Return + return 0; + } + catch (const std::exception& e) + { + return -1; + } +} + +int main(int argc, char *argv[]) +{ + // Parsing command line flags + gflags::ParseCommandLineFlags(&argc, &argv, true); + + // Running tutorialApiCpp + return tutorialApiCpp(); +} diff --git a/examples/tutorial_api_cpp/06_asynchronous_custom_input.cpp b/examples/tutorial_api_cpp/06_asynchronous_custom_input.cpp new file mode 100644 index 00000000..d88a3325 --- /dev/null +++ b/examples/tutorial_api_cpp/06_asynchronous_custom_input.cpp @@ -0,0 +1,223 @@ +// ------------------------- OpenPose C++ API Tutorial - Example 6 - Custom Input ------------------------- +// Asynchronous mode: ideal for fast prototyping when performance is not an issue. +// In this function, the user can implement its own way to create frames (e.g., reading his own folder of images) +// and emplaces/pushes the frames to OpenPose. + +// Command-line user intraface +#define OPENPOSE_FLAGS_DISABLE_PRODUCER +#include +// OpenPose dependencies +#include + +// Custom OpenPose flags +// Producer +DEFINE_string(image_dir, "examples/media/", + "Process a directory of images. Read all standard formats (jpg, png, bmp, etc.)."); + +// The W-classes can be implemented either as a template or as simple classes given +// that the user usually knows which kind of data he will move between the queues, +// in this case we assume a std::shared_ptr of a std::vector of op::Datum + +// This worker will just read and return all the basic image file formats in a directory +class UserInputClass +{ +public: + UserInputClass(const std::string& directoryPath) : + mImageFiles{op::getFilesOnDirectory(directoryPath, op::Extensions::Images)}, // For all basic image formats + // If we want only e.g., "jpg" + "png" images + // mImageFiles{op::getFilesOnDirectory(directoryPath, std::vector{"jpg", "png"})}, + mCounter{0}, + mClosed{false} + { + if (mImageFiles.empty()) + op::error("No images found on: " + directoryPath, __LINE__, __FUNCTION__, __FILE__); + } + + std::shared_ptr>> createDatum() + { + // Close program when empty frame + if (mClosed || mImageFiles.size() <= mCounter) + { + op::log("Last frame read and added to queue. Closing program after it is processed.", op::Priority::High); + // This funtion stops this worker, which will eventually stop the whole thread system once all the frames + // have been processed + mClosed = true; + return nullptr; + } + else // if (!mClosed) + { + // Create new datum + auto datumsPtr = std::make_shared>>(); + datumsPtr->emplace_back(); + auto& datumPtr = datumsPtr->at(0); + datumPtr = std::make_shared(); + + // Fill datum + datumPtr->cvInputData = cv::imread(mImageFiles.at(mCounter++)); + + // If empty frame -> return nullptr + if (datumPtr->cvInputData.empty()) + { + op::log("Empty frame detected on path: " + mImageFiles.at(mCounter-1) + ". Closing program.", + op::Priority::High); + mClosed = true; + datumsPtr = nullptr; + } + + return datumsPtr; + } + } + + bool isFinished() const + { + return mClosed; + } + +private: + const std::vector mImageFiles; + unsigned long long mCounter; + bool mClosed; +}; + +void configureWrapper(op::Wrapper& opWrapper) +{ + try + { + // Configuring OpenPose + + // logging_level + 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::Profiler::setDefaultX(FLAGS_profile_speed); + + // Applying user defined configuration - GFlags to program variables + // outputSize + const auto outputSize = op::flagsToPoint(FLAGS_output_resolution, "-1x-1"); + // netInputSize + const auto netInputSize = op::flagsToPoint(FLAGS_net_resolution, "-1x368"); + // faceNetInputSize + const auto faceNetInputSize = op::flagsToPoint(FLAGS_face_net_resolution, "368x368 (multiples of 16)"); + // handNetInputSize + const auto handNetInputSize = op::flagsToPoint(FLAGS_hand_net_resolution, "368x368 (multiples of 16)"); + // poseModel + const auto poseModel = op::flagsToPoseModel(FLAGS_model_pose); + // JSON saving + if (!FLAGS_write_keypoint.empty()) + op::log("Flag `write_keypoint` is deprecated and will eventually be removed." + " Please, use `write_json` instead.", op::Priority::Max); + // keypointScaleMode + const auto keypointScaleMode = op::flagsToScaleMode(FLAGS_keypoint_scale); + // heatmaps to add + const auto heatMapTypes = op::flagsToHeatMaps(FLAGS_heatmaps_add_parts, FLAGS_heatmaps_add_bkg, + FLAGS_heatmaps_add_PAFs); + const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); + // >1 camera view? + const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1); + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); + // Enabling Google Logging + const bool enableGoogleLogging = true; + + // Pose configuration (use WrapperStructPose{} for default and recommended configuration) + const op::WrapperStructPose wrapperStructPose{ + !FLAGS_body_disable, netInputSize, outputSize, keypointScaleMode, FLAGS_num_gpu, FLAGS_num_gpu_start, + FLAGS_scale_number, (float)FLAGS_scale_gap, op::flagsToRenderMode(FLAGS_render_pose, multipleView), + poseModel, !FLAGS_disable_blending, (float)FLAGS_alpha_pose, (float)FLAGS_alpha_heatmap, + FLAGS_part_to_show, FLAGS_model_folder, heatMapTypes, heatMapScaleMode, FLAGS_part_candidates, + (float)FLAGS_render_threshold, FLAGS_number_people_max, FLAGS_maximize_positives, FLAGS_fps_max, + FLAGS_prototxt_path, FLAGS_caffemodel_path, enableGoogleLogging}; + opWrapper.configure(wrapperStructPose); + // Face configuration (use op::WrapperStructFace{} to disable it) + const op::WrapperStructFace wrapperStructFace{ + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; + opWrapper.configure(wrapperStructFace); + // Hand configuration (use op::WrapperStructHand{} to disable it) + const op::WrapperStructHand wrapperStructHand{ + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, + op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, + (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; + opWrapper.configure(wrapperStructHand); + // Extra functionality configuration (use op::WrapperStructExtra{} to disable it) + const op::WrapperStructExtra wrapperStructExtra{ + FLAGS_3d, FLAGS_3d_min_views, FLAGS_identification, FLAGS_tracking, FLAGS_ik_threads}; + opWrapper.configure(wrapperStructExtra); + // Output (comment or use default argument to disable any output) + const op::WrapperStructOutput wrapperStructOutput{ + FLAGS_cli_verbose, FLAGS_write_keypoint, op::stringToDataFormat(FLAGS_write_keypoint_format), + FLAGS_write_json, FLAGS_write_coco_json, FLAGS_write_coco_foot_json, FLAGS_write_coco_json_variant, + FLAGS_write_images, FLAGS_write_images_format, FLAGS_write_video, FLAGS_write_video_fps, + FLAGS_write_video_with_audio, FLAGS_write_heatmaps, FLAGS_write_heatmaps_format, FLAGS_write_video_3d, + FLAGS_write_video_adam, FLAGS_write_bvh, FLAGS_udp_host, FLAGS_udp_port}; + opWrapper.configure(wrapperStructOutput); + // GUI (comment or use default argument to disable any visual output) + const op::WrapperStructGui wrapperStructGui{ + op::flagsToDisplayMode(FLAGS_display, FLAGS_3d), !FLAGS_no_gui_verbose, FLAGS_fullscreen}; + opWrapper.configure(wrapperStructGui); + // Set to single-thread (for sequential processing and/or debugging and/or reducing latency) + if (FLAGS_disable_multi_thread) + opWrapper.disableMultiThreading(); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +int tutorialApiCpp() +{ + try + { + op::log("Starting OpenPose demo...", op::Priority::High); + const auto opTimer = op::getTimerInit(); + + // Configuring OpenPose + op::log("Configuring OpenPose...", op::Priority::High); + op::Wrapper opWrapper{op::ThreadManagerMode::AsynchronousIn}; + configureWrapper(opWrapper); + + // Start, run, and stop processing - exec() blocks this thread until OpenPose wrapper has finished + op::log("Starting thread(s)...", op::Priority::High); + opWrapper.start(); + + // User processing + UserInputClass userInputClass(FLAGS_image_dir); + bool userWantsToExit = false; + while (!userWantsToExit && !userInputClass.isFinished()) + { + // Push frame + auto datumToProcess = userInputClass.createDatum(); + if (datumToProcess != nullptr) + { + auto successfullyEmplaced = opWrapper.waitAndEmplace(datumToProcess); + if (!successfullyEmplaced) + op::log("Processed datum could not be emplaced.", op::Priority::High); + } + } + + op::log("Stopping thread(s)", op::Priority::High); + opWrapper.stop(); + + // Measuring total time + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); + + // Return + return 0; + } + catch (const std::exception& e) + { + return -1; + } +} + +int main(int argc, char *argv[]) +{ + // Parsing command line flags + gflags::ParseCommandLineFlags(&argc, &argv, true); + + // Running tutorialApiCpp + return tutorialApiCpp(); +} diff --git a/examples/tutorial_api_cpp/5_asynchronous_loop_custom_output.cpp b/examples/tutorial_api_cpp/07_asynchronous_custom_output.cpp similarity index 76% rename from examples/tutorial_api_cpp/5_asynchronous_loop_custom_output.cpp rename to examples/tutorial_api_cpp/07_asynchronous_custom_output.cpp index 35191bcc..4d28d871 100644 --- a/examples/tutorial_api_cpp/5_asynchronous_loop_custom_output.cpp +++ b/examples/tutorial_api_cpp/07_asynchronous_custom_output.cpp @@ -1,19 +1,6 @@ -// ------------------------- OpenPose C++ API Tutorial - Example 5 - XXXXXXXXXXXXX ------------------------- -// Asynchronous output mode: ideal for fast prototyping when performance is not an issue and user wants to use the -// output OpenPose format. The user simply gets the processed frames from the OpenPose wrapper when he desires to. - -// This example shows the user how to use the OpenPose wrapper class: - // 1. Read folder of images / video / webcam - // 2. Extract and render keypoint / heatmap / PAF of that image - // 3. Save the results on disk - // 4. User displays the rendered pose - // Everything in a multi-thread scenario -// In addition to the previous OpenPose modules, we also need to use: - // 1. `core` module: - // For the Array class that the `pose` module needs - // For the Datum struct that the `thread` module sends between the queues - // 2. `utilities` module: for the error & logging functions, i.e., op::error & op::log respectively -// This file should only be used for the user to take specific examples. +// ------------------------- OpenPose C++ API Tutorial - Example 7 - Custom Output ------------------------- +// Asynchronous mode: ideal for fast prototyping when performance is not an issue. +// In this function, the user can implement its own way to render/display the frames. // Command-line user intraface #define OPENPOSE_FLAGS_DISABLE_DISPLAY @@ -26,28 +13,15 @@ DEFINE_bool(no_display, false, "Enable to disable the visual display."); -// If the user needs his own variables, he can inherit the op::Datum struct and add them in there. -// UserDatum can be directly used by the OpenPose wrapper because it inherits from op::Datum, just define -// WrapperT>> instead of Wrapper -// (or equivalently WrapperT>>) -struct UserDatum : public op::Datum -{ - bool boolThatUserNeedsForSomeReason; - - UserDatum(const bool boolThatUserNeedsForSomeReason_ = false) : - boolThatUserNeedsForSomeReason{boolThatUserNeedsForSomeReason_} - {} -}; - // The W-classes can be implemented either as a template or as simple classes given // that the user usually knows which kind of data he will move between the queues, -// in this case we assume a std::shared_ptr of a std::vector of UserDatum +// in this case we assume a std::shared_ptr of a std::vector of op::Datum // This worker will just read and return all the jpg files in a directory class UserOutputClass { public: - bool display(const std::shared_ptr>>& datumsPtr) + bool display(const std::shared_ptr>>& datumsPtr) { // User's displaying/saving/other processing here // datumPtr->cvOutputData: rendered frame with pose or heatmaps @@ -60,10 +34,10 @@ public: key = (char)cv::waitKey(1); } else - op::log("Nullptr or empty datumsPtr found.", op::Priority::High, __LINE__, __FUNCTION__, __FILE__); + op::log("Nullptr or empty datumsPtr found.", op::Priority::High); return (key == 27); } - void printKeypoints(const std::shared_ptr>>& datumsPtr) + void printKeypoints(const std::shared_ptr>>& datumsPtr) { // Example: How to use the pose keypoints if (datumsPtr != nullptr && !datumsPtr->empty()) @@ -114,16 +88,15 @@ public: } } else - op::log("Nullptr or empty datumsPtr found.", op::Priority::High, __LINE__, __FUNCTION__, __FILE__); + op::log("Nullptr or empty datumsPtr found.", op::Priority::High); } }; -int tutorialApiCpp5() +void configureWrapper(op::Wrapper& opWrapper) { try { - op::log("Starting OpenPose demo...", op::Priority::High); - const auto timerBegin = std::chrono::high_resolution_clock::now(); + // Configuring OpenPose // logging_level op::check(0 <= FLAGS_logging_level && FLAGS_logging_level <= 255, "Wrong logging_level value.", @@ -132,6 +105,11 @@ int tutorialApiCpp5() op::Profiler::setDefaultX(FLAGS_profile_speed); // Applying user defined configuration - GFlags to program variables + // producerType + op::ProducerType producerType; + std::string producerString; + std::tie(producerType, producerString) = op::flagsToProducer( + FLAGS_image_dir, FLAGS_video, FLAGS_ip_camera, FLAGS_camera, FLAGS_flir_camera, FLAGS_flir_camera_index); // cameraSize const auto cameraSize = op::flagsToPoint(FLAGS_camera_resolution, "-1x-1"); // outputSize @@ -142,11 +120,6 @@ int tutorialApiCpp5() const auto faceNetInputSize = op::flagsToPoint(FLAGS_face_net_resolution, "368x368 (multiples of 16)"); // handNetInputSize const auto handNetInputSize = op::flagsToPoint(FLAGS_hand_net_resolution, "368x368 (multiples of 16)"); - // producerType - op::ProducerType producerType; - std::string producerString; - std::tie(producerType, producerString) = op::flagsToProducer( - FLAGS_image_dir, FLAGS_video, FLAGS_ip_camera, FLAGS_camera, FLAGS_flir_camera, FLAGS_flir_camera_index); // poseModel const auto poseModel = op::flagsToPoseModel(FLAGS_model_pose); // JSON saving @@ -161,12 +134,12 @@ int tutorialApiCpp5() const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); // >1 camera view? const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1 || FLAGS_flir_camera); + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); // Enabling Google Logging const bool enableGoogleLogging = true; - // Configuring OpenPose - op::log("Configuring OpenPose...", op::Priority::High); - op::WrapperT opWrapperT{op::ThreadManagerMode::AsynchronousOut}; // Pose configuration (use WrapperStructPose{} for default and recommended configuration) const op::WrapperStructPose wrapperStructPose{ !FLAGS_body_disable, netInputSize, outputSize, keypointScaleMode, FLAGS_num_gpu, FLAGS_num_gpu_start, @@ -175,28 +148,29 @@ int tutorialApiCpp5() FLAGS_part_to_show, FLAGS_model_folder, heatMapTypes, heatMapScaleMode, FLAGS_part_candidates, (float)FLAGS_render_threshold, FLAGS_number_people_max, FLAGS_maximize_positives, FLAGS_fps_max, FLAGS_prototxt_path, FLAGS_caffemodel_path, enableGoogleLogging}; - opWrapperT.configure(wrapperStructPose); + opWrapper.configure(wrapperStructPose); // Face configuration (use op::WrapperStructFace{} to disable it) const op::WrapperStructFace wrapperStructFace{ - FLAGS_face, faceNetInputSize, op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; - opWrapperT.configure(wrapperStructFace); + opWrapper.configure(wrapperStructFace); // Hand configuration (use op::WrapperStructHand{} to disable it) const op::WrapperStructHand wrapperStructHand{ - FLAGS_hand, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, FLAGS_hand_tracking, + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; - opWrapperT.configure(wrapperStructHand); + opWrapper.configure(wrapperStructHand); // Extra functionality configuration (use op::WrapperStructExtra{} to disable it) const op::WrapperStructExtra wrapperStructExtra{ FLAGS_3d, FLAGS_3d_min_views, FLAGS_identification, FLAGS_tracking, FLAGS_ik_threads}; - opWrapperT.configure(wrapperStructExtra); + opWrapper.configure(wrapperStructExtra); // Producer (use default to disable any input) const op::WrapperStructInput wrapperStructInput{ producerType, producerString, FLAGS_frame_first, FLAGS_frame_step, FLAGS_frame_last, FLAGS_process_real_time, FLAGS_frame_flip, FLAGS_frame_rotate, FLAGS_frames_repeat, cameraSize, FLAGS_camera_parameter_path, FLAGS_frame_undistort, FLAGS_3d_views}; - opWrapperT.configure(wrapperStructInput); + opWrapper.configure(wrapperStructInput); // Output (comment or use default argument to disable any output) const op::WrapperStructOutput wrapperStructOutput{ FLAGS_cli_verbose, FLAGS_write_keypoint, op::stringToDataFormat(FLAGS_write_keypoint_format), @@ -204,15 +178,33 @@ int tutorialApiCpp5() FLAGS_write_images, FLAGS_write_images_format, FLAGS_write_video, FLAGS_write_video_fps, FLAGS_write_video_with_audio, FLAGS_write_heatmaps, FLAGS_write_heatmaps_format, FLAGS_write_video_3d, FLAGS_write_video_adam, FLAGS_write_bvh, FLAGS_udp_host, FLAGS_udp_port}; - opWrapperT.configure(wrapperStructOutput); + opWrapper.configure(wrapperStructOutput); // No GUI. Equivalent to: opWrapper.configure(op::WrapperStructGui{}); // Set to single-thread (for sequential processing and/or debugging and/or reducing latency) if (FLAGS_disable_multi_thread) - opWrapperT.disableMultiThreading(); + opWrapper.disableMultiThreading(); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +int tutorialApiCpp() +{ + try + { + op::log("Starting OpenPose demo...", op::Priority::High); + const auto opTimer = op::getTimerInit(); + + // Configuring OpenPose + op::log("Configuring OpenPose...", op::Priority::High); + op::Wrapper opWrapper{op::ThreadManagerMode::AsynchronousOut}; + configureWrapper(opWrapper); // Start, run, and stop processing - exec() blocks this thread until OpenPose wrapper has finished op::log("Starting thread(s)...", op::Priority::High); - opWrapperT.start(); + opWrapper.start(); // User processing UserOutputClass userOutputClass; @@ -220,33 +212,28 @@ int tutorialApiCpp5() while (!userWantsToExit) { // Pop frame - std::shared_ptr>> datumProcessed; - if (opWrapperT.waitAndPop(datumProcessed)) + std::shared_ptr>> datumProcessed; + if (opWrapper.waitAndPop(datumProcessed)) { if (!FLAGS_no_display) userWantsToExit = userOutputClass.display(datumProcessed);; userOutputClass.printKeypoints(datumProcessed); } // If OpenPose finished reading images - else if (!opWrapperT.isRunning()) + else if (!opWrapper.isRunning()) break; // Something else happened else - op::log("Processed datum could not be emplaced.", op::Priority::High, __LINE__, __FUNCTION__, __FILE__); + op::log("Processed datum could not be emplaced.", op::Priority::High); } op::log("Stopping thread(s)", op::Priority::High); - opWrapperT.stop(); + opWrapper.stop(); // Measuring total time - const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; - const auto message = "OpenPose demo successfully finished. Total time: " - + std::to_string(totalTimeSec) + " seconds."; - op::log(message, op::Priority::High); + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); - // Return successful message + // Return return 0; } catch (const std::exception& e) @@ -260,6 +247,6 @@ int main(int argc, char *argv[]) // Parsing command line flags gflags::ParseCommandLineFlags(&argc, &argv, true); - // Running tutorialApiCpp5 - return tutorialApiCpp5(); + // Running tutorialApiCpp + return tutorialApiCpp(); } diff --git a/examples/tutorial_api_cpp/4_asynchronous_loop_custom_input_and_output.cpp b/examples/tutorial_api_cpp/08_asynchronous_custom_input_output_and_datum.cpp similarity index 83% rename from examples/tutorial_api_cpp/4_asynchronous_loop_custom_input_and_output.cpp rename to examples/tutorial_api_cpp/08_asynchronous_custom_input_output_and_datum.cpp index 48e15d17..7b6409e8 100644 --- a/examples/tutorial_api_cpp/4_asynchronous_loop_custom_input_and_output.cpp +++ b/examples/tutorial_api_cpp/08_asynchronous_custom_input_output_and_datum.cpp @@ -1,19 +1,7 @@ -// ------------------------- OpenPose C++ API Tutorial - Example 4 - Custom Input and Output ------------------------- -// Asynchronous mode: ideal for fast prototyping when performance is not an issue. The user emplaces/pushes and pops frames from the OpenPose wrapper -// when he desires to. - -// This example shows the user how to use the OpenPose wrapper class: - // 1. User reads images - // 2. Extract and render keypoint / heatmap / PAF of that image - // 3. Save the results on disk - // 4. User displays the rendered pose - // Everything in a multi-thread scenario -// In addition to the previous OpenPose modules, we also need to use: - // 1. `core` module: - // For the Array class that the `pose` module needs - // For the Datum struct that the `thread` module sends between the queues - // 2. `utilities` module: for the error & logging functions, i.e., op::error & op::log respectively -// This file should only be used for the user to take specific examples. +// ------------------------- OpenPose C++ API Tutorial - Example 8 - Custom Input and Output ------------------------- +// Asynchronous mode: ideal for fast prototyping when performance is not an issue. +// In this function, the user can implement its own way to create frames (e.g., reading his own folder of images) +// and its own way to render/display them after being processed by OpenPose. // Command-line user intraface #define OPENPOSE_FLAGS_DISABLE_PRODUCER @@ -114,19 +102,27 @@ class UserOutputClass public: bool display(const std::shared_ptr>>& datumsPtr) { - // User's displaying/saving/other processing here - // datumPtr->cvOutputData: rendered frame with pose or heatmaps - // datumPtr->poseKeypoints: Array with the estimated pose - char key = ' '; - if (datumsPtr != nullptr && !datumsPtr->empty()) + try { - cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); - // Display image and sleeps at least 1 ms (it usually sleeps ~5-10 msec to display the image) - key = (char)cv::waitKey(1); + // User's displaying/saving/other processing here + // datumPtr->cvOutputData: rendered frame with pose or heatmaps + // datumPtr->poseKeypoints: Array with the estimated pose + char key = ' '; + if (datumsPtr != nullptr && !datumsPtr->empty()) + { + // Display image and sleeps at least 1 ms (it usually sleeps ~5-10 msec to display the image) + cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + key = (char)cv::waitKey(1); + } + else + op::log("Nullptr or empty datumsPtr found.", op::Priority::High); + return (key == 27); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + return true; } - else - op::log("Nullptr or empty datumsPtr found.", op::Priority::High, __LINE__, __FUNCTION__, __FILE__); - return (key == 27); } void printKeypoints(const std::shared_ptr>>& datumsPtr) { @@ -177,16 +173,15 @@ public: } } else - op::log("Nullptr or empty datumsPtr found.", op::Priority::High, __LINE__, __FUNCTION__, __FILE__); + op::log("Nullptr or empty datumsPtr found.", op::Priority::High); } }; -int tutorialApiCpp4() +void configureWrapper(op::WrapperT& opWrapperT) { try { - op::log("Starting OpenPose demo...", op::Priority::High); - const auto timerBegin = std::chrono::high_resolution_clock::now(); + // Configuring OpenPose // logging_level op::check(0 <= FLAGS_logging_level && FLAGS_logging_level <= 255, "Wrong logging_level value.", @@ -217,12 +212,12 @@ int tutorialApiCpp4() const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); // >1 camera view? const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1); + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); // Enabling Google Logging const bool enableGoogleLogging = true; - // Configuring OpenPose - op::log("Configuring OpenPose...", op::Priority::High); - op::WrapperT opWrapperT{op::ThreadManagerMode::Asynchronous}; // Pose configuration (use WrapperStructPose{} for default and recommended configuration) const op::WrapperStructPose wrapperStructPose{ !FLAGS_body_disable, netInputSize, outputSize, keypointScaleMode, FLAGS_num_gpu, FLAGS_num_gpu_start, @@ -234,12 +229,13 @@ int tutorialApiCpp4() opWrapperT.configure(wrapperStructPose); // Face configuration (use op::WrapperStructFace{} to disable it) const op::WrapperStructFace wrapperStructFace{ - FLAGS_face, faceNetInputSize, op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; opWrapperT.configure(wrapperStructFace); // Hand configuration (use op::WrapperStructHand{} to disable it) const op::WrapperStructHand wrapperStructHand{ - FLAGS_hand, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, FLAGS_hand_tracking, + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; opWrapperT.configure(wrapperStructHand); @@ -259,6 +255,24 @@ int tutorialApiCpp4() // Set to single-thread (for sequential processing and/or debugging and/or reducing latency) if (FLAGS_disable_multi_thread) opWrapperT.disableMultiThreading(); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +int tutorialApiCpp() +{ + try + { + op::log("Starting OpenPose demo...", op::Priority::High); + const auto opTimer = op::getTimerInit(); + + // Configuring OpenPose + op::log("Configuring OpenPose...", op::Priority::High); + op::WrapperT opWrapperT{op::ThreadManagerMode::Asynchronous}; + configureWrapper(opWrapperT); // Start, run, and stop processing - exec() blocks this thread until OpenPose wrapper has finished op::log("Starting thread(s)...", op::Priority::High); @@ -284,8 +298,7 @@ int tutorialApiCpp4() userOutputClass.printKeypoints(datumProcessed); } else - op::log("Processed datum could not be emplaced.", op::Priority::High, - __LINE__, __FUNCTION__, __FILE__); + op::log("Processed datum could not be emplaced.", op::Priority::High); } } @@ -293,14 +306,9 @@ int tutorialApiCpp4() opWrapperT.stop(); // Measuring total time - const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; - const auto message = "OpenPose demo successfully finished. Total time: " - + std::to_string(totalTimeSec) + " seconds."; - op::log(message, op::Priority::High); + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); - // Return successful message + // Return return 0; } catch (const std::exception& e) @@ -314,6 +322,6 @@ int main(int argc, char *argv[]) // Parsing command line flags gflags::ParseCommandLineFlags(&argc, &argv, true); - // Running tutorialApiCpp4 - return tutorialApiCpp4(); + // Running tutorialApiCpp + return tutorialApiCpp(); } diff --git a/examples/tutorial_api_cpp/09_face_from_image.cpp b/examples/tutorial_api_cpp/09_face_from_image.cpp new file mode 100644 index 00000000..10e0f733 --- /dev/null +++ b/examples/tutorial_api_cpp/09_face_from_image.cpp @@ -0,0 +1,221 @@ +// ----------------------------- OpenPose C++ API Tutorial - Example 9 - Face from Image ----------------------------- +// It reads an image and the face location, process it, and displays the face keypoints. In addition, +// it includes all the OpenPose configuration flags. +// Input: An image and the face rectangle locations. +// Output: OpenPose face keypoint detection. +// NOTE: This demo is auto-selecting the following flags: `--body_disable --face --face_detector 2` + +// Command-line user intraface +#define OPENPOSE_FLAGS_DISABLE_PRODUCER +#define OPENPOSE_FLAGS_DISABLE_DISPLAY +#include +// OpenPose dependencies +#include + +// Custom OpenPose flags +// Producer +DEFINE_string(image_path, "examples/media/COCO_val2014_000000000241.jpg", + "Process an image. Read all standard formats (jpg, png, bmp, etc.)."); +// Display +DEFINE_bool(no_display, false, + "Enable to disable the visual display."); + +// This worker will just read and return all the jpg files in a directory +void display(const std::shared_ptr>>& datumsPtr) +{ + try + { + // User's displaying/saving/other processing here + // datum.cvOutputData: rendered frame with pose or heatmaps + // datum.poseKeypoints: Array with the estimated pose + if (datumsPtr != nullptr && !datumsPtr->empty()) + { + // Display image + cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + cv::waitKey(0); + } + else + op::log("Nullptr or empty datumsPtr found.", op::Priority::High); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +void printKeypoints(const std::shared_ptr>>& datumsPtr) +{ + try + { + // Example: How to use the pose keypoints + if (datumsPtr != nullptr && !datumsPtr->empty()) + { + op::log("Body keypoints: " + datumsPtr->at(0)->poseKeypoints.toString()); + op::log("Face keypoints: " + datumsPtr->at(0)->faceKeypoints.toString()); + op::log("Left hand keypoints: " + datumsPtr->at(0)->handKeypoints[0].toString()); + op::log("Right hand keypoints: " + datumsPtr->at(0)->handKeypoints[1].toString()); + } + else + op::log("Nullptr or empty datumsPtr found.", op::Priority::High); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +void configureWrapper(op::Wrapper& opWrapper) +{ + try + { + // Configuring OpenPose + + // logging_level + 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::Profiler::setDefaultX(FLAGS_profile_speed); + + // Applying user defined configuration - GFlags to program variables + // outputSize + const auto outputSize = op::flagsToPoint(FLAGS_output_resolution, "-1x-1"); + // netInputSize + const auto netInputSize = op::flagsToPoint(FLAGS_net_resolution, "-1x368"); + // faceNetInputSize + const auto faceNetInputSize = op::flagsToPoint(FLAGS_face_net_resolution, "368x368 (multiples of 16)"); + // handNetInputSize + const auto handNetInputSize = op::flagsToPoint(FLAGS_hand_net_resolution, "368x368 (multiples of 16)"); + // poseModel + const auto poseModel = op::flagsToPoseModel(FLAGS_model_pose); + // JSON saving + if (!FLAGS_write_keypoint.empty()) + op::log("Flag `write_keypoint` is deprecated and will eventually be removed." + " Please, use `write_json` instead.", op::Priority::Max); + // keypointScaleMode + const auto keypointScaleMode = op::flagsToScaleMode(FLAGS_keypoint_scale); + // heatmaps to add + const auto heatMapTypes = op::flagsToHeatMaps(FLAGS_heatmaps_add_parts, FLAGS_heatmaps_add_bkg, + FLAGS_heatmaps_add_PAFs); + const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); + // >1 camera view? + const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1); + // Face and hand detectors + const auto faceDetector = op::Detector::Provided; + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); + // Enabling Google Logging + const bool enableGoogleLogging = true; + + // Pose configuration (use WrapperStructPose{} for default and recommended configuration) + const auto bodyEnable = false; + const op::WrapperStructPose wrapperStructPose{ + bodyEnable, netInputSize, outputSize, keypointScaleMode, FLAGS_num_gpu, FLAGS_num_gpu_start, + FLAGS_scale_number, (float)FLAGS_scale_gap, op::flagsToRenderMode(FLAGS_render_pose, multipleView), + poseModel, !FLAGS_disable_blending, (float)FLAGS_alpha_pose, (float)FLAGS_alpha_heatmap, + FLAGS_part_to_show, FLAGS_model_folder, heatMapTypes, heatMapScaleMode, FLAGS_part_candidates, + (float)FLAGS_render_threshold, FLAGS_number_people_max, FLAGS_maximize_positives, FLAGS_fps_max, + FLAGS_prototxt_path, FLAGS_caffemodel_path, enableGoogleLogging}; + opWrapper.configure(wrapperStructPose); + // Face configuration (use op::WrapperStructFace{} to disable it) + const auto face = true; + const op::WrapperStructFace wrapperStructFace{ + face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; + opWrapper.configure(wrapperStructFace); + // Hand configuration (use op::WrapperStructHand{} to disable it) + const op::WrapperStructHand wrapperStructHand{ + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, + op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, + (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; + opWrapper.configure(wrapperStructHand); + // Extra functionality configuration (use op::WrapperStructExtra{} to disable it) + const op::WrapperStructExtra wrapperStructExtra{ + FLAGS_3d, FLAGS_3d_min_views, FLAGS_identification, FLAGS_tracking, FLAGS_ik_threads}; + opWrapper.configure(wrapperStructExtra); + // Output (comment or use default argument to disable any output) + const op::WrapperStructOutput wrapperStructOutput{ + FLAGS_cli_verbose, FLAGS_write_keypoint, op::stringToDataFormat(FLAGS_write_keypoint_format), + FLAGS_write_json, FLAGS_write_coco_json, FLAGS_write_coco_foot_json, FLAGS_write_coco_json_variant, + FLAGS_write_images, FLAGS_write_images_format, FLAGS_write_video, FLAGS_write_video_fps, + FLAGS_write_video_with_audio, FLAGS_write_heatmaps, FLAGS_write_heatmaps_format, FLAGS_write_video_3d, + FLAGS_write_video_adam, FLAGS_write_bvh, FLAGS_udp_host, FLAGS_udp_port}; + opWrapper.configure(wrapperStructOutput); + // No GUI. Equivalent to: opWrapper.configure(op::WrapperStructGui{}); + // Set to single-thread (for sequential processing and/or debugging and/or reducing latency) + if (FLAGS_disable_multi_thread) + opWrapper.disableMultiThreading(); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +int tutorialApiCpp() +{ + try + { + op::log("Starting OpenPose demo...", op::Priority::High); + const auto opTimer = op::getTimerInit(); + + // Configuring OpenPose + op::log("Configuring OpenPose...", op::Priority::High); + op::Wrapper opWrapper{op::ThreadManagerMode::Asynchronous}; + configureWrapper(opWrapper); + + // Starting OpenPose + op::log("Starting thread(s)...", op::Priority::High); + opWrapper.start(); + + // Read image and face rectangle locations + const auto imageToProcess = cv::imread(FLAGS_image_path); + const std::vector> faceRectangles{ + op::Rectangle{330.119385f, 277.532715f, 48.717274f, 48.717274f}, // Face 0 + op::Rectangle{24.036991f, 267.918793f, 65.175171f, 65.175171f}, // Face 1 + op::Rectangle{151.803436f, 32.477852f, 108.295761f, 108.295761f} // Face 2 + }; + + // Create new datum + auto datumsPtr = std::make_shared>>(); + datumsPtr->emplace_back(); + auto& datumPtr = datumsPtr->at(0); + datumPtr = std::make_shared(); + // Fill datum with image and faceRectangles + datumPtr->cvInputData = imageToProcess; + datumPtr->faceRectangles = faceRectangles; + + // Process and display image + opWrapper.emplaceAndPop(datumsPtr); + if (datumsPtr != nullptr) + { + printKeypoints(datumsPtr); + if (!FLAGS_no_display) + display(datumsPtr); + } + else + op::log("Image could not be processed.", op::Priority::High); + + // Info + op::log("NOTE: In addition with the user flags, this demo has auto-selected the following flags:" + " `--body_disable --face --face_detector 2`", op::Priority::High); + + // Measuring total time + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); + + // Return + return 0; + } + catch (const std::exception& e) + { + return -1; + } +} + +int main(int argc, char *argv[]) +{ + // Parsing command line flags + gflags::ParseCommandLineFlags(&argc, &argv, true); + + // Running tutorialApiCpp + return tutorialApiCpp(); +} diff --git a/examples/tutorial_api_cpp/10_hand_from_image.cpp b/examples/tutorial_api_cpp/10_hand_from_image.cpp new file mode 100644 index 00000000..cf0a35cc --- /dev/null +++ b/examples/tutorial_api_cpp/10_hand_from_image.cpp @@ -0,0 +1,230 @@ +// ----------------------------- OpenPose C++ API Tutorial - Example 9 - Face from Image ----------------------------- +// It reads an image and the hand location, process it, and displays the hand keypoints. In addition, +// it includes all the OpenPose configuration flags. +// Input: An image and the hand rectangle locations. +// Output: OpenPose hand keypoint detection. +// NOTE: This demo is auto-selecting the following flags: `--body_disable --hand --hand_detector 2` + +// Command-line user intraface +#define OPENPOSE_FLAGS_DISABLE_PRODUCER +#define OPENPOSE_FLAGS_DISABLE_DISPLAY +#include +// OpenPose dependencies +#include + +// Custom OpenPose flags +// Producer +DEFINE_string(image_path, "examples/media/COCO_val2014_000000000241.jpg", + "Process an image. Read all standard formats (jpg, png, bmp, etc.)."); +// Display +DEFINE_bool(no_display, false, + "Enable to disable the visual display."); + +// This worker will just read and return all the jpg files in a directory +void display(const std::shared_ptr>>& datumsPtr) +{ + try + { + // User's displaying/saving/other processing here + // datum.cvOutputData: rendered frame with pose or heatmaps + // datum.poseKeypoints: Array with the estimated pose + if (datumsPtr != nullptr && !datumsPtr->empty()) + { + // Display image + cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + cv::waitKey(0); + } + else + op::log("Nullptr or empty datumsPtr found.", op::Priority::High); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +void printKeypoints(const std::shared_ptr>>& datumsPtr) +{ + try + { + // Example: How to use the pose keypoints + if (datumsPtr != nullptr && !datumsPtr->empty()) + { + op::log("Body keypoints: " + datumsPtr->at(0)->poseKeypoints.toString()); + op::log("Face keypoints: " + datumsPtr->at(0)->faceKeypoints.toString()); + op::log("Left hand keypoints: " + datumsPtr->at(0)->handKeypoints[0].toString()); + op::log("Right hand keypoints: " + datumsPtr->at(0)->handKeypoints[1].toString()); + } + else + op::log("Nullptr or empty datumsPtr found.", op::Priority::High); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +void configureWrapper(op::Wrapper& opWrapper) +{ + try + { + // Configuring OpenPose + + // logging_level + 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::Profiler::setDefaultX(FLAGS_profile_speed); + + // Applying user defined configuration - GFlags to program variables + // outputSize + const auto outputSize = op::flagsToPoint(FLAGS_output_resolution, "-1x-1"); + // netInputSize + const auto netInputSize = op::flagsToPoint(FLAGS_net_resolution, "-1x368"); + // faceNetInputSize + const auto faceNetInputSize = op::flagsToPoint(FLAGS_face_net_resolution, "368x368 (multiples of 16)"); + // handNetInputSize + const auto handNetInputSize = op::flagsToPoint(FLAGS_hand_net_resolution, "368x368 (multiples of 16)"); + // poseModel + const auto poseModel = op::flagsToPoseModel(FLAGS_model_pose); + // JSON saving + if (!FLAGS_write_keypoint.empty()) + op::log("Flag `write_keypoint` is deprecated and will eventually be removed." + " Please, use `write_json` instead.", op::Priority::Max); + // keypointScaleMode + const auto keypointScaleMode = op::flagsToScaleMode(FLAGS_keypoint_scale); + // heatmaps to add + const auto heatMapTypes = op::flagsToHeatMaps(FLAGS_heatmaps_add_parts, FLAGS_heatmaps_add_bkg, + FLAGS_heatmaps_add_PAFs); + const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); + // >1 camera view? + const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1); + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::Detector::Provided; + // Enabling Google Logging + const bool enableGoogleLogging = true; + + // Pose configuration (use WrapperStructPose{} for default and recommended configuration) + const auto bodyEnable = false; + const op::WrapperStructPose wrapperStructPose{ + bodyEnable, netInputSize, outputSize, keypointScaleMode, FLAGS_num_gpu, FLAGS_num_gpu_start, + FLAGS_scale_number, (float)FLAGS_scale_gap, op::flagsToRenderMode(FLAGS_render_pose, multipleView), + poseModel, !FLAGS_disable_blending, (float)FLAGS_alpha_pose, (float)FLAGS_alpha_heatmap, + FLAGS_part_to_show, FLAGS_model_folder, heatMapTypes, heatMapScaleMode, FLAGS_part_candidates, + (float)FLAGS_render_threshold, FLAGS_number_people_max, FLAGS_maximize_positives, FLAGS_fps_max, + FLAGS_prototxt_path, FLAGS_caffemodel_path, enableGoogleLogging}; + opWrapper.configure(wrapperStructPose); + // Face configuration (use op::WrapperStructFace{} to disable it) + const op::WrapperStructFace wrapperStructFace{ + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; + opWrapper.configure(wrapperStructFace); + // Hand configuration (use op::WrapperStructHand{} to disable it) + const auto hand = true; + const op::WrapperStructHand wrapperStructHand{ + hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, + op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, + (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; + opWrapper.configure(wrapperStructHand); + // Extra functionality configuration (use op::WrapperStructExtra{} to disable it) + const op::WrapperStructExtra wrapperStructExtra{ + FLAGS_3d, FLAGS_3d_min_views, FLAGS_identification, FLAGS_tracking, FLAGS_ik_threads}; + opWrapper.configure(wrapperStructExtra); + // Output (comment or use default argument to disable any output) + const op::WrapperStructOutput wrapperStructOutput{ + FLAGS_cli_verbose, FLAGS_write_keypoint, op::stringToDataFormat(FLAGS_write_keypoint_format), + FLAGS_write_json, FLAGS_write_coco_json, FLAGS_write_coco_foot_json, FLAGS_write_coco_json_variant, + FLAGS_write_images, FLAGS_write_images_format, FLAGS_write_video, FLAGS_write_video_fps, + FLAGS_write_video_with_audio, FLAGS_write_heatmaps, FLAGS_write_heatmaps_format, FLAGS_write_video_3d, + FLAGS_write_video_adam, FLAGS_write_bvh, FLAGS_udp_host, FLAGS_udp_port}; + opWrapper.configure(wrapperStructOutput); + // No GUI. Equivalent to: opWrapper.configure(op::WrapperStructGui{}); + // Set to single-thread (for sequential processing and/or debugging and/or reducing latency) + if (FLAGS_disable_multi_thread) + opWrapper.disableMultiThreading(); + } + catch (const std::exception& e) + { + op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } +} + +int tutorialApiCpp() +{ + try + { + op::log("Starting OpenPose demo...", op::Priority::High); + const auto opTimer = op::getTimerInit(); + + // Configuring OpenPose + op::log("Configuring OpenPose...", op::Priority::High); + op::Wrapper opWrapper{op::ThreadManagerMode::Asynchronous}; + configureWrapper(opWrapper); + + // Starting OpenPose + op::log("Starting thread(s)...", op::Priority::High); + opWrapper.start(); + + // Read image and hand rectangle locations + const auto imageToProcess = cv::imread(FLAGS_image_path); + const std::vector, 2>> handRectangles{ + // Left/Right hands person 0 + std::array, 2>{ + op::Rectangle{320.035889f, 377.675049f, 69.300949f, 69.300949f}, + op::Rectangle{0.f, 0.f, 0.f, 0.f}}, + // Left/Right hands person 1 + std::array, 2>{ + op::Rectangle{80.155792f, 407.673492f, 80.812706f, 80.812706f}, + op::Rectangle{46.449715f, 404.559753f, 98.898178f, 98.898178f}}, + // Left/Right hands person 2 + std::array, 2>{ + op::Rectangle{185.692673f, 303.112244f, 157.587555f, 157.587555f}, + op::Rectangle{88.984360f, 268.866547f, 117.818230f, 117.818230f}} + }; + + // Create new datum + auto datumsPtr = std::make_shared>>(); + datumsPtr->emplace_back(); + auto& datumPtr = datumsPtr->at(0); + datumPtr = std::make_shared(); + // Fill datum with image and handRectangles + datumPtr->cvInputData = imageToProcess; + datumPtr->handRectangles = handRectangles; + + // Process and display image + opWrapper.emplaceAndPop(datumsPtr); + if (datumsPtr != nullptr) + { + printKeypoints(datumsPtr); + if (!FLAGS_no_display) + display(datumsPtr); + } + else + op::log("Image could not be processed.", op::Priority::High); + + // Info + op::log("NOTE: In addition with the user flags, this demo has auto-selected the following flags:" + " `--body_disable --hand --hand_detector 2`", op::Priority::High); + + // Measuring total time + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); + + // Return + return 0; + } + catch (const std::exception& e) + { + return -1; + } +} + +int main(int argc, char *argv[]) +{ + // Parsing command line flags + gflags::ParseCommandLineFlags(&argc, &argv, true); + + // Running tutorialApiCpp + return tutorialApiCpp(); +} diff --git a/examples/tutorial_api_cpp/7_synchronous_custom_input.cpp b/examples/tutorial_api_cpp/11_synchronous_custom_input.cpp similarity index 94% rename from examples/tutorial_api_cpp/7_synchronous_custom_input.cpp rename to examples/tutorial_api_cpp/11_synchronous_custom_input.cpp index afa71a14..f104cd26 100644 --- a/examples/tutorial_api_cpp/7_synchronous_custom_input.cpp +++ b/examples/tutorial_api_cpp/11_synchronous_custom_input.cpp @@ -110,7 +110,7 @@ private: unsigned long long mCounter; }; -int tutorialApiCpp7() +int tutorialApiCpp() { try { @@ -152,6 +152,9 @@ int tutorialApiCpp7() // >1 camera view? // const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1 || FLAGS_flir_camera); const auto multipleView = false; + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); // Enabling Google Logging const bool enableGoogleLogging = true; @@ -177,12 +180,13 @@ int tutorialApiCpp7() opWrapperT.configure(wrapperStructPose); // Face configuration (use op::WrapperStructFace{} to disable it) const op::WrapperStructFace wrapperStructFace{ - FLAGS_face, faceNetInputSize, op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; opWrapperT.configure(wrapperStructFace); // Hand configuration (use op::WrapperStructHand{} to disable it) const op::WrapperStructHand wrapperStructHand{ - FLAGS_hand, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, FLAGS_hand_tracking, + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; opWrapperT.configure(wrapperStructHand); @@ -212,8 +216,8 @@ int tutorialApiCpp7() // Measuring total time const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; + const auto totalTimeSec = double( + std::chrono::duration_cast(now-timerBegin).count()* 1e-9); const auto message = "OpenPose demo successfully finished. Total time: " + std::to_string(totalTimeSec) + " seconds."; op::log(message, op::Priority::High); @@ -232,6 +236,6 @@ int main(int argc, char *argv[]) // Parsing command line flags gflags::ParseCommandLineFlags(&argc, &argv, true); - // Running tutorialApiCpp7 - return tutorialApiCpp7(); + // Running tutorialApiCpp + return tutorialApiCpp(); } diff --git a/examples/tutorial_api_cpp/6_synchronous_custom_postprocessing.cpp b/examples/tutorial_api_cpp/13_synchronous_custom_postprocessing.cpp similarity index 94% rename from examples/tutorial_api_cpp/6_synchronous_custom_postprocessing.cpp rename to examples/tutorial_api_cpp/13_synchronous_custom_postprocessing.cpp index 35b4ce70..e03f7bd1 100644 --- a/examples/tutorial_api_cpp/6_synchronous_custom_postprocessing.cpp +++ b/examples/tutorial_api_cpp/13_synchronous_custom_postprocessing.cpp @@ -68,7 +68,7 @@ public: } }; -int tutorialApiCpp6() +int tutorialApiCpp() { try { @@ -87,6 +87,11 @@ int tutorialApiCpp6() // op::Profiler::setDefaultX(100); // Applying user defined configuration - GFlags to program variables + // producerType + op::ProducerType producerType; + std::string producerString; + std::tie(producerType, producerString) = op::flagsToProducer( + FLAGS_image_dir, FLAGS_video, FLAGS_ip_camera, FLAGS_camera, FLAGS_flir_camera, FLAGS_flir_camera_index); // cameraSize const auto cameraSize = op::flagsToPoint(FLAGS_camera_resolution, "-1x-1"); // outputSize @@ -97,11 +102,6 @@ int tutorialApiCpp6() const auto faceNetInputSize = op::flagsToPoint(FLAGS_face_net_resolution, "368x368 (multiples of 16)"); // handNetInputSize const auto handNetInputSize = op::flagsToPoint(FLAGS_hand_net_resolution, "368x368 (multiples of 16)"); - // producerType - op::ProducerType producerType; - std::string producerString; - std::tie(producerType, producerString) = op::flagsToProducer( - FLAGS_image_dir, FLAGS_video, FLAGS_ip_camera, FLAGS_camera, FLAGS_flir_camera, FLAGS_flir_camera_index); // poseModel const auto poseModel = op::flagsToPoseModel(FLAGS_model_pose); // JSON saving @@ -116,6 +116,9 @@ int tutorialApiCpp6() const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); // >1 camera view? const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1 || FLAGS_flir_camera); + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); // Enabling Google Logging const bool enableGoogleLogging = true; @@ -141,12 +144,13 @@ int tutorialApiCpp6() opWrapperT.configure(wrapperStructPose); // Face configuration (use op::WrapperStructFace{} to disable it) const op::WrapperStructFace wrapperStructFace{ - FLAGS_face, faceNetInputSize, op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; opWrapperT.configure(wrapperStructFace); // Hand configuration (use op::WrapperStructHand{} to disable it) const op::WrapperStructHand wrapperStructHand{ - FLAGS_hand, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, FLAGS_hand_tracking, + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; opWrapperT.configure(wrapperStructHand); @@ -182,8 +186,8 @@ int tutorialApiCpp6() // Measuring total time const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; + const auto totalTimeSec = double( + std::chrono::duration_cast(now-timerBegin).count()* 1e-9); const auto message = "OpenPose demo successfully finished. Total time: " + std::to_string(totalTimeSec) + " seconds."; op::log(message, op::Priority::High); @@ -202,6 +206,6 @@ int main(int argc, char *argv[]) // Parsing command line flags gflags::ParseCommandLineFlags(&argc, &argv, true); - // Running tutorialApiCpp6 - return tutorialApiCpp6(); + // Running tutorialApiCpp + return tutorialApiCpp(); } diff --git a/examples/tutorial_api_cpp/8_synchronous_custom_output.cpp b/examples/tutorial_api_cpp/14_synchronous_custom_output.cpp similarity index 95% rename from examples/tutorial_api_cpp/8_synchronous_custom_output.cpp rename to examples/tutorial_api_cpp/14_synchronous_custom_output.cpp index 795bc483..2980a89a 100644 --- a/examples/tutorial_api_cpp/8_synchronous_custom_output.cpp +++ b/examples/tutorial_api_cpp/14_synchronous_custom_output.cpp @@ -125,7 +125,7 @@ public: } }; -int tutorialApiCpp8() +int tutorialApiCpp() { try { @@ -144,6 +144,11 @@ int tutorialApiCpp8() // op::Profiler::setDefaultX(100); // Applying user defined configuration - GFlags to program variables + // producerType + op::ProducerType producerType; + std::string producerString; + std::tie(producerType, producerString) = op::flagsToProducer( + FLAGS_image_dir, FLAGS_video, FLAGS_ip_camera, FLAGS_camera, FLAGS_flir_camera, FLAGS_flir_camera_index); // cameraSize const auto cameraSize = op::flagsToPoint(FLAGS_camera_resolution, "-1x-1"); // outputSize @@ -154,11 +159,6 @@ int tutorialApiCpp8() const auto faceNetInputSize = op::flagsToPoint(FLAGS_face_net_resolution, "368x368 (multiples of 16)"); // handNetInputSize const auto handNetInputSize = op::flagsToPoint(FLAGS_hand_net_resolution, "368x368 (multiples of 16)"); - // producerType - op::ProducerType producerType; - std::string producerString; - std::tie(producerType, producerString) = op::flagsToProducer( - FLAGS_image_dir, FLAGS_video, FLAGS_ip_camera, FLAGS_camera, FLAGS_flir_camera, FLAGS_flir_camera_index); // poseModel const auto poseModel = op::flagsToPoseModel(FLAGS_model_pose); // JSON saving @@ -173,6 +173,9 @@ int tutorialApiCpp8() const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); // >1 camera view? const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1 || FLAGS_flir_camera); + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); // Enabling Google Logging const bool enableGoogleLogging = true; @@ -198,12 +201,13 @@ int tutorialApiCpp8() opWrapperT.configure(wrapperStructPose); // Face configuration (use op::WrapperStructFace{} to disable it) const op::WrapperStructFace wrapperStructFace{ - FLAGS_face, faceNetInputSize, op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; opWrapperT.configure(wrapperStructFace); // Hand configuration (use op::WrapperStructHand{} to disable it) const op::WrapperStructHand wrapperStructHand{ - FLAGS_hand, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, FLAGS_hand_tracking, + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; opWrapperT.configure(wrapperStructHand); @@ -236,8 +240,8 @@ int tutorialApiCpp8() // Measuring total time const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; + const auto totalTimeSec = double( + std::chrono::duration_cast(now-timerBegin).count()* 1e-9); const auto message = "OpenPose demo successfully finished. Total time: " + std::to_string(totalTimeSec) + " seconds."; op::log(message, op::Priority::High); @@ -256,6 +260,6 @@ int main(int argc, char *argv[]) // Parsing command line flags gflags::ParseCommandLineFlags(&argc, &argv, true); - // Running tutorialApiCpp8 - return tutorialApiCpp8(); + // Running tutorialApiCpp + return tutorialApiCpp(); } diff --git a/examples/tutorial_api_cpp/9_synchronous_custom_all.cpp b/examples/tutorial_api_cpp/15_synchronous_custom_all.cpp similarity index 96% rename from examples/tutorial_api_cpp/9_synchronous_custom_all.cpp rename to examples/tutorial_api_cpp/15_synchronous_custom_all.cpp index 940db9bc..510fa9d3 100644 --- a/examples/tutorial_api_cpp/9_synchronous_custom_all.cpp +++ b/examples/tutorial_api_cpp/15_synchronous_custom_all.cpp @@ -224,7 +224,7 @@ public: } }; -int tutorialApiCpp9() +int tutorialApiCpp() { try { @@ -260,6 +260,9 @@ int tutorialApiCpp9() const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); // >1 camera view? const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1); + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); // Enabling Google Logging const bool enableGoogleLogging = true; @@ -295,12 +298,13 @@ int tutorialApiCpp9() opWrapperT.configure(wrapperStructPose); // Face configuration (use op::WrapperStructFace{} to disable it) const op::WrapperStructFace wrapperStructFace{ - FLAGS_face, faceNetInputSize, op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; opWrapperT.configure(wrapperStructFace); // Hand configuration (use op::WrapperStructHand{} to disable it) const op::WrapperStructHand wrapperStructHand{ - FLAGS_hand, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, FLAGS_hand_tracking, + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; opWrapperT.configure(wrapperStructHand); @@ -327,8 +331,8 @@ int tutorialApiCpp9() // Measuring total time const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; + const auto totalTimeSec = double( + std::chrono::duration_cast(now-timerBegin).count()* 1e-9); const auto message = "OpenPose demo successfully finished. Total time: " + std::to_string(totalTimeSec) + " seconds."; op::log(message, op::Priority::High); @@ -347,6 +351,6 @@ int main(int argc, char *argv[]) // Parsing command line flags gflags::ParseCommandLineFlags(&argc, &argv, true); - // Running tutorialApiCpp9 - return tutorialApiCpp9(); + // Running tutorialApiCpp + return tutorialApiCpp(); } diff --git a/examples/tutorial_api_cpp/CMakeLists.txt b/examples/tutorial_api_cpp/CMakeLists.txt index 8d9dc191..881b2b76 100644 --- a/examples/tutorial_api_cpp/CMakeLists.txt +++ b/examples/tutorial_api_cpp/CMakeLists.txt @@ -1,13 +1,18 @@ set(EXAMPLE_FILES - 1_body_from_image.cpp - 2_whole_body_from_image.cpp - 3_keypoints_from_image_configurable.cpp - 4_asynchronous_loop_custom_input_and_output.cpp - 5_asynchronous_loop_custom_output.cpp - 6_synchronous_custom_postprocessing.cpp - 7_synchronous_custom_input.cpp - 8_synchronous_custom_output.cpp - 9_synchronous_custom_all.cpp) + 01_body_from_image_default.cpp + 02_whole_body_from_image_default.cpp + 03_keypoints_from_image.cpp + 04_keypoints_from_images.cpp + 05_keypoints_from_images_multi_gpu.cpp + 06_asynchronous_custom_input.cpp + 07_asynchronous_custom_output.cpp + 08_asynchronous_custom_input_output_and_datum.cpp + 09_face_from_image.cpp + 10_hand_from_image.cpp + 11_synchronous_custom_input.cpp + 13_synchronous_custom_postprocessing.cpp + 14_synchronous_custom_output.cpp + 15_synchronous_custom_all.cpp) include(${CMAKE_SOURCE_DIR}/cmake/Utils.cmake) diff --git a/examples/tutorial_developer/thread_2_user_processing_function.cpp b/examples/tutorial_api_thread/1_thread_user_processing_function.cpp similarity index 58% rename from examples/tutorial_developer/thread_2_user_processing_function.cpp rename to examples/tutorial_api_thread/1_thread_user_processing_function.cpp index 4c810d64..6a13475a 100644 --- a/examples/tutorial_developer/thread_2_user_processing_function.cpp +++ b/examples/tutorial_api_thread/1_thread_user_processing_function.cpp @@ -1,4 +1,4 @@ -// ------------------------- OpenPose Library Tutorial - Thread - Example 2 - User Processing Function ------------------------- +// ------------------------- OpenPose Library Tutorial - Thread - Example 1 - User Processing Function ------------------------- // This fourth example shows the user how to: // 1. Read folder of images / video / webcam (`producer` module) // 2. Use the processing implemented by the user @@ -8,58 +8,10 @@ // 1. `core` module: for the Datum struct that the `thread` module sends between the queues // 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 -// Allow Google Flags in Ubuntu 14 -#ifndef GFLAGS_GFLAGS_H_ - namespace gflags = google; -#endif +// Command-line user intraface +#include // OpenPose dependencies -#include -#include -#include -#include -#include - -// See all the available parameter options withe the `--help` flag. E.g., `build/examples/openpose/openpose.bin --help` -// Note: This command 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_int32(camera, -1, "The camera index for cv::VideoCapture. Integer in the range [0, 9]. Select a negative" - " number (by default), to auto-detect and open the first available camera."); -DEFINE_string(camera_resolution, "-1x-1", "Set the camera resolution (either `--camera` or `--flir_camera`). `-1x-1` will use the" - " default 1280x720 for `--camera`, or the maximum flir camera resolution available for" - " `--flir_camera`"); -DEFINE_string(video, "", "Use a video file instead of the camera. Use `examples/media/video.avi` for our default" - " example video."); -DEFINE_string(image_dir, "", "Process a directory of images. Use `examples/media/` for our default example folder with 20" - " images. Read all standard formats (jpg, png, bmp, etc.)."); -DEFINE_bool(flir_camera, false, "Whether to use FLIR (Point-Grey) stereo camera."); -DEFINE_int32(flir_camera_index, -1, "Select -1 (default) to run on all detected flir cameras at once. Otherwise, select the flir" - " camera index to run, where 0 corresponds to the detected flir camera with the lowest" - " serial number, and `n` to the `n`-th lowest serial number camera."); -DEFINE_string(ip_camera, "", "String with the IP camera URL. It supports protocols like RTSP and HTTP."); -DEFINE_bool(process_real_time, false, "Enable to keep the original source frame rate (e.g., for video). If the processing time is" - " too long, it will skip frames. If it is too fast, it will slow it down."); -DEFINE_string(camera_parameter_path, "models/cameraParameters/flir/", "String with the folder where the camera parameters are located. If there" - " is only 1 XML file (for single video, webcam, or images from the same camera), you must" - " specify the whole XML file path (ending in .xml)."); -DEFINE_bool(frame_undistort, false, "If false (default), it will not undistort the image, if true, it will undistortionate them" - " based on the camera parameters found in `camera_parameter_path`"); -// OpenPose -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(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_parameter_path` must be set. OpenPose must find as many `xml` files in the" - " parameter folder as this number indicates."); -// Consumer -DEFINE_bool(fullscreen, false, "Run in full-screen mode (press f during runtime to toggle)."); +#include // This class can be implemented either as a template or as a simple class given // that the user usually knows which kind of data he will move between the queues, @@ -94,12 +46,12 @@ public: } }; -int tutorialDeveloperThread2() +int openPoseTutorialThread1() { try { op::log("Starting OpenPose demo...", op::Priority::High); - const auto timerBegin = std::chrono::high_resolution_clock::now(); + const auto opTimer = op::getTimerInit(); // ------------------------- INITIALIZATION ------------------------- // Step 1 - Set logging level @@ -133,13 +85,12 @@ int tutorialDeveloperThread2() (int)producerSharedPtr->get(CV_CAP_PROP_FRAME_WIDTH), (int)producerSharedPtr->get(CV_CAP_PROP_FRAME_HEIGHT)}; // Step 4 - Setting thread workers && manager - typedef op::Datum TypedefDatum; - typedef std::shared_ptr>> TypedefDatumsSP; + typedef std::shared_ptr>> TypedefDatumsSP; op::ThreadManager threadManager; // Step 5 - Initializing the worker classes // Frames producer (e.g., video, webcam, ...) - auto DatumProducer = std::make_shared>(producerSharedPtr); - auto wDatumProducer = std::make_shared>(DatumProducer); + auto DatumProducer = std::make_shared>(producerSharedPtr); + auto wDatumProducer = std::make_shared>(DatumProducer); // Specific WUserClass auto wUserClass = std::make_shared(); // GUI (Display) @@ -197,15 +148,10 @@ int tutorialDeveloperThread2() // op::log("Stopping thread(s)", op::Priority::High); // threadManager.stop(); - // ------------------------- CLOSING ------------------------- // Measuring total time - const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; - const auto message = "OpenPose demo successfully finished. Total time: " - + std::to_string(totalTimeSec) + " seconds."; - op::log(message, op::Priority::High); - // Return successful message + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); + + // Return return 0; } catch (const std::exception& e) @@ -220,6 +166,6 @@ int main(int argc, char *argv[]) // Parsing command line flags gflags::ParseCommandLineFlags(&argc, &argv, true); - // Running tutorialDeveloperThread2 - return tutorialDeveloperThread2(); + // Running openPoseTutorialThread1 + return openPoseTutorialThread1(); } diff --git a/examples/tutorial_developer/thread_4_user_input_processing_output_and_datum.cpp b/examples/tutorial_api_thread/2_thread_user_input_processing_output_and_datum.cpp similarity index 90% rename from examples/tutorial_developer/thread_4_user_input_processing_output_and_datum.cpp rename to examples/tutorial_api_thread/2_thread_user_input_processing_output_and_datum.cpp index cbf1feb5..c1ade142 100644 --- a/examples/tutorial_developer/thread_4_user_input_processing_output_and_datum.cpp +++ b/examples/tutorial_api_thread/2_thread_user_input_processing_output_and_datum.cpp @@ -1,4 +1,4 @@ -// ------------------------- OpenPose Library Tutorial - Thread - Example 4 - User Input Processing And Output ------------------------- +// ------------------------- OpenPose Library Tutorial - Thread - Example 2 - User Input Processing And Output ------------------------- // This fourth example shows the user how to: // 1. Read folder of images / video / webcam (`producer` module) // 2. Use the processing implemented by the user @@ -16,16 +16,7 @@ namespace gflags = google; #endif // OpenPose dependencies -// Option a) Importing all modules #include -// Option b) Manually importing the desired modules. Recommended if you only intend to use a few modules. -// #include -// #include -// #include -// #include -// #include -// #include -// #include // See all the available parameter options withe the `--help` flag. E.g., `build/examples/openpose/openpose.bin --help` // Note: This command will show you flags for other unnecessary 3rdparty files. Check only the flags for the OpenPose @@ -39,7 +30,6 @@ DEFINE_string(image_dir, "examples/media/", "Process a direc // Consumer DEFINE_bool(fullscreen, false, "Run in full-screen mode (press f during runtime to toggle)."); - // If the user needs his own variables, he can inherit the op::Datum struct and add them in there. // UserDatum can be directly used by the OpenPose wrapper because it inherits from op::Datum, just define // WrapperT>> instead of Wrapper @@ -183,12 +173,12 @@ public: } }; -int openPoseTutorialThread4() +int openPoseTutorialThread2() { try { op::log("Starting OpenPose demo...", op::Priority::High); - const auto timerBegin = std::chrono::high_resolution_clock::now(); + const auto opTimer = op::getTimerInit(); // ------------------------- INITIALIZATION ------------------------- // Step 1 - Set logging level @@ -242,15 +232,10 @@ int openPoseTutorialThread4() // op::log("Stopping thread(s)", op::Priority::High); // threadManager.stop(); - // ------------------------- CLOSING ------------------------- // Measuring total time - const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; - const auto message = "OpenPose demo successfully finished. Total time: " - + std::to_string(totalTimeSec) + " seconds."; - op::log(message, op::Priority::High); - // Return successful message + op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High); + + // Return return 0; } catch (const std::exception& e) @@ -265,6 +250,6 @@ int main(int argc, char *argv[]) // Parsing command line flags gflags::ParseCommandLineFlags(&argc, &argv, true); - // Running openPoseTutorialThread4 - return openPoseTutorialThread4(); + // Running openPoseTutorialThread2 + return openPoseTutorialThread2(); } diff --git a/examples/tutorial_developer/CMakeLists.txt b/examples/tutorial_api_thread/CMakeLists.txt similarity index 77% rename from examples/tutorial_developer/CMakeLists.txt rename to examples/tutorial_api_thread/CMakeLists.txt index 7ef02229..6addce9d 100644 --- a/examples/tutorial_developer/CMakeLists.txt +++ b/examples/tutorial_api_thread/CMakeLists.txt @@ -1,10 +1,6 @@ set(EXAMPLE_FILES - pose_1_extract_from_image.cpp - pose_2_extract_pose_or_heatmat_from_image.cpp - thread_1_openpose_read_and_display.cpp - thread_2_user_processing_function.cpp - thread_3_user_input_processing_and_output.cpp - thread_4_user_input_processing_output_and_datum.cpp) + 1_thread_user_processing_function.cpp + 2_thread_user_input_processing_output_and_datum.cpp) foreach(EXAMPLE_FILE ${EXAMPLE_FILES}) @@ -21,7 +17,7 @@ foreach(EXAMPLE_FILE ${EXAMPLE_FILES}) target_link_libraries(${EXE_NAME} openpose ${examples_3rdparty_libraries}) if (WIN32) - set_property(TARGET ${EXE_NAME} PROPERTY FOLDER "Examples/Tutorial/Developer Examples") + set_property(TARGET ${EXE_NAME} PROPERTY FOLDER "Examples/Tutorial/Thread API") configure_file(${CMAKE_SOURCE_DIR}/cmake/OpenPose${VCXPROJ_FILE_GPU_MODE}.vcxproj.user ${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj.user @ONLY) # Properties->General->Output Directory diff --git a/examples/tutorial_api_thread/README.md b/examples/tutorial_api_thread/README.md new file mode 100644 index 00000000..0c00b062 --- /dev/null +++ b/examples/tutorial_api_thread/README.md @@ -0,0 +1,4 @@ +# Thread API Examples +**NOTE**: This is an advanced API, you are most probably looking for the [examples/tutorial_api_python/](../tutorial_api_python/) examples folder, which provides examples of the thread API but applied to body pose estimation. + +This folder provides examples to the basic OpenPose thread mechanism API. It is only meant for people interesed in the multi-thread architecture without been interesed in the OpenPose pose estimation algorithm. diff --git a/examples/tutorial_developer/README.md b/examples/tutorial_developer/README.md deleted file mode 100644 index 4d6dab25..00000000 --- a/examples/tutorial_developer/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Developer Examples -**Disclaimer**: This folder is meant for internal OpenPose developers. The Examples might highly change, and we will not answer questions about them nor provide official support for them. - -**If the OpenPose library does not compile for an error happening due to a file from this folder, notify us**. diff --git a/examples/tutorial_developer/pose_1_extract_from_image.cpp b/examples/tutorial_developer/pose_1_extract_from_image.cpp deleted file mode 100644 index 25261c0e..00000000 --- a/examples/tutorial_developer/pose_1_extract_from_image.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// ------------------------- 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 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 -// Allow Google Flags in Ubuntu 14 -#ifndef GFLAGS_GFLAGS_H_ - namespace gflags = google; -#endif -// OpenPose dependencies -#include -#include -#include -#include -#include - -// See all the available parameter options withe the `--help` flag. E.g., `build/examples/openpose/openpose.bin --help` -// Note: This command 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, "examples/media/COCO_val2014_000000000192.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."); -DEFINE_double(scale_gap, 0.25, "Scale gap between scales. No effect unless scale_number > 1. Initial scale is always 1." - " If you want to change the initial scale, you actually want to multiply the" - " `net_resolution` by your desired initial scale."); -DEFINE_int32(scale_number, 1, "Number of scales to average."); -// OpenPose Rendering -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 tutorialDeveloperPose1() -{ - try - { - op::log("Starting OpenPose demo...", op::Priority::High); - const auto timerBegin = std::chrono::high_resolution_clock::now(); - - // ------------------------- INITIALIZATION ------------------------- - // Step 1 - Set logging level - // - 0 will output all the logging messages - // - 255 will output nothing - 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__); - // Step 2 - Read GFlags (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__); - if (FLAGS_scale_gap <= 0. && FLAGS_scale_number > 1) - op::error("Incompatible flag configuration: scale_gap must be greater than 0 or scale_number = 1.", - __LINE__, __FUNCTION__, __FILE__); - // Step 3 - Initialize all required classes - op::ScaleAndSizeExtractor scaleAndSizeExtractor(netInputSize, outputSize, FLAGS_scale_number, FLAGS_scale_gap); - 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{"OpenPose Tutorial - Example 1", outputSize}; - // Step 4 - Initialize resources on desired thread (in this case single thread, i.e., we init resources here) - 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 imageSize{inputImage.cols, inputImage.rows}; - // Step 2 - Get desired scale sizes - std::vector scaleInputToNetInputs; - std::vector> netInputSizes; - double scaleInputToOutput; - op::Point 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); - // Step 4 - Estimate poseKeypoints - poseExtractorCaffe.forwardPass(netInputArray, imageSize, scaleInputToNetInputs); - const auto poseKeypoints = poseExtractorCaffe.getPoseKeypoints(); - // Step 5 - Render poseKeypoints - poseRenderer.renderPose(outputArray, poseKeypoints, scaleInputToOutput); - // Step 6 - OpenPose output format to cv::Mat - auto outputImage = opOutputToCvMat.formatToCvMat(outputArray); - - // ------------------------- SHOWING RESULT AND CLOSING ------------------------- - // Show results - frameDisplayer.displayFrame(outputImage, 0); // Alternative: cv::imshow(outputImage) + cv::waitKey(0) - // Measuring total time - const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; - const auto message = "OpenPose demo successfully finished. Total time: " - + std::to_string(totalTimeSec) + " seconds."; - op::log(message, op::Priority::High); - // Return successful message - 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 tutorialDeveloperPose1 - return tutorialDeveloperPose1(); -} diff --git a/examples/tutorial_developer/pose_2_extract_pose_or_heatmat_from_image.cpp b/examples/tutorial_developer/pose_2_extract_pose_or_heatmat_from_image.cpp deleted file mode 100644 index 7540c86d..00000000 --- a/examples/tutorial_developer/pose_2_extract_pose_or_heatmat_from_image.cpp +++ /dev/null @@ -1,163 +0,0 @@ -// ------------------------- OpenPose Library Tutorial - Pose - Example 2 - Extract Pose or Heatmap from Image ------------------------- -// This second 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 or heatmap on a resized copy of the input image (`pose` module) - // 4. Display the rendered pose or heatmap (`gui` module) -// In addition to the previous OpenPose modules, we also need to use: - // 1. `core` module: for the Array 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 -// Allow Google Flags in Ubuntu 14 -#ifndef GFLAGS_GFLAGS_H_ - namespace gflags = google; -#endif -// OpenPose dependencies -#include -#include -#include -#include -#include - -// See all the available parameter options withe the `--help` flag. E.g., `build/examples/openpose/openpose.bin --help` -// Note: This command 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, "examples/media/COCO_val2014_000000000192.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."); -DEFINE_double(scale_gap, 0.25, "Scale gap between scales. No effect unless scale_number > 1. Initial scale is always 1." - " If you want to change the initial scale, you actually want to multiply the" - " `net_resolution` by your desired initial scale."); -DEFINE_int32(scale_number, 1, "Number of scales to average."); -// OpenPose Rendering -DEFINE_int32(part_to_show, 19, "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_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."); -DEFINE_double(alpha_heatmap, 0.7, "Blending factor (range 0-1) between heatmap and original frame. 1 will only show the" - " heatmap, 0 will only show the frame. Only valid for GPU rendering."); - -int tutorialDeveloperPose2() -{ - try - { - op::log("Starting OpenPose demo...", op::Priority::High); - const auto timerBegin = std::chrono::high_resolution_clock::now(); - - // ------------------------- INITIALIZATION ------------------------- - // Step 1 - Set logging level - // - 0 will output all the logging messages - // - 255 will output nothing - 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__); - // Step 2 - Read GFlags (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__); - if (FLAGS_scale_gap <= 0. && FLAGS_scale_number > 1) - op::error("Incompatible flag configuration: scale_gap must be greater than 0 or scale_number = 1.", - __LINE__, __FUNCTION__, __FILE__); - // Step 3 - Initialize all required classes - op::ScaleAndSizeExtractor scaleAndSizeExtractor(netInputSize, outputSize, FLAGS_scale_number, FLAGS_scale_gap); - op::CvMatToOpInput cvMatToOpInput{poseModel}; - op::CvMatToOpOutput cvMatToOpOutput; - auto poseExtractorPtr = std::make_shared(poseModel, FLAGS_model_folder, - FLAGS_num_gpu_start); - op::PoseGpuRenderer poseGpuRenderer{poseModel, poseExtractorPtr, (float)FLAGS_render_threshold, - !FLAGS_disable_blending, (float)FLAGS_alpha_pose, (float)FLAGS_alpha_heatmap}; - poseGpuRenderer.setElementToRender(FLAGS_part_to_show); - op::OpOutputToCvMat opOutputToCvMat; - op::FrameDisplayer frameDisplayer{"OpenPose Tutorial - Example 2", outputSize}; - // Step 4 - Initialize resources on desired thread (in this case single thread, i.e., we init resources here) - poseExtractorPtr->initializationOnThread(); - poseGpuRenderer.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 imageSize{inputImage.cols, inputImage.rows}; - // Step 2 - Get desired scale sizes - std::vector scaleInputToNetInputs; - std::vector> netInputSizes; - double scaleInputToOutput; - op::Point 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); - // Step 4 - Estimate poseKeypoints - poseExtractorPtr->forwardPass(netInputArray, imageSize, scaleInputToNetInputs); - const auto poseKeypoints = poseExtractorPtr->getPoseKeypoints(); - const auto scaleNetToOutput = poseExtractorPtr->getScaleNetToOutput(); - // Step 5 - Render pose - poseGpuRenderer.renderPose(outputArray, poseKeypoints, scaleInputToOutput, scaleNetToOutput); - // Step 6 - OpenPose output format to cv::Mat - auto outputImage = opOutputToCvMat.formatToCvMat(outputArray); - - // ------------------------- SHOWING RESULT AND CLOSING ------------------------- - // Show results - frameDisplayer.displayFrame(outputImage, 0); // Alternative: cv::imshow(outputImage) + cv::waitKey(0) - // Measuring total time - const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; - const auto message = "OpenPose demo successfully finished. Total time: " - + std::to_string(totalTimeSec) + " seconds."; - op::log(message, op::Priority::High); - // Return successful message - 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 tutorialDeveloperPose2 - return tutorialDeveloperPose2(); -} diff --git a/examples/tutorial_developer/thread_1_openpose_read_and_display.cpp b/examples/tutorial_developer/thread_1_openpose_read_and_display.cpp deleted file mode 100644 index 217a49b1..00000000 --- a/examples/tutorial_developer/thread_1_openpose_read_and_display.cpp +++ /dev/null @@ -1,184 +0,0 @@ -// ------------------------- OpenPose Library Tutorial - Thread - Example 1 - OpenPose Read And Display ------------------------- -// This third example shows the user how to: - // 1. Read folder of images / video / webcam (`producer` module) - // 2. Display the rendered pose (`gui` module) - // Everything in a multi-thread scenario (`thread` module) -// In addition to the previous OpenPose modules, we also need to use: - // 1. `core` module: for the Datum struct that the `thread` module sends between the queues - // 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 -// Allow Google Flags in Ubuntu 14 -#ifndef GFLAGS_GFLAGS_H_ - namespace gflags = google; -#endif -// OpenPose dependencies -#include -#include -#include -#include -#include - -// See all the available parameter options withe the `--help` flag. E.g., `build/examples/openpose/openpose.bin --help` -// Note: This command 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_int32(camera, -1, "The camera index for cv::VideoCapture. Integer in the range [0, 9]. Select a negative" - " number (by default), to auto-detect and open the first available camera."); -DEFINE_string(camera_resolution, "-1x-1", "Set the camera resolution (either `--camera` or `--flir_camera`). `-1x-1` will use the" - " default 1280x720 for `--camera`, or the maximum flir camera resolution available for" - " `--flir_camera`"); -DEFINE_string(video, "", "Use a video file instead of the camera. Use `examples/media/video.avi` for our default" - " example video."); -DEFINE_string(image_dir, "", "Process a directory of images. Use `examples/media/` for our default example folder with 20" - " images. Read all standard formats (jpg, png, bmp, etc.)."); -DEFINE_bool(flir_camera, false, "Whether to use FLIR (Point-Grey) stereo camera."); -DEFINE_int32(flir_camera_index, -1, "Select -1 (default) to run on all detected flir cameras at once. Otherwise, select the flir" - " camera index to run, where 0 corresponds to the detected flir camera with the lowest" - " serial number, and `n` to the `n`-th lowest serial number camera."); -DEFINE_string(ip_camera, "", "String with the IP camera URL. It supports protocols like RTSP and HTTP."); -DEFINE_bool(process_real_time, false, "Enable to keep the original source frame rate (e.g., for video). If the processing time is" - " too long, it will skip frames. If it is too fast, it will slow it down."); -DEFINE_string(camera_parameter_path, "models/cameraParameters/flir/", "String with the folder where the camera parameters are located. If there" - " is only 1 XML file (for single video, webcam, or images from the same camera), you must" - " specify the whole XML file path (ending in .xml)."); -DEFINE_bool(frame_undistort, false, "If false (default), it will not undistort the image, if true, it will undistortionate them" - " based on the camera parameters found in `camera_parameter_path`"); -// OpenPose -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(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_parameter_path` must be set. OpenPose must find as many `xml` files in the" - " parameter folder as this number indicates."); -// Consumer -DEFINE_bool(fullscreen, false, "Run in full-screen mode (press f during runtime to toggle)."); - -int tutorialDeveloperThread1() -{ - try - { - op::log("Starting OpenPose demo...", op::Priority::High); - const auto timerBegin = std::chrono::high_resolution_clock::now(); - - // ------------------------- INITIALIZATION ------------------------- - // Step 1 - Set logging level - // - 0 will output all the logging messages - // - 255 will output nothing - 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); - // Step 2 - Read GFlags (user defined configuration) - // cameraSize - const auto cameraSize = op::flagsToPoint(FLAGS_camera_resolution, "-1x-1"); - // outputSize - const auto outputSize = op::flagsToPoint(FLAGS_output_resolution, "-1x-1"); - // producerType - op::ProducerType producerType; - std::string producerString; - std::tie(producerType, producerString) = op::flagsToProducer( - FLAGS_image_dir, FLAGS_video, FLAGS_ip_camera, FLAGS_camera, FLAGS_flir_camera, FLAGS_flir_camera_index); - const auto displayProducerFpsMode = (FLAGS_process_real_time - ? op::ProducerFpsMode::OriginalFps : op::ProducerFpsMode::RetrievalFps); - auto producerSharedPtr = createProducer( - producerType, producerString, cameraSize, FLAGS_camera_parameter_path, FLAGS_frame_undistort, - FLAGS_3d_views); - producerSharedPtr->setProducerFpsMode(displayProducerFpsMode); - op::log("", op::Priority::Low, __LINE__, __FUNCTION__, __FILE__); - // Step 3 - Setting producer - auto videoSeekSharedPtr = std::make_shared, std::atomic>>(); - videoSeekSharedPtr->first = false; - videoSeekSharedPtr->second = 0; - const op::Point producerSize{ - (int)producerSharedPtr->get(CV_CAP_PROP_FRAME_WIDTH), - (int)producerSharedPtr->get(CV_CAP_PROP_FRAME_HEIGHT)}; - // Step 4 - Setting thread workers && manager - typedef op::Datum TypedefDatum; - typedef std::shared_ptr>> TypedefDatumsSP; - op::ThreadManager threadManager; - // Step 5 - Initializing the worker classes - // Frames producer (e.g., video, webcam, ...) - auto DatumProducer = std::make_shared>(producerSharedPtr); - auto wDatumProducer = std::make_shared>(DatumProducer); - // GUI (Display) - auto gui = std::make_shared(outputSize, FLAGS_fullscreen, threadManager.getIsRunningSharedPtr()); - auto wGui = std::make_shared>(gui); - - // ------------------------- CONFIGURING THREADING ------------------------- - // In this simple multi-thread example, we will do the following: - // 3 (virtual) queues: 0, 1, 2 - // 1 real queue: 1. The first and last queue ids (in this case 0 and 2) are not actual queues, but the - // beginning and end of the processing sequence - // 2 threads: 0, 1 - // wDatumProducer will generate frames (there is no real queue 0) and push them on queue 1 - // wGui will pop frames from queue 1 and process them (there is no real queue 2) - auto threadId = 0ull; - auto queueIn = 0ull; - auto queueOut = 1ull; - threadManager.add(threadId++, wDatumProducer, queueIn++, queueOut++); // Thread 0, queues 0 -> 1 - threadManager.add(threadId++, wGui, queueIn++, queueOut++); // Thread 1, queues 1 -> 2 - - // Equivalent single-thread version (option a) - // const auto threadId = 0ull; - // auto queueIn = 0ull; - // auto queueOut = 1ull; - // threadManager.add(threadId, wDatumProducer, queueIn++, queueOut++); // Thread 0, queues 0 -> 1 - // threadManager.add(threadId, wGui, queueIn++, queueOut++); // Thread 0, queues 1 -> 2 - - // Equivalent single-thread version (option b) - // const auto threadId = 0ull; - // const auto queueIn = 0ull; - // const auto queueOut = 1ull; - // threadManager.add(threadId, {wDatumProducer, wGui}, queueIn, queueOut); // Thread 0, queues 0 -> 1 - - // ------------------------- STARTING AND STOPPING THREADING ------------------------- - op::log("Starting thread(s)...", op::Priority::High); - // Two different ways of running the program on multithread environment - // Option a) Using the main thread (this thread) for processing (it saves 1 thread, recommended) - threadManager.exec(); - // Option b) Giving to the user the control of this thread - // // VERY IMPORTANT NOTE: if OpenCV is compiled with Qt support, this option will not work. Qt needs the main - // // thread to plot visual results, so the final GUI (which uses OpenCV) would return an exception similar to: - // // `QMetaMethod::invoke: Unable to invoke methods with return values in queued connections` - // // Start threads - // threadManager.start(); - // // Keep program alive while running threads. Here the user could perform any other desired function - // while (threadManager.isRunning()) - // std::this_thread::sleep_for(std::chrono::milliseconds{33}); - // // Stop and join threads - // op::log("Stopping thread(s)", op::Priority::High); - // threadManager.stop(); - - // ------------------------- CLOSING ------------------------- - // Measuring total time - const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; - const auto message = "OpenPose demo successfully finished. Total time: " - + std::to_string(totalTimeSec) + " seconds."; - op::log(message, op::Priority::High); - - // Return successful message - 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 tutorialDeveloperThread1 - return tutorialDeveloperThread1(); -} diff --git a/examples/tutorial_developer/thread_3_user_input_processing_and_output.cpp b/examples/tutorial_developer/thread_3_user_input_processing_and_output.cpp deleted file mode 100644 index 2560beee..00000000 --- a/examples/tutorial_developer/thread_3_user_input_processing_and_output.cpp +++ /dev/null @@ -1,256 +0,0 @@ -// ------------------------- OpenPose Library Tutorial - Thread - Example 3 - User Input Processing And Output ------------------------- -// This fourth example shows the user how to: - // 1. Read folder of images / video / webcam (`producer` module) - // 2. Use the processing implemented by the user - // 3. Display the rendered pose (`gui` module) - // Everything in a multi-thread scenario (`thread` module) -// In addition to the previous OpenPose modules, we also need to use: - // 1. `core` module: for the Datum struct that the `thread` module sends between the queues - // 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 -// Allow Google Flags in Ubuntu 14 -#ifndef GFLAGS_GFLAGS_H_ - namespace gflags = google; -#endif -// OpenPose dependencies -// Option a) Importing all modules -#include -// Option b) Manually importing the desired modules. Recommended if you only intend to use a few modules. -// #include -// #include -// #include -// #include -// #include -// #include -// #include - -// See all the available parameter options withe the `--help` flag. E.g., `build/examples/openpose/openpose.bin --help` -// Note: This command 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_dir, "examples/media/", "Process a directory of images. Read all standard formats (jpg, png, bmp, etc.)."); -// Consumer -DEFINE_bool(fullscreen, false, "Run in full-screen mode (press f during runtime to toggle)."); - -// The W-classes can be implemented either as a template or as simple classes given -// that the user usually knows which kind of data he will move between the queues, -// in this case we assume a std::shared_ptr of a std::vector of op::Datum - -// This worker will just read and return all the basic image file formats in a directory -class WUserInput : public op::WorkerProducer>>> -{ -public: - WUserInput(const std::string& directoryPath) : - mImageFiles{op::getFilesOnDirectory(directoryPath, op::Extensions::Images)}, // For all basic image formats - // If we want only e.g., "jpg" + "png" images - // mImageFiles{op::getFilesOnDirectory(directoryPath, std::vector{"jpg", "png"})}, - mCounter{0} - { - if (mImageFiles.empty()) - op::error("No images found on: " + directoryPath, __LINE__, __FUNCTION__, __FILE__); - } - - void initializationOnThread() {} - - std::shared_ptr>> workProducer() - { - try - { - // Close program when empty frame - if (mImageFiles.size() <= mCounter) - { - op::log("Last frame read and added to queue. Closing program after it is processed.", - op::Priority::High); - // This funtion stops this worker, which will eventually stop the whole thread system once all the - // frames have been processed - this->stop(); - return nullptr; - } - else - { - // Create new datum - auto datumsPtr = std::make_shared>>(); - datumsPtr->emplace_back(); - auto& datumPtr = datumsPtr->at(0); - - // Fill datum - datumPtr->cvInputData = cv::imread(mImageFiles.at(mCounter++)); - - // If empty frame -> return nullptr - if (datumPtr->cvInputData.empty()) - { - op::log("Empty frame detected on path: " + mImageFiles.at(mCounter-1) + ". Closing program.", - op::Priority::High); - this->stop(); - datumsPtr = nullptr; - } - - return datumsPtr; - } - } - catch (const std::exception& e) - { - op::log("Some kind of unexpected error happened."); - this->stop(); - op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); - return nullptr; - } - } - -private: - const std::vector mImageFiles; - unsigned long long mCounter; -}; - -// This worker will just invert the image -class WUserPostProcessing : public op::Worker>>> -{ -public: - WUserPostProcessing() - { - // User's constructor here - } - - void initializationOnThread() {} - - void work(std::shared_ptr>>& datumsPtr) - { - // User's post-processing (after OpenPose processing & before OpenPose outputs) here - // datumPtr->cvOutputData: rendered frame with pose or heatmaps - // datumPtr->poseKeypoints: Array with the estimated pose - try - { - if (datumsPtr != nullptr && !datumsPtr->empty()) - for (auto& datumPtr : *datumsPtr) - cv::bitwise_not(datumPtr->cvInputData, datumPtr->cvOutputData); - } - catch (const std::exception& e) - { - op::log("Some kind of unexpected error happened."); - this->stop(); - op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); - } - } -}; - -// This worker will just read and return all the jpg files in a directory -class WUserOutput : public op::WorkerConsumer>>> -{ -public: - void initializationOnThread() {} - - void workConsumer(const std::shared_ptr>>& datumsPtr) - { - try - { - // User's displaying/saving/other processing here - // datumPtr->cvOutputData: rendered frame with pose or heatmaps - // datumPtr->poseKeypoints: Array with the estimated pose - if (datumsPtr != nullptr && !datumsPtr->empty()) - { - cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); - // It displays the image and sleeps at least 1 ms (it usually sleeps ~5-10 msec to display the image) - cv::waitKey(1); - } - } - catch (const std::exception& e) - { - op::log("Some kind of unexpected error happened."); - this->stop(); - op::error(e.what(), __LINE__, __FUNCTION__, __FILE__); - } - } -}; - -int openPoseTutorialThread3() -{ - try - { - op::log("Starting OpenPose demo...", op::Priority::High); - const auto timerBegin = std::chrono::high_resolution_clock::now(); - - // ------------------------- INITIALIZATION ------------------------- - // Step 1 - Set logging level - // - 0 will output all the logging messages - // - 255 will output nothing - 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); - // Step 2 - Setting thread workers && manager - typedef std::shared_ptr>> TypedefDatumsSP; - typedef std::shared_ptr> TypedefWorker; - op::ThreadManager threadManager; - // Step 3 - Initializing the worker classes - // Frames producer (e.g., video, webcam, ...) - TypedefWorker wUserInput = std::make_shared(FLAGS_image_dir); - // Processing - TypedefWorker wUserProcessing = std::make_shared(); - // GUI (Display) - TypedefWorker wUserOutput = std::make_shared(); - - // ------------------------- CONFIGURING THREADING ------------------------- - // In this simple multi-thread example, we will do the following: - // 3 (virtual) queues: 0, 1, 2 - // 1 real queue: 1. The first and last queue ids (in this case 0 and 2) are not actual queues, but the - // beginning and end of the processing sequence - // 2 threads: 0, 1 - // wUserInput will generate frames (there is no real queue 0) and push them on queue 1 - // wGui will pop frames from queue 1 and process them (there is no real queue 2) - auto threadId = 0ull; - auto queueIn = 0ull; - auto queueOut = 1ull; - threadManager.add(threadId++, wUserInput, queueIn++, queueOut++); // Thread 0, queues 0 -> 1 - threadManager.add(threadId++, wUserProcessing, queueIn++, queueOut++); // Thread 1, queues 1 -> 2 - threadManager.add(threadId++, wUserOutput, queueIn++, queueOut++); // Thread 2, queues 2 -> 3 - - // ------------------------- STARTING AND STOPPING THREADING ------------------------- - op::log("Starting thread(s)...", op::Priority::High); - // Two different ways of running the program on multithread environment - // Option a) Using the main thread (this thread) for processing (it saves 1 thread, recommended) - threadManager.exec(); - // Option b) Giving to the user the control of this thread - // // VERY IMPORTANT NOTE: if OpenCV is compiled with Qt support, this option will not work. Qt needs the main - // // thread to plot visual results, so the final GUI (which uses OpenCV) would return an exception similar to: - // // `QMetaMethod::invoke: Unable to invoke methods with return values in queued connections` - // // Start threads - // threadManager.start(); - // // Keep program alive while running threads. Here the user could perform any other desired function - // while (threadManager.isRunning()) - // std::this_thread::sleep_for(std::chrono::milliseconds{33}); - // // Stop and join threads - // op::log("Stopping thread(s)", op::Priority::High); - // threadManager.stop(); - - // ------------------------- CLOSING ------------------------- - // Measuring total time - const auto now = std::chrono::high_resolution_clock::now(); - const auto totalTimeSec = (double)std::chrono::duration_cast(now-timerBegin).count() - * 1e-9; - const auto message = "OpenPose demo successfully finished. Total time: " - + std::to_string(totalTimeSec) + " seconds."; - op::log(message, op::Priority::High); - // Return successful message - 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 openPoseTutorialThread3 - return openPoseTutorialThread3(); -} diff --git a/include/openpose/flags.hpp b/include/openpose/flags.hpp index b16c80b3..53b9f7bd 100644 --- a/include/openpose/flags.hpp +++ b/include/openpose/flags.hpp @@ -128,6 +128,13 @@ DEFINE_bool(face, false, "Enables face keypoint d " `model_folder`. Note that this will considerable slow down the performance and increse" " the required GPU memory. In addition, the greater number of people on the image, the" " slower OpenPose will be."); +DEFINE_int32(face_detector, 0, "Kind of face rectangle detector. Select 0 (default) to select OpenPose body detector (most" + " accurate one and fastest one if body is enabled), 1 to select OpenCV face detector (not" + " implemented for hands), 2 to indicate that it will be provided by the user, or 3 to" + " also apply hand tracking (only for hand). Hand tracking might improve hand keypoint" + " 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_string(face_net_resolution, "368x368", "Multiples of 16 and squared. Analogous to `net_resolution` but applied to the face keypoint" " detector. 320x320 usually works fine while giving a substantial speed up when multiple" " faces on the image."); @@ -135,6 +142,7 @@ DEFINE_string(face_net_resolution, "368x368", "Multiples of 16 and squ DEFINE_bool(hand, false, "Enables hand keypoint detection. It will share some parameters from the body pose, e.g." " `model_folder`. Analogously to `--face`, it will also slow down the performance, increase" " the required GPU memory and its speed depends on the number of people."); +DEFINE_int32(hand_detector, 0, "Kind of hand rectangle detector. Analogous to `--face_detector`."); DEFINE_string(hand_net_resolution, "368x368", "Multiples of 16 and squared. Analogous to `net_resolution` but applied to the hand keypoint" " detector."); DEFINE_int32(hand_scale_number, 1, "Analogous to `scale_number` but applied to the hand keypoint detector. Our best results" @@ -142,10 +150,6 @@ DEFINE_int32(hand_scale_number, 1, "Analogous to `scale_num DEFINE_double(hand_scale_range, 0.4, "Analogous purpose than `scale_gap` but applied to the hand keypoint detector. Total range" " between smallest and biggest scale. The scales will be centered in ratio 1. E.g., if" " scaleRange = 0.4 and scalesNumber = 2, then there will be 2 scales, 0.8 and 1.2."); -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."); // 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" diff --git a/include/openpose/utilities/flagsToOpenPose.hpp b/include/openpose/utilities/flagsToOpenPose.hpp index 8daf039b..16309555 100644 --- a/include/openpose/utilities/flagsToOpenPose.hpp +++ b/include/openpose/utilities/flagsToOpenPose.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace op { @@ -15,6 +16,8 @@ namespace op OP_API ScaleMode flagsToHeatMapScaleMode(const int heatMapScaleMode); + OP_API Detector flagsToDetector(const int detector); + // Determine type of frame source OP_API ProducerType flagsToProducerType(const std::string& imageDirectory, const std::string& videoPath, const std::string& ipCameraPath, const int webcamIndex, diff --git a/include/openpose/utilities/profiler.hpp b/include/openpose/utilities/profiler.hpp index 276bdc8e..c0e1cc2c 100644 --- a/include/openpose/utilities/profiler.hpp +++ b/include/openpose/utilities/profiler.hpp @@ -1,23 +1,31 @@ #ifndef OPENPOSE_UTILITIES_PROFILER_HPP #define OPENPOSE_UTILITIES_PROFILER_HPP +#include #include #include - -// Enable PROFILER_ENABLED on Makefile.config in order to use this function. Otherwise nothing will be outputted. - -// How to use - example: -// For GPU - It can only be applied in the main.cpp file: - // Profiler::profileGpuMemory(__LINE__, __FUNCTION__, __FILE__); -// For time: - // // ... inside continuous loop ... - // const auto profilerKey = Profiler::timerInit(__LINE__, __FUNCTION__, __FILE__); - // // functions to do... - // Profiler::timerEnd(profilerKey); - // Profiler::printAveragedTimeMsOnIterationX(profilerKey, __LINE__, __FUNCTION__, __FILE__, NUMBER_ITERATIONS); +#include namespace op { + OP_API std::chrono::time_point getTimerInit(); + + OP_API double getTimeSeconds(const std::chrono::time_point& timerInit); + + OP_API void printTime( + const std::chrono::time_point& timerInit, const std::string& firstMessage, + const std::string& secondMessage, const Priority priority); + + // Enable PROFILER_ENABLED on Makefile.config or CMake in order to use this function. Otherwise nothing will be outputted. + // How to use - example: + // For GPU - It can only be applied in the main.cpp file: + // Profiler::profileGpuMemory(__LINE__, __FUNCTION__, __FILE__); + // For time: + // // ... inside continuous loop ... + // const auto profilerKey = Profiler::timerInit(__LINE__, __FUNCTION__, __FILE__); + // // functions to do... + // Profiler::timerEnd(profilerKey); + // Profiler::printAveragedTimeMsOnIterationX(profilerKey, __LINE__, __FUNCTION__, __FILE__, NUMBER_ITERATIONS); class OP_API Profiler { public: @@ -30,13 +38,13 @@ namespace op static void timerEnd(const std::string& key); - static void printAveragedTimeMsOnIterationX(const std::string& key, const int line, - const std::string& function, const std::string& file, - const unsigned long long x = DEFAULT_X); + static void printAveragedTimeMsOnIterationX( + const std::string& key, const int line, const std::string& function, const std::string& file, + const unsigned long long x = DEFAULT_X); - static void printAveragedTimeMsEveryXIterations(const std::string& key, const int line, - const std::string& function, const std::string& file, - const unsigned long long x = DEFAULT_X); + static void printAveragedTimeMsEveryXIterations( + const std::string& key, const int line, const std::string& function, const std::string& file, + const unsigned long long x = DEFAULT_X); static void profileGpuMemory(const int line, const std::string& function, const std::string& file); }; diff --git a/include/openpose/wrapper/enumClasses.hpp b/include/openpose/wrapper/enumClasses.hpp index b8d739c0..502f960c 100644 --- a/include/openpose/wrapper/enumClasses.hpp +++ b/include/openpose/wrapper/enumClasses.hpp @@ -3,6 +3,15 @@ namespace op { + enum class Detector : unsigned char + { + Body = 0, + OpenCV, + Provided, + BodyWithTracking, + Size, + }; + enum class WorkerType : unsigned char { Input = 0, diff --git a/include/openpose/wrapper/wrapper.hpp b/include/openpose/wrapper/wrapper.hpp index 6f2811b3..54e5d34e 100644 --- a/include/openpose/wrapper/wrapper.hpp +++ b/include/openpose/wrapper/wrapper.hpp @@ -152,6 +152,13 @@ namespace op */ bool waitAndEmplace(TDatumsSP& tDatums); + /** + * Similar to waitAndEmplace(const TDatumsSP& tDatums), but it takes a cv::Mat as input. + * @param cvMat cv::Mat with the image to be processed. + * @return Boolean specifying whether the tDatums could be emplaced. + */ + bool waitAndEmplace(cv::Mat& cvMat); + /** * Push (copy) an element on the first (input) queue. * Same as tryEmplace, but it copies the data instead of moving it. @@ -168,6 +175,13 @@ namespace op */ bool waitAndPush(const TDatumsSP& tDatums); + /** + * Similar to waitAndPush(const TDatumsSP& tDatums), but it takes a cv::Mat as input. + * @param cvMat cv::Mat with the image to be processed. + * @return Boolean specifying whether the tDatums could be pushed. + */ + bool waitAndPush(const cv::Mat& cvMat); + /** * Pop (retrieve) an element from the last (output) queue. * Only valid if ThreadManagerMode::Asynchronous or ThreadManagerMode::AsynchronousOut. @@ -188,12 +202,16 @@ namespace op bool waitAndPop(TDatumsSP& tDatums); /** - * Runs both waitAndEmplace and waitAndPop + * Runs both waitAndEmplace and waitAndPop. + * @param tDatums TDatumsSP element where the retrieved element will be placed. + * @return Boolean specifying whether the tDatums could be retrieved. */ bool emplaceAndPop(TDatumsSP& tDatums); /** - * Runs both waitAndEmplace and waitAndPop + * Similar to emplaceAndPop(TDatumsSP& tDatums), but it takes a cv::Mat as input. + * @param cvMat cv::Mat with the image to be processed. + * @return TDatumsSP element where the processed information will be placed. */ TDatumsSP emplaceAndPop(const cv::Mat& cvMat); @@ -475,6 +493,28 @@ namespace op } } + template + bool WrapperT::waitAndEmplace(cv::Mat& cvMat) + { + try + { + // Create new datum + auto datumsPtr = std::make_shared>>(); + datumsPtr->emplace_back(); + auto& tDatumPtr = datumsPtr->at(0); + tDatumPtr = std::make_shared(); + // Fill datum + std::swap(tDatumPtr->cvInputData, cvMat); + // Return result + return waitAndEmplace(datumsPtr); + } + catch (const std::exception& e) + { + error(e.what(), __LINE__, __FUNCTION__, __FILE__); + return false; + } + } + template bool WrapperT::tryPush(const TDatumsSP& tDatums) { @@ -509,6 +549,28 @@ namespace op } } + template + bool WrapperT::waitAndPush(const cv::Mat& cvMat) + { + try + { + // Create new datum + auto datumsPtr = std::make_shared>>(); + datumsPtr->emplace_back(); + auto& tDatumPtr = datumsPtr->at(0); + tDatumPtr = std::make_shared(); + // Fill datum + tDatumPtr->cvInputData = cvMat.clone(); + // Return result + return waitAndEmplace(datumsPtr); + } + catch (const std::exception& e) + { + error(e.what(), __LINE__, __FUNCTION__, __FILE__); + return false; + } + } + template bool WrapperT::tryPop(TDatumsSP& tDatums) { diff --git a/include/openpose/wrapper/wrapperAuxiliary.hpp b/include/openpose/wrapper/wrapperAuxiliary.hpp index 3017fd02..20624666 100644 --- a/include/openpose/wrapper/wrapperAuxiliary.hpp +++ b/include/openpose/wrapper/wrapperAuxiliary.hpp @@ -351,15 +351,21 @@ namespace op { log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__); // Face detector - // OpenPose face detector - if (wrapperStructPose.enable) + // OpenPose body-based face detector + if (wrapperStructFace.detector == Detector::Body) { + // Sanity check + if (!wrapperStructPose.enable) + error("Body keypoint detection is disabled but face Detector is set to Body. Either" + " re-enable OpenPose body or select a different face Detector (`--face_detector`).", + __LINE__, __FUNCTION__, __FILE__); + // Constructors const auto faceDetector = std::make_shared(wrapperStructPose.poseModel); for (auto& wPose : poseExtractorsWs) wPose.emplace_back(std::make_shared>(faceDetector)); } // OpenCV face detector - else + else if (wrapperStructFace.detector == Detector::OpenCV) { log("Body keypoint detection is disabled. Hence, using OpenCV face detector (much less" " accurate but faster).", Priority::High); @@ -372,6 +378,11 @@ namespace op ); } } + // If provided by user: We do not need to create a FaceDetector + // Unknown face Detector + else if (wrapperStructFace.detector != Detector::Provided) + error("Unknown face Detector. Select a valid face Detector (`--face_detector`).", + __LINE__, __FUNCTION__, __FILE__); // Face keypoint extractor for (auto gpu = 0u; gpu < poseExtractorsWs.size(); gpu++) { @@ -396,16 +407,32 @@ namespace op const auto handDetector = std::make_shared(wrapperStructPose.poseModel); for (auto gpu = 0u; gpu < poseExtractorsWs.size(); gpu++) { + // Sanity check + if ((wrapperStructHand.detector == Detector::BodyWithTracking + || wrapperStructHand.detector == Detector::Body) + && !wrapperStructPose.enable) + error("Body keypoint detection is disabled but hand Detector is set to Body. Either" + " re-enable OpenPose body or select a different hand Detector (`--hand_detector`).", + __LINE__, __FUNCTION__, __FILE__); // Hand detector - // If tracking - if (wrapperStructHand.tracking) + // OpenPose body-based hand detector with tracking + if (wrapperStructHand.detector == Detector::BodyWithTracking) + { poseExtractorsWs.at(gpu).emplace_back( std::make_shared>(handDetector) ); - // If detection - else + } + // OpenPose body-based hand detector + else if (wrapperStructHand.detector == Detector::Body) + { poseExtractorsWs.at(gpu).emplace_back( std::make_shared>(handDetector)); + } + // If provided by user: We do not need to create a FaceDetector + // Unknown hand Detector + else if (wrapperStructHand.detector != Detector::Provided) + error("Unknown hand Detector. Select a valid hand Detector (`--hand_detector`).", + __LINE__, __FUNCTION__, __FILE__); // Hand keypoint extractor const auto netOutputSize = wrapperStructHand.netInputSize; const auto handExtractorNet = std::make_shared( @@ -418,8 +445,8 @@ namespace op poseExtractorsWs.at(gpu).emplace_back( std::make_shared>(handExtractorNet) ); - // If tracking - if (wrapperStructHand.tracking) + // If OpenPose body-based hand detector with tracking + if (wrapperStructHand.detector == Detector::BodyWithTracking) poseExtractorsWs.at(gpu).emplace_back( std::make_shared>(handDetector) ); diff --git a/include/openpose/wrapper/wrapperStructFace.hpp b/include/openpose/wrapper/wrapperStructFace.hpp index 3969dbf0..6072a6ae 100644 --- a/include/openpose/wrapper/wrapperStructFace.hpp +++ b/include/openpose/wrapper/wrapperStructFace.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace op { @@ -19,6 +20,12 @@ namespace op */ bool enable; + /** + * Kind of face rectangle detector. Recommended Detector::Body (fastest one if body is enabled and most + * accurate one), which is based on the OpenPose body keypoint detector. + */ + Detector detector; + /** * CCN (Conv Net) input size. * The greater, the slower and more memory it will be needed, but it will potentially increase accuracy. @@ -59,8 +66,9 @@ namespace op * Since all the elements of the struct are public, they can also be manually filled. */ WrapperStructFace( - const bool enable = false, const Point& netInputSize = Point{368, 368}, - const RenderMode renderMode = RenderMode::Gpu, const float alphaKeypoint = FACE_DEFAULT_ALPHA_KEYPOINT, + const bool enable = false, const Detector detector = Detector::Body, + const Point& netInputSize = Point{368, 368}, const RenderMode renderMode = RenderMode::Gpu, + const float alphaKeypoint = FACE_DEFAULT_ALPHA_KEYPOINT, const float alphaHeatMap = FACE_DEFAULT_ALPHA_HEAT_MAP, const float renderThreshold = 0.4f); }; } diff --git a/include/openpose/wrapper/wrapperStructHand.hpp b/include/openpose/wrapper/wrapperStructHand.hpp index 4f14727b..d6467427 100644 --- a/include/openpose/wrapper/wrapperStructHand.hpp +++ b/include/openpose/wrapper/wrapperStructHand.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace op { @@ -19,6 +20,17 @@ namespace op */ bool enable; + /** + * Kind of hand rectangle detector. Recommended Detector::Body (fastest one if body is enabled and most + * accurate one), which is based on the OpenPose body keypoint detector. + * For hand, there is the alternative of Detector::BodyWithTracking. If selected, it will add tracking + * between frames. 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. + */ + Detector detector; + /** * CCN (Conv Net) input size. * The greater, the slower and more memory it will be needed, but it will potentially increase accuracy. @@ -40,14 +52,6 @@ namespace op */ float scaleRange; - /** - * Whether to add tracking between frames. 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. - */ - bool tracking; - /** * Whether to render the output (pose locations, body, background or PAF heat maps) with CPU or GPU. * Select `None` for no rendering, `Cpu` or `Gpu` por CPU and GPU rendering respectively. @@ -81,9 +85,10 @@ namespace op * Since all the elements of the struct are public, they can also be manually filled. */ WrapperStructHand( - const bool enable = false, const Point& netInputSize = Point{368, 368}, - const int scalesNumber = 1, const float scaleRange = 0.4f, const bool tracking = false, - const RenderMode renderMode = RenderMode::Gpu, const float alphaKeypoint = HAND_DEFAULT_ALPHA_KEYPOINT, + const bool enable = false, const Detector detector = Detector::Body, + const Point& netInputSize = Point{368, 368}, const int scalesNumber = 1, + const float scaleRange = 0.4f, const RenderMode renderMode = RenderMode::Gpu, + const float alphaKeypoint = HAND_DEFAULT_ALPHA_KEYPOINT, const float alphaHeatMap = HAND_DEFAULT_ALPHA_HEAT_MAP, const float renderThreshold = 0.2f); }; } diff --git a/python/openpose/openpose_python.cpp b/python/openpose/openpose_python.cpp index ee0c30a7..67e664f1 100644 --- a/python/openpose/openpose_python.cpp +++ b/python/openpose/openpose_python.cpp @@ -93,6 +93,9 @@ public: const auto heatMapScaleMode = op::flagsToHeatMapScaleMode(FLAGS_heatmaps_scale); // >1 camera view? const auto multipleView = (FLAGS_3d || FLAGS_3d_views > 1); + // Face and hand detectors + const auto faceDetector = op::flagsToDetector(FLAGS_face_detector); + const auto handDetector = op::flagsToDetector(FLAGS_hand_detector); // Enabling Google Logging const bool enableGoogleLogging = true; @@ -107,12 +110,13 @@ public: opWrapper->configure(wrapperStructPose); // Face configuration (use op::WrapperStructFace{} to disable it) const op::WrapperStructFace wrapperStructFace{ - FLAGS_face, faceNetInputSize, op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), + FLAGS_face, faceDetector, faceNetInputSize, + op::flagsToRenderMode(FLAGS_face_render, multipleView, FLAGS_render_pose), (float)FLAGS_face_alpha_pose, (float)FLAGS_face_alpha_heatmap, (float)FLAGS_face_render_threshold}; opWrapper->configure(wrapperStructFace); // Hand configuration (use op::WrapperStructHand{} to disable it) const op::WrapperStructHand wrapperStructHand{ - FLAGS_hand, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, FLAGS_hand_tracking, + FLAGS_hand, handDetector, handNetInputSize, FLAGS_hand_scale_number, (float)FLAGS_hand_scale_range, op::flagsToRenderMode(FLAGS_hand_render, multipleView, FLAGS_render_pose), (float)FLAGS_hand_alpha_pose, (float)FLAGS_hand_alpha_heatmap, (float)FLAGS_hand_render_threshold}; opWrapper->configure(wrapperStructHand); diff --git a/scripts/travis/run_tests.sh b/scripts/travis/run_tests.sh index fffadbb9..ebcea371 100755 --- a/scripts/travis/run_tests.sh +++ b/scripts/travis/run_tests.sh @@ -11,52 +11,72 @@ if [[ $RUN_EXAMPLES == true ]] ; then echo " " echo "OpenPose demo..." - ./build/examples/openpose/openpose.bin --net_resolution -1x32 --image_dir examples/media/ --write_json output/ --display 0 --render_pose 0 + ./build/examples/openpose/openpose.bin --net_resolution -1x32 --image_dir examples/media/ --write_json output/ --write_images output/ --display 0 echo " " echo "Tutorial Add Module: Example 1..." - ./build/examples/tutorial_add_module/1_custom_post_processing.bin --net_resolution -1x32 --image_dir examples/media/ --write_json output/ --display 0 --render_pose 0 + ./build/examples/tutorial_add_module/1_custom_post_processing.bin --net_resolution -1x32 --image_dir examples/media/ --write_json output/ --write_images output/ --display 0 echo " " - # # Note: Examples 1-2 require the whole OpenPose resolution (too much RAM memory) + # # Note: Examples 1-2 require the whole OpenPose resolution (too much RAM memory) and the GUI # echo "Tutorial API C++: Examples 1-2..." - # ./build/examples/tutorial_api_cpp/1_body_from_image.bin - # ./build/examples/tutorial_api_cpp/2_whole_body_from_image.bin + # ./build/examples/tutorial_api_cpp/01_body_from_image_default.bin + # ./build/examples/tutorial_api_cpp/02_whole_body_from_image_default.bin # echo " " echo "Tutorial API C++: Example 3..." - ./build/examples/tutorial_api_cpp/3_keypoints_from_image_configurable.bin --no_display --net_resolution -1x32 --write_json output/ + ./build/examples/tutorial_api_cpp/03_keypoints_from_image.bin --no_display --net_resolution -1x32 --write_json output/ echo " " echo "Tutorial API C++: Example 4..." - ./build/examples/tutorial_api_cpp/4_asynchronous_loop_custom_input_and_output.bin --no_display --net_resolution -1x32 --image_dir examples/media/ + ./build/examples/tutorial_api_cpp/04_keypoints_from_images.bin --no_display --net_resolution -1x32 --write_json output/ echo " " echo "Tutorial API C++: Example 5..." - ./build/examples/tutorial_api_cpp/5_asynchronous_loop_custom_output.bin --no_display --net_resolution -1x32 --image_dir examples/media/ + ./build/examples/tutorial_api_cpp/05_keypoints_from_images_multi_gpu.bin --no_display --net_resolution -1x32 --write_json output/ echo " " echo "Tutorial API C++: Example 6..." - ./build/examples/tutorial_api_cpp/6_synchronous_custom_postprocessing.bin --net_resolution -1x32 --image_dir examples/media/ --write_json output/ --display 0 --render_pose 0 + ./build/examples/tutorial_api_cpp/06_asynchronous_custom_input.bin --net_resolution -1x32 --image_dir examples/media/ --write_json output/ --write_images output/ --display 0 echo " " echo "Tutorial API C++: Example 7..." - ./build/examples/tutorial_api_cpp/7_synchronous_custom_input.bin --net_resolution -1x32 --image_dir examples/media/ --write_json output/ --display 0 --render_pose 0 + ./build/examples/tutorial_api_cpp/07_asynchronous_custom_output.bin --no_display --net_resolution -1x32 --image_dir examples/media/ echo " " echo "Tutorial API C++: Example 8..." - ./build/examples/tutorial_api_cpp/8_synchronous_custom_output.bin --no_display --net_resolution -1x32 --image_dir examples/media/ + ./build/examples/tutorial_api_cpp/08_asynchronous_custom_input_output_and_datum.bin --no_display --net_resolution -1x32 --image_dir examples/media/ echo " " echo "Tutorial API C++: Example 9..." - ./build/examples/tutorial_api_cpp/9_synchronous_custom_all.bin --no_display --net_resolution -1x32 --image_dir examples/media/ + ./build/examples/tutorial_api_cpp/09_face_from_image.bin --no_display --face_net_resolution 32x32 + echo " " + + echo "Tutorial API C++: Example 10..." + ./build/examples/tutorial_api_cpp/10_hand_from_image.bin --no_display --hand_net_resolution 32x32 + echo " " + + echo "Tutorial API C++: Example 11..." + ./build/examples/tutorial_api_cpp/11_synchronous_custom_input.bin --net_resolution -1x32 --image_dir examples/media/ --write_json output/ --write_images output/ --display 0 + echo " " + + echo "Tutorial API C++: Example 13..." + ./build/examples/tutorial_api_cpp/13_synchronous_custom_postprocessing.bin --net_resolution -1x32 --image_dir examples/media/ --write_json output/ --write_images output/ --display 0 + echo " " + + echo "Tutorial API C++: Example 14..." + ./build/examples/tutorial_api_cpp/14_synchronous_custom_output.bin --no_display --net_resolution -1x32 --image_dir examples/media/ + echo " " + + echo "Tutorial API C++: Example 15..." + ./build/examples/tutorial_api_cpp/15_synchronous_custom_all.bin --no_display --net_resolution -1x32 --image_dir examples/media/ echo " " # Python examples if [[ $WITH_PYTHON == true ]] ; then echo "Tutorial API Python: OpenPose demo..." cd build/examples/tutorial_api_python - python openpose_python.py --net_resolution -1x32 --image_dir ../../../examples/media/ --write_json output/ --display 0 --render_pose 0 + python openpose_python.py --net_resolution -1x32 --image_dir ../../../examples/media/ --write_json output/ --write_images output/ --display 0 echo " " # Note: All Python examples require GUI fi diff --git a/src/openpose/utilities/flagsToOpenPose.cpp b/src/openpose/utilities/flagsToOpenPose.cpp index 589ee71d..b09ac396 100644 --- a/src/openpose/utilities/flagsToOpenPose.cpp +++ b/src/openpose/utilities/flagsToOpenPose.cpp @@ -112,6 +112,27 @@ namespace op } } + Detector flagsToDetector(const int detector) + { + try + { + log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__); + if (detector >= 0 && detector < (int)Detector::Size) + return (Detector)detector; + else + { + error("Value (" + std::to_string(detector) + ") does not correspond with any Detector.", + __LINE__, __FUNCTION__, __FILE__); + return Detector::Body; + } + } + catch (const std::exception& e) + { + error(e.what(), __LINE__, __FUNCTION__, __FILE__); + return Detector::Body; + } + } + ProducerType flagsToProducerType(const std::string& imageDirectory, const std::string& videoPath, const std::string& ipCameraPath, const int webcamIndex, const bool flirCamera) diff --git a/src/openpose/utilities/profiler.cpp b/src/openpose/utilities/profiler.cpp index 2801145f..e670b857 100644 --- a/src/openpose/utilities/profiler.cpp +++ b/src/openpose/utilities/profiler.cpp @@ -10,6 +10,50 @@ namespace op { unsigned long long Profiler::DEFAULT_X = 1000; + std::chrono::time_point getTimerInit() + { + try + { + return std::chrono::high_resolution_clock::now(); + } + catch (const std::exception& e) + { + error(e.what(), __LINE__, __FUNCTION__, __FILE__); + return std::chrono::high_resolution_clock::now(); + } + } + + double getTimeSeconds(const std::chrono::time_point& timerInit) + { + try + { + const auto now = std::chrono::high_resolution_clock::now(); + const auto totalTimeSec = double( + std::chrono::duration_cast(now-timerInit).count() * 1e-9); + return totalTimeSec; + } + catch (const std::exception& e) + { + error(e.what(), __LINE__, __FUNCTION__, __FILE__); + return -1.; + } + } + + void printTime( + const std::chrono::time_point& timerInit, const std::string& firstMessage, + const std::string& secondMessage, const Priority priority) + { + try + { + const auto message = firstMessage + std::to_string(getTimeSeconds(timerInit)) + secondMessage; + op::log(message, priority); + } + catch (const std::exception& e) + { + error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } + } + #ifdef PROFILER_ENABLED std::map> sProfilerTuple{ @@ -27,7 +71,7 @@ namespace op void printAveragedTimeMsCommon(const double timePast, const unsigned long long timeCounter, const int line, const std::string& function, const std::string& file) { - const auto stringMessage = std::to_string( timePast / timeCounter / 1e6 ) + " msec at"; + const auto stringMessage = std::to_string( timePast / timeCounter / 1e6 ) + " msec"; log(stringMessage, Priority::Max, line, function, file); } #endif diff --git a/src/openpose/wrapper/wrapperAuxiliary.cpp b/src/openpose/wrapper/wrapperAuxiliary.cpp index 7ae8e142..272c2cd6 100644 --- a/src/openpose/wrapper/wrapperAuxiliary.cpp +++ b/src/openpose/wrapper/wrapperAuxiliary.cpp @@ -110,14 +110,10 @@ namespace op error("Writting video is only available if the OpenPose producer is used (i.e." " producerSharedPtr cannot be a nullptr).", __LINE__, __FUNCTION__, __FILE__); - if (!wrapperStructPose.enable) - { - if (!wrapperStructFace.enable) - error("Body keypoint detection must be enabled.", __LINE__, __FUNCTION__, __FILE__); - if (wrapperStructHand.enable) - error("Body keypoint detection must be enabled in order to run hand keypoint detection.", - __LINE__, __FUNCTION__, __FILE__); - } + if (!wrapperStructPose.enable && !wrapperStructFace.enable && !wrapperStructHand.enable) + error("Body, face, and hand keypoint detectors are disabled. You must enable at least one (i.e," + " unselect `--body_disable`, select `--face`, or select `--hand`.", + __LINE__, __FUNCTION__, __FILE__); // If 3-D module, 1 person is the maximum if (wrapperStructExtra.reconstruct3d && wrapperStructPose.numberPeopleMax != 1) { diff --git a/src/openpose/wrapper/wrapperStructFace.cpp b/src/openpose/wrapper/wrapperStructFace.cpp index 224ef20e..b480d50e 100644 --- a/src/openpose/wrapper/wrapperStructFace.cpp +++ b/src/openpose/wrapper/wrapperStructFace.cpp @@ -3,9 +3,10 @@ namespace op { WrapperStructFace::WrapperStructFace( - const bool enable_, const Point& netInputSize_, const RenderMode renderMode_, const float alphaKeypoint_, - const float alphaHeatMap_, const float renderThreshold_) : + const bool enable_, const Detector detector_, const Point& netInputSize_, const RenderMode renderMode_, + const float alphaKeypoint_, const float alphaHeatMap_, const float renderThreshold_) : enable{enable_}, + detector{detector_}, netInputSize{netInputSize_}, renderMode{renderMode_}, alphaKeypoint{alphaKeypoint_}, diff --git a/src/openpose/wrapper/wrapperStructHand.cpp b/src/openpose/wrapper/wrapperStructHand.cpp index bb3a0bca..2f97819f 100644 --- a/src/openpose/wrapper/wrapperStructHand.cpp +++ b/src/openpose/wrapper/wrapperStructHand.cpp @@ -3,14 +3,14 @@ namespace op { WrapperStructHand::WrapperStructHand( - const bool enable_, const Point& netInputSize_, const int scalesNumber_, const float scaleRange_, - const bool tracking_, const RenderMode renderMode_, const float alphaKeypoint_, const float alphaHeatMap_, + const bool enable_, const Detector detector_, const Point& netInputSize_, const int scalesNumber_, + const float scaleRange_, const RenderMode renderMode_, const float alphaKeypoint_, const float alphaHeatMap_, const float renderThreshold_) : enable{enable_}, + detector{detector_}, netInputSize{netInputSize_}, scalesNumber{scalesNumber_}, scaleRange{scaleRange_}, - tracking{tracking_}, renderMode{renderMode_}, alphaKeypoint{alphaKeypoint_}, alphaHeatMap{alphaHeatMap_},