diff --git a/examples/tutorial_api_cpp/01_body_from_image_default.cpp b/examples/tutorial_api_cpp/01_body_from_image_default.cpp index 430bdd34..3771793b 100644 --- a/examples/tutorial_api_cpp/01_body_from_image_default.cpp +++ b/examples/tutorial_api_cpp/01_body_from_image_default.cpp @@ -26,7 +26,7 @@ void display(const std::shared_ptr>>& dat if (datumsPtr != nullptr && !datumsPtr->empty()) { // Display image - cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + cv::imshow(OPEN_POSE_NAME_AND_VERSION + " - Tutorial C++ API", datumsPtr->at(0)->cvOutputData); cv::waitKey(0); } else diff --git a/examples/tutorial_api_cpp/02_whole_body_from_image_default.cpp b/examples/tutorial_api_cpp/02_whole_body_from_image_default.cpp index 4d8139aa..8d1e4b19 100644 --- a/examples/tutorial_api_cpp/02_whole_body_from_image_default.cpp +++ b/examples/tutorial_api_cpp/02_whole_body_from_image_default.cpp @@ -26,7 +26,7 @@ void display(const std::shared_ptr>>& dat if (datumsPtr != nullptr && !datumsPtr->empty()) { // Display image - cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + cv::imshow(OPEN_POSE_NAME_AND_VERSION + " - Tutorial C++ API", datumsPtr->at(0)->cvOutputData); cv::waitKey(0); } else diff --git a/examples/tutorial_api_cpp/03_keypoints_from_image.cpp b/examples/tutorial_api_cpp/03_keypoints_from_image.cpp index ad5f4b47..a475f1b0 100644 --- a/examples/tutorial_api_cpp/03_keypoints_from_image.cpp +++ b/examples/tutorial_api_cpp/03_keypoints_from_image.cpp @@ -28,7 +28,7 @@ void display(const std::shared_ptr>>& dat if (datumsPtr != nullptr && !datumsPtr->empty()) { // Display image - cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + cv::imshow(OPEN_POSE_NAME_AND_VERSION + " - Tutorial C++ API", datumsPtr->at(0)->cvOutputData); cv::waitKey(0); } else diff --git a/examples/tutorial_api_cpp/04_keypoints_from_images.cpp b/examples/tutorial_api_cpp/04_keypoints_from_images.cpp index 80ee3354..10997a9e 100644 --- a/examples/tutorial_api_cpp/04_keypoints_from_images.cpp +++ b/examples/tutorial_api_cpp/04_keypoints_from_images.cpp @@ -11,7 +11,7 @@ // Custom OpenPose flags // Producer -DEFINE_string(image_dir, "examples/media/", +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, @@ -29,7 +29,7 @@ bool display(const std::shared_ptr>>& dat 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); + cv::imshow(OPEN_POSE_NAME_AND_VERSION + " - Tutorial C++ API", datumsPtr->at(0)->cvOutputData); key = (char)cv::waitKey(1); } else 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 index 1e2749b8..0bf47dc9 100644 --- a/examples/tutorial_api_cpp/05_keypoints_from_images_multi_gpu.cpp +++ b/examples/tutorial_api_cpp/05_keypoints_from_images_multi_gpu.cpp @@ -11,8 +11,14 @@ // Custom OpenPose flags // Producer -DEFINE_string(image_dir, "examples/media/", +DEFINE_string(image_dir, "examples/media/", "Process a directory of images. Read all standard formats (jpg, png, bmp, etc.)."); +// OpenPose +DEFINE_bool(latency_is_irrelevant_and_computer_with_lots_of_ram, false, + "If false, it will read and then then process images right away. If true, it will first store all the frames and" + " later process them (slightly faster). However: 1) Latency will hugely increase (no frames will be processed" + " until they have all been read). And 2) The program might go out of RAM memory with long videos or folders with" + " many images (so the computer might freeze)."); // Display DEFINE_bool(no_display, false, "Enable to disable the visual display."); @@ -29,7 +35,7 @@ bool display(const std::shared_ptr>>& dat 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); + cv::imshow(OPEN_POSE_NAME_AND_VERSION + " - Tutorial C++ API", datumsPtr->at(0)->cvOutputData); key = (char)cv::waitKey(1); } else @@ -160,6 +166,9 @@ int tutorialApiCpp() op::log("Configuring OpenPose...", op::Priority::High); op::Wrapper opWrapper{op::ThreadManagerMode::Asynchronous}; configureWrapper(opWrapper); + // Increase maximum wrapper queue size + if (FLAGS_latency_is_irrelevant_and_computer_with_lots_of_ram) + opWrapper.setDefaultMaxSizeQueues(std::numeric_limits::max()); // Starting OpenPose op::log("Starting thread(s)...", op::Priority::High); @@ -177,12 +186,63 @@ int tutorialApiCpp() // 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) + if (!FLAGS_latency_is_irrelevant_and_computer_with_lots_of_ram) { - // Read and push images into OpenPose wrapper - for (auto gpuId = 0 ; gpuId < numberGPUs ; gpuId++) + for (auto imageBaseId = 0u ; imageBaseId < imagePaths.size() ; imageBaseId+=numberGPUs) + { + // Read and push images into OpenPose wrapper + for (auto gpuId = 0 ; gpuId < numberGPUs ; gpuId++) + { + const auto imageId = imageBaseId+gpuId; + if (imageId < imagePaths.size()) + { + const auto& imagePath = imagePaths.at(imageId); + // 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++) + { + const auto imageId = imageBaseId+gpuId; + if (imageId < imagePaths.size()) + { + 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); + } + } + } + } + // Option c) Even easier and faster to implement than option b. In addition, its runtime performance should + // be slightly faster too, but: + // - Latency will hugely increase (no frames will be processed until they have all been read). + // - The program might go out of RAM memory with long videos or folders with many images (so the computer + // might freeze). + else + { + // Read and push all images into OpenPose wrapper + op::log("Loading images into OpenPose wrapper...", op::Priority::High); + for (const auto& imagePath : imagePaths) { - const auto& imagePath = imagePaths.at(imageId+gpuId); // Faster alternative that moves imageToProcess auto imageToProcess = cv::imread(imagePath); opWrapper.waitAndEmplace(imageToProcess); @@ -191,7 +251,8 @@ int tutorialApiCpp() // opWrapper.waitAndPush(imageToProcess); } // Retrieve processed results from OpenPose wrapper - for (auto gpuId = 0 ; gpuId < numberGPUs ; gpuId++) + op::log("Retrieving results from OpenPose wrapper...", op::Priority::High); + for (auto imageId = 0u ; imageId < imagePaths.size() ; imageId++) { std::shared_ptr>> datumProcessed; const auto status = opWrapper.waitAndPop(datumProcessed); diff --git a/examples/tutorial_api_cpp/09_face_from_image.cpp b/examples/tutorial_api_cpp/06_face_from_image.cpp similarity index 98% rename from examples/tutorial_api_cpp/09_face_from_image.cpp rename to examples/tutorial_api_cpp/06_face_from_image.cpp index b951d81a..e207cfc2 100644 --- a/examples/tutorial_api_cpp/09_face_from_image.cpp +++ b/examples/tutorial_api_cpp/06_face_from_image.cpp @@ -1,4 +1,4 @@ -// ----------------------------- OpenPose C++ API Tutorial - Example 9 - Face from Image ----------------------------- +// ----------------------------- OpenPose C++ API Tutorial - Example 6 - 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. @@ -31,7 +31,7 @@ void display(const std::shared_ptr>>& dat if (datumsPtr != nullptr && !datumsPtr->empty()) { // Display image - cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + cv::imshow(OPEN_POSE_NAME_AND_VERSION + " - Tutorial C++ API", datumsPtr->at(0)->cvOutputData); cv::waitKey(0); } else diff --git a/examples/tutorial_api_cpp/10_hand_from_image.cpp b/examples/tutorial_api_cpp/07_hand_from_image.cpp similarity index 98% rename from examples/tutorial_api_cpp/10_hand_from_image.cpp rename to examples/tutorial_api_cpp/07_hand_from_image.cpp index 4297b082..183df76d 100644 --- a/examples/tutorial_api_cpp/10_hand_from_image.cpp +++ b/examples/tutorial_api_cpp/07_hand_from_image.cpp @@ -1,4 +1,4 @@ -// ----------------------------- OpenPose C++ API Tutorial - Example 9 - Face from Image ----------------------------- +// ----------------------------- OpenPose C++ API Tutorial - Example 7 - 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. @@ -31,7 +31,7 @@ void display(const std::shared_ptr>>& dat if (datumsPtr != nullptr && !datumsPtr->empty()) { // Display image - cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + cv::imshow(OPEN_POSE_NAME_AND_VERSION + " - Tutorial C++ API", datumsPtr->at(0)->cvOutputData); cv::waitKey(0); } else diff --git a/examples/tutorial_api_cpp/06_asynchronous_custom_input.cpp b/examples/tutorial_api_cpp/09_asynchronous_custom_input.cpp similarity index 96% rename from examples/tutorial_api_cpp/06_asynchronous_custom_input.cpp rename to examples/tutorial_api_cpp/09_asynchronous_custom_input.cpp index d88a3325..252029df 100644 --- a/examples/tutorial_api_cpp/06_asynchronous_custom_input.cpp +++ b/examples/tutorial_api_cpp/09_asynchronous_custom_input.cpp @@ -1,4 +1,4 @@ -// ------------------------- OpenPose C++ API Tutorial - Example 6 - Custom Input ------------------------- +// ------------------------- OpenPose C++ API Tutorial - Example 9 - 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. @@ -11,13 +11,9 @@ // Custom OpenPose flags // Producer -DEFINE_string(image_dir, "examples/media/", +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 { diff --git a/examples/tutorial_api_cpp/07_asynchronous_custom_output.cpp b/examples/tutorial_api_cpp/10_asynchronous_custom_output.cpp similarity index 96% rename from examples/tutorial_api_cpp/07_asynchronous_custom_output.cpp rename to examples/tutorial_api_cpp/10_asynchronous_custom_output.cpp index 4d28d871..9b5b9a90 100644 --- a/examples/tutorial_api_cpp/07_asynchronous_custom_output.cpp +++ b/examples/tutorial_api_cpp/10_asynchronous_custom_output.cpp @@ -1,6 +1,6 @@ -// ------------------------- OpenPose C++ API Tutorial - Example 7 - Custom Output ------------------------- +// ------------------------- OpenPose C++ API Tutorial - Example 10 - 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. +// In this function, the user can implement its own way to render/display/storage the results. // Command-line user intraface #define OPENPOSE_FLAGS_DISABLE_DISPLAY @@ -13,10 +13,6 @@ DEFINE_bool(no_display, false, "Enable to disable the visual display."); -// 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 jpg files in a directory class UserOutputClass { @@ -29,7 +25,7 @@ public: char key = ' '; if (datumsPtr != nullptr && !datumsPtr->empty()) { - cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + cv::imshow(OPEN_POSE_NAME_AND_VERSION + " - Tutorial C++ API", 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); } diff --git a/examples/tutorial_api_cpp/08_asynchronous_custom_input_output_and_datum.cpp b/examples/tutorial_api_cpp/11_asynchronous_custom_input_output_and_datum.cpp similarity index 96% rename from examples/tutorial_api_cpp/08_asynchronous_custom_input_output_and_datum.cpp rename to examples/tutorial_api_cpp/11_asynchronous_custom_input_output_and_datum.cpp index 7b6409e8..e6d80421 100644 --- a/examples/tutorial_api_cpp/08_asynchronous_custom_input_output_and_datum.cpp +++ b/examples/tutorial_api_cpp/11_asynchronous_custom_input_output_and_datum.cpp @@ -1,4 +1,4 @@ -// ------------------------- OpenPose C++ API Tutorial - Example 8 - Custom Input and Output ------------------------- +// --------------------- OpenPose C++ API Tutorial - Example 11 - Custom Input, Output, and Datum --------------------- // 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. @@ -12,7 +12,7 @@ // Custom OpenPose flags // Producer -DEFINE_string(image_dir, "examples/media/", +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, @@ -31,10 +31,6 @@ struct UserDatum : public op::Datum {} }; -// 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 - // This worker will just read and return all the basic image file formats in a directory class UserInputClass { @@ -111,7 +107,7 @@ public: 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); + cv::imshow(OPEN_POSE_NAME_AND_VERSION + " - Tutorial C++ API", datumsPtr->at(0)->cvOutputData); key = (char)cv::waitKey(1); } else diff --git a/examples/tutorial_api_cpp/11_synchronous_custom_input.cpp b/examples/tutorial_api_cpp/12_synchronous_custom_input.cpp similarity index 71% rename from examples/tutorial_api_cpp/11_synchronous_custom_input.cpp rename to examples/tutorial_api_cpp/12_synchronous_custom_input.cpp index f104cd26..aa9d7d45 100644 --- a/examples/tutorial_api_cpp/11_synchronous_custom_input.cpp +++ b/examples/tutorial_api_cpp/12_synchronous_custom_input.cpp @@ -1,20 +1,7 @@ -// ------------------------- OpenPose C++ API Tutorial - Example 7 - XXXXXXXXXXXXX ------------------------- -// If the user wants to learn to use the OpenPose library, we highly recommend to start with the -// examples in `examples/tutorial_api_cpp/`. -// This example summarizes all the functionality of the OpenPose library: - // 1. Read folder of images / video / webcam (`producer` module) - // 2. Extract and render body keypoint / heatmap / PAF of that image (`pose` module) - // 3. Extract and render face keypoint / heatmap / PAF of that image (`face` module) - // 4. Save the results on disk (`filestream` module) - // 5. Display the rendered pose (`gui` module) - // Everything in a multi-thread scenario (`thread` module) - // Points 2 to 5 are included in the `wrapper` 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 - // 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 12 - Custom Input ------------------------- +// Synchronous mode: ideal for production integration. It provides the fastest results with respect to runtime +// performance. +// In this function, the user can implement its own way to create frames (e.g., reading his own folder of images). // Command-line user intraface #define OPENPOSE_FLAGS_DISABLE_PRODUCER @@ -24,28 +11,11 @@ // Custom OpenPose flags // Producer -DEFINE_string(image_dir, "examples/media/", +DEFINE_string(image_dir, "examples/media/", "Process a directory of images. Read all standard formats (jpg, png, bmp, etc.)."); -// 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 - // This worker will just read and return all the basic image file formats in a directory -class WUserInput : public op::WorkerProducer>>> +class WUserInput : public op::WorkerProducer>>> { public: WUserInput(const std::string& directoryPath) : @@ -60,7 +30,7 @@ public: void initializationOnThread() {} - std::shared_ptr>> workProducer() + std::shared_ptr>> workProducer() { try { @@ -77,10 +47,10 @@ public: else { // Create new datum - auto datumsPtr = std::make_shared>>(); + auto datumsPtr = std::make_shared>>(); datumsPtr->emplace_back(); auto& datumPtr = datumsPtr->at(0); - datumPtr = std::make_shared(); + datumPtr = std::make_shared(); // Fill datum datumPtr->cvInputData = cv::imread(mImageFiles.at(mCounter++)); @@ -110,23 +80,17 @@ private: unsigned long long mCounter; }; -int tutorialApiCpp() +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.", __LINE__, __FUNCTION__, __FILE__); op::ConfigureLog::setPriorityThreshold((op::Priority)FLAGS_logging_level); op::Profiler::setDefaultX(FLAGS_profile_speed); - // // For debugging - // // Print all logging messages - // op::ConfigureLog::setPriorityThreshold(op::Priority::None); - // // Print out speed values faster - // op::Profiler::setDefaultX(100); // Applying user defined configuration - GFlags to program variables // outputSize @@ -158,16 +122,12 @@ int tutorialApiCpp() // Enabling Google Logging const bool enableGoogleLogging = true; - // OpenPose wrapper - op::log("Configuring OpenPose...", op::Priority::High); - op::WrapperT opWrapperT; - // Initializing the user custom classes // Frames producer (e.g., video, webcam, ...) auto wUserInput = std::make_shared(FLAGS_image_dir); // Add custom processing const auto workerInputOnNewThread = true; - opWrapperT.setWorker(op::WorkerType::Input, wUserInput, workerInputOnNewThread); + opWrapper.setWorker(op::WorkerType::Input, wUserInput, workerInputOnNewThread); // Pose configuration (use WrapperStructPose{} for default and recommended configuration) const op::WrapperStructPose wrapperStructPose{ @@ -177,23 +137,23 @@ int tutorialApiCpp() 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, 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, 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); // 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), @@ -201,28 +161,41 @@ int tutorialApiCpp() 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); // 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}; - opWrapperT.configure(wrapperStructGui); + opWrapper.configure(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(); + + // OpenPose wrapper + op::log("Configuring OpenPose...", op::Priority::High); + op::Wrapper opWrapper; + 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.exec(); + 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 return 0; } catch (const std::exception& e) diff --git a/examples/tutorial_api_cpp/13_synchronous_custom_postprocessing.cpp b/examples/tutorial_api_cpp/14_synchronous_custom_postprocessing.cpp similarity index 69% rename from examples/tutorial_api_cpp/13_synchronous_custom_postprocessing.cpp rename to examples/tutorial_api_cpp/14_synchronous_custom_postprocessing.cpp index e03f7bd1..f5b049b2 100644 --- a/examples/tutorial_api_cpp/13_synchronous_custom_postprocessing.cpp +++ b/examples/tutorial_api_cpp/14_synchronous_custom_postprocessing.cpp @@ -1,45 +1,16 @@ -// ------------------------- OpenPose C++ API Tutorial - Example 6 - XXXXXXXXXXXXX ------------------------- -// If the user wants to learn to use the OpenPose library, we highly recommend to start with the -// examples in `examples/tutorial_api_cpp/`. -// This example summarizes all the functionality of the OpenPose library: - // 1. Read folder of images / video / webcam (`producer` module) - // 2. Extract and render body keypoint / heatmap / PAF of that image (`pose` module) - // 3. Extract and render face keypoint / heatmap / PAF of that image (`face` module) - // 4. Save the results on disk (`filestream` module) - // 5. Display the rendered pose (`gui` module) - // Everything in a multi-thread scenario (`thread` module) - // Points 2 to 5 are included in the `wrapper` 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 - // 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 14 - Custom Post-processing ------------------------- +// Synchronous mode: ideal for production integration. It provides the fastest results with respect to runtime +// performance. +// In this function, the user can implement its own post-processing, i.e., his function will be called after OpenPose +// has processed the frames but before saving or visualizing any result. // Command-line user intraface #include // OpenPose dependencies #include -// 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 - // This worker will just invert the image -class WUserPostProcessing : public op::Worker>>> +class WUserPostProcessing : public op::Worker>>> { public: WUserPostProcessing() @@ -49,7 +20,7 @@ public: void initializationOnThread() {} - void work(std::shared_ptr>>& datumsPtr) + 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 @@ -68,23 +39,17 @@ public: } }; -int tutorialApiCpp() +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.", __LINE__, __FUNCTION__, __FILE__); op::ConfigureLog::setPriorityThreshold((op::Priority)FLAGS_logging_level); op::Profiler::setDefaultX(FLAGS_profile_speed); - // // For debugging - // // Print all logging messages - // op::ConfigureLog::setPriorityThreshold(op::Priority::None); - // // Print out speed values faster - // op::Profiler::setDefaultX(100); // Applying user defined configuration - GFlags to program variables // producerType @@ -122,16 +87,12 @@ int tutorialApiCpp() // Enabling Google Logging const bool enableGoogleLogging = true; - // OpenPose wrapper - op::log("Configuring OpenPose...", op::Priority::High); - op::WrapperT opWrapperT; - // Initializing the user custom classes // Processing auto wUserPostProcessing = std::make_shared(); // Add custom processing const auto workerProcessingOnNewThread = true; - opWrapperT.setWorker(op::WorkerType::PostProcessing, wUserPostProcessing, workerProcessingOnNewThread); + opWrapper.setWorker(op::WorkerType::PostProcessing, wUserPostProcessing, workerProcessingOnNewThread); // Pose configuration (use WrapperStructPose{} for default and recommended configuration) const op::WrapperStructPose wrapperStructPose{ @@ -141,29 +102,29 @@ int tutorialApiCpp() 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, 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, 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), @@ -171,28 +132,41 @@ int tutorialApiCpp() 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); // 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}; - opWrapperT.configure(wrapperStructGui); + opWrapper.configure(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(); + + // OpenPose wrapper + op::log("Configuring OpenPose...", op::Priority::High); + op::Wrapper opWrapper; + 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.exec(); + 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 return 0; } catch (const std::exception& e) diff --git a/examples/tutorial_api_cpp/14_synchronous_custom_output.cpp b/examples/tutorial_api_cpp/15_synchronous_custom_output.cpp similarity index 76% rename from examples/tutorial_api_cpp/14_synchronous_custom_output.cpp rename to examples/tutorial_api_cpp/15_synchronous_custom_output.cpp index 2980a89a..de6dffcd 100644 --- a/examples/tutorial_api_cpp/14_synchronous_custom_output.cpp +++ b/examples/tutorial_api_cpp/15_synchronous_custom_output.cpp @@ -1,20 +1,7 @@ -// ------------------------- OpenPose C++ API Tutorial - Example 8 - XXXXXXXXXXXXX ------------------------- -// If the user wants to learn to use the OpenPose library, we highly recommend to start with the -// examples in `examples/tutorial_api_cpp/`. -// This example summarizes all the functionality of the OpenPose library: - // 1. Read folder of images / video / webcam (`producer` module) - // 2. Extract and render body keypoint / heatmap / PAF of that image (`pose` module) - // 3. Extract and render face keypoint / heatmap / PAF of that image (`face` module) - // 4. Save the results on disk (`filestream` module) - // 5. Display the rendered pose (`gui` module) - // Everything in a multi-thread scenario (`thread` module) - // Points 2 to 5 are included in the `wrapper` 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 - // 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 15 - Custom Output ------------------------- +// Synchronous mode: ideal for production integration. It provides the fastest results with respect to runtime +// performance. +// In this function, the user can implement its own way to render/display/storage the results. // Command-line user intraface #define OPENPOSE_FLAGS_DISABLE_DISPLAY @@ -27,30 +14,13 @@ 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 - // This worker will just read and return all the jpg files in a directory -class WUserOutput : public op::WorkerConsumer>>> +class WUserOutput : public op::WorkerConsumer>>> { public: void initializationOnThread() {} - void workConsumer(const std::shared_ptr>>& datumsPtr) + void workConsumer(const std::shared_ptr>>& datumsPtr) { try { @@ -109,7 +79,7 @@ public: if (!FLAGS_no_display) { // Display rendered output image - cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + cv::imshow(OPEN_POSE_NAME_AND_VERSION + " - Tutorial C++ API", datumsPtr->at(0)->cvOutputData); // Display image and sleeps at least 1 ms (it usually sleeps ~5-10 msec to display the image) const char key = (char)cv::waitKey(1); if (key == 27) @@ -125,23 +95,17 @@ public: } }; -int tutorialApiCpp() +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.", __LINE__, __FUNCTION__, __FILE__); op::ConfigureLog::setPriorityThreshold((op::Priority)FLAGS_logging_level); op::Profiler::setDefaultX(FLAGS_profile_speed); - // // For debugging - // // Print all logging messages - // op::ConfigureLog::setPriorityThreshold(op::Priority::None); - // // Print out speed values faster - // op::Profiler::setDefaultX(100); // Applying user defined configuration - GFlags to program variables // producerType @@ -179,16 +143,12 @@ int tutorialApiCpp() // Enabling Google Logging const bool enableGoogleLogging = true; - // OpenPose wrapper - op::log("Configuring OpenPose...", op::Priority::High); - op::WrapperT opWrapperT; - // Initializing the user custom classes // GUI (Display) auto wUserOutput = std::make_shared(); // Add custom processing const auto workerOutputOnNewThread = true; - opWrapperT.setWorker(op::WorkerType::Output, wUserOutput, workerOutputOnNewThread); + opWrapper.setWorker(op::WorkerType::Output, wUserOutput, workerOutputOnNewThread); // Pose configuration (use WrapperStructPose{} for default and recommended configuration) const op::WrapperStructPose wrapperStructPose{ @@ -198,29 +158,29 @@ int tutorialApiCpp() 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, 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, 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), @@ -228,25 +188,38 @@ int tutorialApiCpp() 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(); + + // OpenPose wrapper + op::log("Configuring OpenPose...", op::Priority::High); + op::Wrapper opWrapper; + 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.exec(); + 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 return 0; } catch (const std::exception& e) diff --git a/examples/tutorial_api_cpp/15_synchronous_custom_all.cpp b/examples/tutorial_api_cpp/16_synchronous_custom_all_and_datum.cpp similarity index 89% rename from examples/tutorial_api_cpp/15_synchronous_custom_all.cpp rename to examples/tutorial_api_cpp/16_synchronous_custom_all_and_datum.cpp index 510fa9d3..aebc6518 100644 --- a/examples/tutorial_api_cpp/15_synchronous_custom_all.cpp +++ b/examples/tutorial_api_cpp/16_synchronous_custom_all_and_datum.cpp @@ -1,19 +1,9 @@ -// ------------------------- OpenPose C++ API Tutorial - Example 9 - XXXXXXXXXXXXX ------------------------- -// Synchronous mode: ideal for performance. The user can add his own frames producer / post-processor / consumer to the OpenPose wrapper or use the -// default ones. - -// 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 16 - Custom Input, Pre-processing, Post-processing, Output, and Datum --- +// Synchronous mode: ideal for production integration. It provides the fastest results with respect to runtime +// performance. +// In this function, the user can implement its own way to read frames, implement its own post-processing (i.e., his +// function will be called after OpenPose has processed the frames but before saving), visualizing any result +// render/display/storage the results, and use their custom Datum structure // Command-line user intraface #define OPENPOSE_FLAGS_DISABLE_PRODUCER @@ -24,7 +14,7 @@ // Custom OpenPose flags // Producer -DEFINE_string(image_dir, "examples/media/", +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, @@ -43,10 +33,6 @@ struct UserDatum : public op::Datum {} }; -// 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 - // This worker will just read and return all the basic image file formats in a directory class WUserInput : public op::WorkerProducer>>> { @@ -208,7 +194,7 @@ public: if (!FLAGS_no_display) { // Display rendered output image - cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + cv::imshow(OPEN_POSE_NAME_AND_VERSION + " - Tutorial C++ API", datumsPtr->at(0)->cvOutputData); // Display image and sleeps at least 1 ms (it usually sleeps ~5-10 msec to display the image) const char key = (char)cv::waitKey(1); if (key == 27) @@ -224,12 +210,11 @@ public: } }; -int tutorialApiCpp() +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.", @@ -274,9 +259,6 @@ int tutorialApiCpp() // GUI (Display) auto wUserOutput = std::make_shared(); - // OpenPose wrapper - op::log("Configuring OpenPose...", op::Priority::High); - op::WrapperT opWrapperT; // Add custom input const auto workerInputOnNewThread = false; opWrapperT.setWorker(op::WorkerType::Input, wUserInput, workerInputOnNewThread); @@ -324,20 +306,33 @@ int tutorialApiCpp() // 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(); + + // OpenPose wrapper + op::log("Configuring OpenPose...", op::Priority::High); + op::WrapperT opWrapperT; + configureWrapper(opWrapperT); // Start, run, and stop processing - exec() blocks this thread until OpenPose wrapper has finished op::log("Starting thread(s)...", op::Priority::High); 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 return 0; } catch (const std::exception& e) diff --git a/examples/tutorial_api_cpp/CMakeLists.txt b/examples/tutorial_api_cpp/CMakeLists.txt index 881b2b76..5e710a00 100644 --- a/examples/tutorial_api_cpp/CMakeLists.txt +++ b/examples/tutorial_api_cpp/CMakeLists.txt @@ -4,15 +4,17 @@ set(EXAMPLE_FILES 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) + 06_face_from_image.cpp + 07_hand_from_image.cpp + # 08_heatmaps_from_image.cpp + 09_asynchronous_custom_input.cpp + 10_asynchronous_custom_output.cpp + 11_asynchronous_custom_input_output_and_datum.cpp + 12_synchronous_custom_input.cpp + # 13_synchronous_custom_preprocessing.cpp + 14_synchronous_custom_postprocessing.cpp + 15_synchronous_custom_output.cpp + 16_synchronous_custom_all_and_datum.cpp) include(${CMAKE_SOURCE_DIR}/cmake/Utils.cmake) diff --git a/examples/tutorial_api_thread/2_thread_user_input_processing_output_and_datum.cpp b/examples/tutorial_api_thread/2_thread_user_input_processing_output_and_datum.cpp index c1ade142..36dd091a 100644 --- a/examples/tutorial_api_thread/2_thread_user_input_processing_output_and_datum.cpp +++ b/examples/tutorial_api_thread/2_thread_user_input_processing_output_and_datum.cpp @@ -159,7 +159,7 @@ public: // datumPtr->poseKeypoints: Array with the estimated pose if (datumsPtr != nullptr && !datumsPtr->empty()) { - cv::imshow("User worker GUI", datumsPtr->at(0)->cvOutputData); + cv::imshow(OPEN_POSE_NAME_AND_VERSION + " - Tutorial Thread API", 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); } diff --git a/include/openpose/thread/threadManager.hpp b/include/openpose/thread/threadManager.hpp index f00f4cc3..83f142e0 100644 --- a/include/openpose/thread/threadManager.hpp +++ b/include/openpose/thread/threadManager.hpp @@ -21,10 +21,19 @@ namespace op virtual ~ThreadManager(); + /** + * It sets the maximum number of elements in the queue. + * For maximum speed, set to a very large number, but the trade-off would be: + * - Latency will hugely increase. + * - The program might go out of RAM memory (so the computer might freeze). + * For minimum latency while keeping an optimal speed, set to -1, that will automatically + * detect the ideal number based on how many elements are connected to that queue. + * @param defaultMaxSizeQueues long long element with the maximum number of elements on the queue. + */ void setDefaultMaxSizeQueues(const long long defaultMaxSizeQueues = -1); - void add(const unsigned long long threadId, const std::vector& tWorkers, const unsigned long long queueInId, - const unsigned long long queueOutId); + void add(const unsigned long long threadId, const std::vector& tWorkers, + const unsigned long long queueInId, const unsigned long long queueOutId); void add(const unsigned long long threadId, const TWorker& tWorker, const unsigned long long queueInId, const unsigned long long queueOutId); diff --git a/include/openpose/wrapper/wrapper.hpp b/include/openpose/wrapper/wrapper.hpp index 54e5d34e..2383aabf 100644 --- a/include/openpose/wrapper/wrapper.hpp +++ b/include/openpose/wrapper/wrapper.hpp @@ -133,6 +133,17 @@ namespace op */ bool isRunning() const; + /** + * It sets the maximum number of elements in the queue. + * For maximum speed, set to a very large number, but the trade-off would be: + * - Latency will hugely increase. + * - The program might go out of RAM memory (so the computer might freeze). + * For minimum latency while keeping an optimal speed, set to -1, that will automatically + * detect the ideal number based on how many elements are connected to that queue. + * @param defaultMaxSizeQueues long long element with the maximum number of elements on the queue. + */ + void setDefaultMaxSizeQueues(const long long defaultMaxSizeQueues = -1); + /** * Emplace (move) an element on the first (input) queue. * Only valid if ThreadManagerMode::Asynchronous or ThreadManagerMode::AsynchronousIn. @@ -459,6 +470,19 @@ namespace op } } + template + void WrapperT::setDefaultMaxSizeQueues(const long long defaultMaxSizeQueues) + { + try + { + mThreadManager.setDefaultMaxSizeQueues(defaultMaxSizeQueues); + } + catch (const std::exception& e) + { + error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } + } + template bool WrapperT::tryEmplace(TDatumsSP& tDatums) { diff --git a/scripts/travis/run_tests.sh b/scripts/travis/run_tests.sh index f0017cba..54864386 100755 --- a/scripts/travis/run_tests.sh +++ b/scripts/travis/run_tests.sh @@ -11,11 +11,11 @@ if [[ $RUN_EXAMPLES == true ]] ; then echo " " echo "OpenPose demo..." - ./build/examples/openpose/openpose.bin --net_resolution -1x32 --image_dir examples/media/ --write_json output/ --write_images output/ --display 0 --render_pose 1 + ./build/examples/openpose/openpose.bin --image_dir examples/media/ --net_resolution -1x32 --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/ --write_images output/ --display 0 --render_pose 1 + ./build/examples/tutorial_add_module/1_custom_post_processing.bin --image_dir examples/media/ --net_resolution -1x32 --write_json output/ --write_images output/ --display 0 echo " " # # Note: Examples 1-2 require the whole OpenPose resolution (too much RAM memory) and the GUI @@ -25,58 +25,67 @@ if [[ $RUN_EXAMPLES == true ]] ; then # echo " " echo "Tutorial API C++: Example 3..." - ./build/examples/tutorial_api_cpp/03_keypoints_from_image.bin --no_display --net_resolution -1x32 --write_json output/ + ./build/examples/tutorial_api_cpp/03_keypoints_from_image.bin --net_resolution -1x32 --write_json output/ --write_images output/ --no_display echo " " echo "Tutorial API C++: Example 4..." - ./build/examples/tutorial_api_cpp/04_keypoints_from_images.bin --no_display --net_resolution -1x32 --write_json output/ + ./build/examples/tutorial_api_cpp/04_keypoints_from_images.bin --net_resolution -1x32 --write_json output/ --write_images output/ --no_display echo " " echo "Tutorial API C++: Example 5..." - ./build/examples/tutorial_api_cpp/05_keypoints_from_images_multi_gpu.bin --no_display --net_resolution -1x32 --write_json output/ + ./build/examples/tutorial_api_cpp/05_keypoints_from_images_multi_gpu.bin --net_resolution -1x32 --write_json output/ --write_images output/ --no_display + ./build/examples/tutorial_api_cpp/05_keypoints_from_images_multi_gpu.bin --net_resolution -1x32 --write_json output/ --write_images output/ --no_display --latency_is_irrelevant_and_computer_with_lots_of_ram echo " " echo "Tutorial API C++: Example 6..." - ./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 --render_pose 1 + ./build/examples/tutorial_api_cpp/06_face_from_image.bin --face_net_resolution 32x32 --write_json output/ --write_images output/ --no_display echo " " echo "Tutorial API C++: Example 7..." - ./build/examples/tutorial_api_cpp/07_asynchronous_custom_output.bin --no_display --net_resolution -1x32 --image_dir examples/media/ + ./build/examples/tutorial_api_cpp/07_hand_from_image.bin --hand_net_resolution 32x32 --write_json output/ --write_images output/ --no_display echo " " - echo "Tutorial API C++: Example 8..." - ./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 8..." + # ./build/examples/tutorial_api_cpp/08_heatmaps_from_image.bin --hand_net_resolution 32x32 --write_json output/ --write_images output/ --no_display + # echo " " echo "Tutorial API C++: Example 9..." - ./build/examples/tutorial_api_cpp/09_face_from_image.bin --no_display --face_net_resolution 32x32 + ./build/examples/tutorial_api_cpp/09_asynchronous_custom_input.bin --image_dir examples/media/ --net_resolution -1x32 --write_json output/ --write_images output/ --display 0 echo " " echo "Tutorial API C++: Example 10..." - ./build/examples/tutorial_api_cpp/10_hand_from_image.bin --no_display --hand_net_resolution 32x32 + ./build/examples/tutorial_api_cpp/10_asynchronous_custom_output.bin --image_dir examples/media/ --net_resolution -1x32 --write_json output/ --write_images output/ --no_display 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 --render_pose 1 + ./build/examples/tutorial_api_cpp/11_asynchronous_custom_input_output_and_datum.bin --image_dir examples/media/ --net_resolution -1x32 --write_json output/ --write_images output/ --no_display 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 --render_pose 1 + echo "Tutorial API C++: Example 12..." + ./build/examples/tutorial_api_cpp/12_synchronous_custom_input.bin --image_dir examples/media/ --net_resolution -1x32 --write_json output/ --write_images output/ --display 0 echo " " + # echo "Tutorial API C++: Example 13..." + # ./build/examples/tutorial_api_cpp/13_synchronous_custom_preprocessing.bin --image_dir examples/media/ --net_resolution -1x32 --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/ + ./build/examples/tutorial_api_cpp/14_synchronous_custom_postprocessing.bin --image_dir examples/media/ --net_resolution -1x32 --write_json output/ --write_images output/ --display 0 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/ + ./build/examples/tutorial_api_cpp/15_synchronous_custom_output.bin --image_dir examples/media/ --net_resolution -1x32 --write_json output/ --write_images output/ --no_display + echo " " + + echo "Tutorial API C++: Example 16..." + ./build/examples/tutorial_api_cpp/16_synchronous_custom_all_and_datum.bin --image_dir examples/media/ --net_resolution -1x32 --write_json output/ --write_images output/ --no_display 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/ --write_images output/ --display 0 --render_pose 1 + python openpose_python.py --image_dir ../../../examples/media/ --net_resolution -1x32 --write_json output/ --write_images output/ --display 0 echo " " # Note: All Python examples require GUI fi