diff --git a/doc/demo_overview.md b/doc/demo_overview.md index 7351ac46..413b740c 100644 --- a/doc/demo_overview.md +++ b/doc/demo_overview.md @@ -241,9 +241,9 @@ Each flag is divided into flag name, default value, and description. - DEFINE_string(write_video_3d, "", "Analogous to `--write_video`, but applied to the 3D output."); - DEFINE_string(write_video_adam, "", "Experimental, not available yet. Analogous to `--write_video`, but applied to Adam model."); - DEFINE_string(write_json, "", "Directory to write OpenPose output in JSON format. It includes body, hand, and face pose keypoints (2-D and 3-D), as well as pose candidates (if `--part_candidates` enabled)."); -- DEFINE_string(write_coco_json, "", "Full file path to write people pose data with JSON COCO validation format."); -- DEFINE_string(write_coco_foot_json, "", "Full file path to write people foot pose data with JSON COCO validation format."); -- DEFINE_int32(write_coco_json_variant, 0, "Currently, this option is experimental and only makes effect on car JSON generation. It selects the COCO variant for cocoJsonSaver."); +- DEFINE_string(write_coco_json, "", "Full file path to write people pose data with JSON COCO validation format. If foot, face, hands, etc. JSON is also desired (`--write_coco_json_variants`), they are saved with different file name suffix."); +- DEFINE_int32(write_coco_json_variants, 1, "Add 1 for body, add 2 for foot, 4 for face, and/or 8 for hands. Use 0 to use all the possible candidates. E.g., 7 would mean body+foot+face COCO JSON."); +- DEFINE_int32(write_coco_json_variant, 0, "Currently, this option is experimental and only makes effect on car JSON generation. It selects the COCO variant for cocoJsonSaver."); - DEFINE_string(write_heatmaps, "", "Directory to write body pose heatmaps in PNG format. At least 1 `add_heatmaps_X` flag must be enabled."); - DEFINE_string(write_heatmaps_format, "png", "File extension and format for `write_heatmaps`, analogous to `write_images_format`. For lossless compression, recommended `png` for integer `heatmaps_scale` and `float` for floating values."); - DEFINE_string(write_keypoint, "", "(Deprecated, use `write_json`) Directory to write the people pose keypoint data. Set format with `write_keypoint_format`."); diff --git a/doc/release_notes.md b/doc/release_notes.md index 18027bd5..fd14f24a 100644 --- a/doc/release_notes.md +++ b/doc/release_notes.md @@ -323,6 +323,7 @@ OpenPose Library - Release Notes 31. Removed boost::shared_ptr and caffe::Blob dependencies from the headers. No 3rdparty dependencies left on headers (except dim3 for CUDA). 32. Added Array `poseNetOutput` to Datum so that user can introduce his custom network output. 33. OpenPose will never provoke a core dumped or crash. Exceptions in threads (`errorWorker()` instead of `error()`) lead to stopping the threads and reporting the error from the main thread, while exceptions in destructors (`errorDestructor()` instead of `error()`) are reported with std::cerr but not thrown as std::exceptions. + 34. When reading a directory of images, they will be sorted in natural order (rather than regular sort). 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. @@ -339,6 +340,7 @@ OpenPose Library - Release Notes 11. Moved most sh scripts into the `scripts/` folder. Only models/getModels.sh and the `*.bat` files are kept under `models/` and `3rdparty/windows`. 12. 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. 13. Renamed intRound, charRound, etc. by positiveIntRound, positiveCharRound, etc. so that people can realize it is not safe for negative numbers. + 14. Replaced flag `--write_coco_foot_json` by `--write_coco_json_variants` in order to generalize to any COCO JSON format (i.e., hand, face, etc). 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/openpose/openpose.cpp b/examples/openpose/openpose.cpp index 0479e02e..fac94620 100755 --- a/examples/openpose/openpose.cpp +++ b/examples/openpose/openpose.cpp @@ -96,7 +96,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_add_module/1_custom_post_processing.cpp b/examples/tutorial_add_module/1_custom_post_processing.cpp index ecbc7ebe..85ee15e9 100644 --- a/examples/tutorial_add_module/1_custom_post_processing.cpp +++ b/examples/tutorial_add_module/1_custom_post_processing.cpp @@ -114,7 +114,7 @@ void configureWrapper(op::WrapperT& opWrapperT) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/03_keypoints_from_image.cpp b/examples/tutorial_api_cpp/03_keypoints_from_image.cpp index 0663f0bf..6ad50103 100644 --- a/examples/tutorial_api_cpp/03_keypoints_from_image.cpp +++ b/examples/tutorial_api_cpp/03_keypoints_from_image.cpp @@ -132,7 +132,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/04_keypoints_from_images.cpp b/examples/tutorial_api_cpp/04_keypoints_from_images.cpp index ab670bd0..5630876d 100644 --- a/examples/tutorial_api_cpp/04_keypoints_from_images.cpp +++ b/examples/tutorial_api_cpp/04_keypoints_from_images.cpp @@ -134,7 +134,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; 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 15144eb2..afa38c8c 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 @@ -140,7 +140,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/06_face_from_image.cpp b/examples/tutorial_api_cpp/06_face_from_image.cpp index 741e0393..ec8aefb5 100644 --- a/examples/tutorial_api_cpp/06_face_from_image.cpp +++ b/examples/tutorial_api_cpp/06_face_from_image.cpp @@ -135,7 +135,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/07_hand_from_image.cpp b/examples/tutorial_api_cpp/07_hand_from_image.cpp index 45221d39..6cc9d794 100644 --- a/examples/tutorial_api_cpp/07_hand_from_image.cpp +++ b/examples/tutorial_api_cpp/07_hand_from_image.cpp @@ -135,7 +135,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/08_heatmaps_from_image.cpp b/examples/tutorial_api_cpp/08_heatmaps_from_image.cpp index 270e2a60..76b67207 100644 --- a/examples/tutorial_api_cpp/08_heatmaps_from_image.cpp +++ b/examples/tutorial_api_cpp/08_heatmaps_from_image.cpp @@ -164,7 +164,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/09_keypoints_from_heatmaps.cpp b/examples/tutorial_api_cpp/09_keypoints_from_heatmaps.cpp index fbc7f004..07eccb0a 100644 --- a/examples/tutorial_api_cpp/09_keypoints_from_heatmaps.cpp +++ b/examples/tutorial_api_cpp/09_keypoints_from_heatmaps.cpp @@ -135,7 +135,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/10_asynchronous_custom_input.cpp b/examples/tutorial_api_cpp/10_asynchronous_custom_input.cpp index 88e48a4a..a64e5412 100644 --- a/examples/tutorial_api_cpp/10_asynchronous_custom_input.cpp +++ b/examples/tutorial_api_cpp/10_asynchronous_custom_input.cpp @@ -146,7 +146,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/11_asynchronous_custom_output.cpp b/examples/tutorial_api_cpp/11_asynchronous_custom_output.cpp index cc79230e..9d35f393 100644 --- a/examples/tutorial_api_cpp/11_asynchronous_custom_output.cpp +++ b/examples/tutorial_api_cpp/11_asynchronous_custom_output.cpp @@ -171,7 +171,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/12_asynchronous_custom_input_output_and_datum.cpp b/examples/tutorial_api_cpp/12_asynchronous_custom_input_output_and_datum.cpp index d6d88043..e7bd9254 100644 --- a/examples/tutorial_api_cpp/12_asynchronous_custom_input_output_and_datum.cpp +++ b/examples/tutorial_api_cpp/12_asynchronous_custom_input_output_and_datum.cpp @@ -243,7 +243,7 @@ void configureWrapper(op::WrapperT& opWrapperT) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/13_synchronous_custom_input.cpp b/examples/tutorial_api_cpp/13_synchronous_custom_input.cpp index c55846a6..95ae0629 100644 --- a/examples/tutorial_api_cpp/13_synchronous_custom_input.cpp +++ b/examples/tutorial_api_cpp/13_synchronous_custom_input.cpp @@ -159,7 +159,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/14_synchronous_custom_preprocessing.cpp b/examples/tutorial_api_cpp/14_synchronous_custom_preprocessing.cpp index f1ee1769..f86d7fe3 100644 --- a/examples/tutorial_api_cpp/14_synchronous_custom_preprocessing.cpp +++ b/examples/tutorial_api_cpp/14_synchronous_custom_preprocessing.cpp @@ -129,7 +129,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/15_synchronous_custom_postprocessing.cpp b/examples/tutorial_api_cpp/15_synchronous_custom_postprocessing.cpp index 584378a8..814f8a1a 100644 --- a/examples/tutorial_api_cpp/15_synchronous_custom_postprocessing.cpp +++ b/examples/tutorial_api_cpp/15_synchronous_custom_postprocessing.cpp @@ -130,7 +130,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/16_synchronous_custom_output.cpp b/examples/tutorial_api_cpp/16_synchronous_custom_output.cpp index a5d22e5b..0c88fdeb 100644 --- a/examples/tutorial_api_cpp/16_synchronous_custom_output.cpp +++ b/examples/tutorial_api_cpp/16_synchronous_custom_output.cpp @@ -186,7 +186,7 @@ void configureWrapper(op::Wrapper& opWrapper) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/examples/tutorial_api_cpp/17_synchronous_custom_all_and_datum.cpp b/examples/tutorial_api_cpp/17_synchronous_custom_all_and_datum.cpp index 1c855929..6fedf3dc 100644 --- a/examples/tutorial_api_cpp/17_synchronous_custom_all_and_datum.cpp +++ b/examples/tutorial_api_cpp/17_synchronous_custom_all_and_datum.cpp @@ -299,7 +299,7 @@ void configureWrapper(op::WrapperT& opWrapperT) // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/include/openpose/filestream/cocoJsonSaver.hpp b/include/openpose/filestream/cocoJsonSaver.hpp index 1dad7732..f4d5cc35 100644 --- a/include/openpose/filestream/cocoJsonSaver.hpp +++ b/include/openpose/filestream/cocoJsonSaver.hpp @@ -23,7 +23,8 @@ namespace op */ explicit CocoJsonSaver( const std::string& filePathToSave, const PoseModel poseModel, const bool humanReadable = true, - const CocoJsonFormat cocoJsonFormat = CocoJsonFormat::Body, const int mCocoJsonVariant = 0); + const int cocoJsonVariants = 1, const CocoJsonFormat cocoJsonFormat = CocoJsonFormat::Body, + const int cocoJsonVariant = 0); virtual ~CocoJsonSaver(); @@ -33,10 +34,8 @@ namespace op private: const PoseModel mPoseModel; - const CocoJsonFormat mCocoJsonFormat; const int mCocoJsonVariant; - JsonOfstream mJsonOfstream; - bool mFirstElementAdded; + std::vector> mJsonOfstreams; DELETE_COPY(CocoJsonSaver); }; diff --git a/include/openpose/filestream/enumClasses.hpp b/include/openpose/filestream/enumClasses.hpp index ed0fef5e..ff8e984f 100644 --- a/include/openpose/filestream/enumClasses.hpp +++ b/include/openpose/filestream/enumClasses.hpp @@ -14,7 +14,8 @@ namespace op enum class CocoJsonFormat : unsigned char { Body, - Hand, + Hand21, + Hand42, Face, Foot, Car, diff --git a/include/openpose/filestream/jsonOfstream.hpp b/include/openpose/filestream/jsonOfstream.hpp index bb5ea804..d9c01007 100644 --- a/include/openpose/filestream/jsonOfstream.hpp +++ b/include/openpose/filestream/jsonOfstream.hpp @@ -11,6 +11,21 @@ namespace op public: explicit JsonOfstream(const std::string& filePath, const bool humanReadable = true); + /** + * Move constructor. + * It destroys the original JsonOfstream to be moved. + * @param array JsonOfstream to be moved. + */ + JsonOfstream(JsonOfstream&& jsonOfstream); + + /** + * Move assignment. + * Similar to JsonOfstream(JsonOfstream&& jsonOfstream). + * @param array JsonOfstream to be moved. + * @return The resulting JsonOfstream. + */ + JsonOfstream& operator=(JsonOfstream&& jsonOfstream); + virtual ~JsonOfstream(); void objectOpen(); @@ -39,7 +54,7 @@ namespace op void enter(); private: - const bool mHumanReadable; + bool mHumanReadable; long long mBracesCounter; long long mBracketsCounter; std::ofstream mOfstream; diff --git a/include/openpose/flags.hpp b/include/openpose/flags.hpp index 7dcb74d7..e47dedbe 100644 --- a/include/openpose/flags.hpp +++ b/include/openpose/flags.hpp @@ -243,9 +243,12 @@ DEFINE_string(write_video_3d, "", "Analogous to `--write_v DEFINE_string(write_video_adam, "", "Experimental, not available yet. Analogous to `--write_video`, but applied to Adam model."); DEFINE_string(write_json, "", "Directory to write OpenPose output in JSON format. It includes body, hand, and face pose" " keypoints (2-D and 3-D), as well as pose candidates (if `--part_candidates` enabled)."); -DEFINE_string(write_coco_json, "", "Full file path to write people pose data with JSON COCO validation format."); -DEFINE_string(write_coco_foot_json, "", "Full file path to write people foot pose data with JSON COCO validation format."); -DEFINE_int32(write_coco_json_variant, 0, "Currently, this option is experimental and only makes effect on car JSON generation. It" +DEFINE_string(write_coco_json, "", "Full file path to write people pose data with JSON COCO validation format. If foot, face," + " hands, etc. JSON is also desired (`--write_coco_json_variants`), they are saved with" + " different file name suffix."); +DEFINE_int32(write_coco_json_variants, 1, "Add 1 for body, add 2 for foot, 4 for face, and/or 8 for hands. Use 0 to use all the" + " possible candidates. E.g., 7 would mean body+foot+face COCO JSON."); +DEFINE_int32(write_coco_json_variant, 0, "Currently, this option is experimental and only makes effect on car JSON generation. It" " selects the COCO variant for cocoJsonSaver."); DEFINE_string(write_heatmaps, "", "Directory to write body pose heatmaps in PNG format. At least 1 `add_heatmaps_X` flag" " must be enabled."); diff --git a/include/openpose/wrapper/wrapperAuxiliary.hpp b/include/openpose/wrapper/wrapperAuxiliary.hpp index 6388fdc7..ac02054e 100644 --- a/include/openpose/wrapper/wrapperAuxiliary.hpp +++ b/include/openpose/wrapper/wrapperAuxiliary.hpp @@ -667,7 +667,7 @@ namespace op outputWs.emplace_back(std::make_shared>(keypointSaver)); } log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__); - // Write OpenPose output data on disk in json format (body/hand/face keypoints, body part locations if + // Write OpenPose output data on disk in JSON format (body/hand/face keypoints, body part locations if // enabled, etc.) if (!writeJsonCleaned.empty()) { @@ -676,7 +676,7 @@ namespace op outputWs.emplace_back(std::make_shared>(peopleJsonSaver)); } log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__); - // Write people pose data on disk (COCO validation json format) + // Write people pose/foot/face/hand/etc. data on disk (COCO validation JSON format) if (!wrapperStructOutput.writeCocoJson.empty()) { log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__); @@ -684,6 +684,7 @@ namespace op const auto humanFormat = true; const auto cocoJsonSaver = std::make_shared( wrapperStructOutput.writeCocoJson, wrapperStructPose.poseModel, humanFormat, + wrapperStructOutput.writeCocoJsonVariants, (wrapperStructPose.poseModel != PoseModel::CAR_22 && wrapperStructPose.poseModel != PoseModel::CAR_12 ? CocoJsonFormat::Body : CocoJsonFormat::Car), @@ -691,16 +692,6 @@ namespace op outputWs.emplace_back(std::make_shared>(cocoJsonSaver)); } log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__); - // Write people foot pose data on disk (COCO validation json format for foot data) - if (!wrapperStructOutput.writeCocoFootJson.empty()) - { - // If humanFormat: bigger size (& maybe slower to process), but easier for user to read it - const auto humanFormat = true; - const auto cocoJsonSaver = std::make_shared( - wrapperStructOutput.writeCocoFootJson, wrapperStructPose.poseModel, humanFormat, - CocoJsonFormat::Foot); - outputWs.emplace_back(std::make_shared>(cocoJsonSaver)); - } log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__); // Write frames as desired image format on hard disk if (!writeImagesCleaned.empty()) diff --git a/include/openpose/wrapper/wrapperStructOutput.hpp b/include/openpose/wrapper/wrapperStructOutput.hpp index 04b2489b..91470ce7 100644 --- a/include/openpose/wrapper/wrapperStructOutput.hpp +++ b/include/openpose/wrapper/wrapperStructOutput.hpp @@ -51,9 +51,11 @@ namespace op std::string writeCocoJson; /** - * Analogous to writeCocoJson but for foot keypoints. + * It selects the COCO variants for cocoJsonSaver. + * Add 1 for body, add 2 for foot, 4 for face, and/or 8 for hands. Use 0 to use all the possible candidates. + * E.g., 7 would mean body+foot+face COCO JSON.. */ - std::string writeCocoFootJson; + int writeCocoJsonVariants; /** * Experimental option (only makes effect on car JSON generation). @@ -148,7 +150,7 @@ namespace op WrapperStructOutput( const double verbose = -1, const std::string& writeKeypoint = "", const DataFormat writeKeypointFormat = DataFormat::Xml, const std::string& writeJson = "", - const std::string& writeCocoJson = "", const std::string& writeCocoFootJson = "", + const std::string& writeCocoJson = "", const int writeCocoJsonVariants = 1, const int writeCocoJsonVariant = 1, const std::string& writeImages = "", const std::string& writeImagesFormat = "", const std::string& writeVideo = "", const double writeVideoFps = -1., const bool writeVideoWithAudio = false, diff --git a/python/openpose/openpose_python.cpp b/python/openpose/openpose_python.cpp index e1710b34..99761964 100644 --- a/python/openpose/openpose_python.cpp +++ b/python/openpose/openpose_python.cpp @@ -129,7 +129,7 @@ public: // 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_json, FLAGS_write_coco_json, FLAGS_write_coco_json_variants, 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}; diff --git a/scripts/tests/pose_accuracy_coco_val.sh b/scripts/tests/pose_accuracy_coco_val.sh index 17133cf0..e45d6848 100755 --- a/scripts/tests/pose_accuracy_coco_val.sh +++ b/scripts/tests/pose_accuracy_coco_val.sh @@ -16,14 +16,14 @@ JSON_FOLDER=../evaluation/coco_val_jsons/ OP_BIN=./build/examples/openpose/openpose.bin # 1 scale -$OP_BIN --image_dir $IMAGE_FOLDER --display 0 --render_pose 0 --cli_verbose 0.2 --write_coco_json ${JSON_FOLDER}1.json --write_coco_foot_json ${JSON_FOLDER}1_foot.json -# $OP_BIN --image_dir $IMAGE_FOLDER --display 0 --render_pose 0 --cli_verbose 0.2 --write_coco_json ${JSON_FOLDER}1_max.json --write_coco_foot_json ${JSON_FOLDER}1_foot_max.json \ +$OP_BIN --image_dir $IMAGE_FOLDER --display 0 --render_pose 0 --cli_verbose 0.2 --write_coco_json ${JSON_FOLDER}1.json --write_coco_json_variants 3 +# $OP_BIN --image_dir $IMAGE_FOLDER --display 0 --render_pose 0 --cli_verbose 0.2 --write_coco_json ${JSON_FOLDER}1_max.json --write_coco_json_variants 3 \ # --maximize_positives # # 4 scales -# $OP_BIN --image_dir $IMAGE_FOLDER --display 0 --render_pose 0 --cli_verbose 0.2 --write_coco_json ${JSON_FOLDER}1_4.json --write_coco_foot_json ${JSON_FOLDER}4_foot.json \ +# $OP_BIN --image_dir $IMAGE_FOLDER --display 0 --render_pose 0 --cli_verbose 0.2 --write_coco_json ${JSON_FOLDER}1_4.json --write_coco_json_variants 3 \ # --scale_number 4 --scale_gap 0.25 --net_resolution "1312x736" -# $OP_BIN --image_dir $IMAGE_FOLDER --display 0 --render_pose 0 --cli_verbose 0.2 --write_coco_json ${JSON_FOLDER}1_4_max.json --write_coco_foot_json ${JSON_FOLDER}4_foot_max.json \ +# $OP_BIN --image_dir $IMAGE_FOLDER --display 0 --render_pose 0 --cli_verbose 0.2 --write_coco_json ${JSON_FOLDER}1_4_max.json --write_coco_json_variants 3 \ # --scale_number 4 --scale_gap 0.25 --net_resolution "1312x736" --maximize_positives # # \ # # --model_pose BODY_23 --model_folder ${JSON_FOLDER} diff --git a/scripts/tests/pose_accuracy_coco_val_foot.sh b/scripts/tests/pose_accuracy_coco_val_foot.sh deleted file mode 100755 index f8efd3dc..00000000 --- a/scripts/tests/pose_accuracy_coco_val_foot.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - - - -# Script for internal use. We might completely change it continuously and we will not answer questions about it. - -clear && clear - -# USAGE EXAMPLE -# See ./scripts/tests/pose_accuracy_coco_test.sh - -# Parameters -IMAGE_FOLDER=/home/gines/devel/images/val2017/ -JSON_FOLDER=../evaluation/coco_val_jsons/ -OP_BIN=./build/examples/openpose/openpose.bin - - # 1 scale -$OP_BIN --image_dir $IMAGE_FOLDER --write_coco_foot_json ${JSON_FOLDER}1_foot.json --write_coco_json ${JSON_FOLDER}1.json --display 0 --render_pose 0 - -# # 4 scales -# $OP_BIN --model_pose BODY_25 --image_dir $IMAGE_FOLDER --write_coco_foot_json ${JSON_FOLDER}1_4_foot.json --display 0 --render_pose 0 --scale_number 4 --scale_gap 0.25 --net_resolution "1312x736" diff --git a/src/openpose/3d/cameraParameterReader.cpp b/src/openpose/3d/cameraParameterReader.cpp index f3519413..e6b6b626 100644 --- a/src/openpose/3d/cameraParameterReader.cpp +++ b/src/openpose/3d/cameraParameterReader.cpp @@ -41,12 +41,14 @@ namespace op // Add extrinsics if not empty if (!cameraExtrinsics.empty()) mCameraExtrinsics.emplace_back(cameraExtrinsics.clone()); + else + mCameraExtrinsics.emplace_back(cv::Mat::eye(3, 4, cameraIntrinsics.type())); // Add extrinsics (initial) if not empty if (!cameraExtrinsicsInitial.empty()) mCameraExtrinsicsInitial.emplace_back(cameraExtrinsicsInitial.clone()); // Otherwise, add cv::eye else - mCameraExtrinsics.emplace_back(cv::Mat::eye(3, 4, cameraIntrinsics.type())); + mCameraExtrinsicsInitial.emplace_back(cv::Mat::eye(3, 4, cameraIntrinsics.type())); mCameraMatrices.emplace_back(mCameraIntrinsics.back() * mCameraExtrinsics.back()); // Undistortion cv::Mats mRemoveDistortionMaps1.resize(getNumberCameras()); diff --git a/src/openpose/filestream/cocoJsonSaver.cpp b/src/openpose/filestream/cocoJsonSaver.cpp index d35d4f6a..825f7eb7 100644 --- a/src/openpose/filestream/cocoJsonSaver.cpp +++ b/src/openpose/filestream/cocoJsonSaver.cpp @@ -1,38 +1,69 @@ #include // std::iota #include +#include #include #include namespace op { CocoJsonSaver::CocoJsonSaver(const std::string& filePathToSave, const PoseModel poseModel, - const bool humanReadable, const CocoJsonFormat cocoJsonFormat, - const int cocoJsonVariant) : + const bool humanReadable, const int cocoJsonVariants, + const CocoJsonFormat cocoJsonFormat, const int cocoJsonVariant) : mPoseModel{poseModel}, - mCocoJsonFormat{cocoJsonFormat}, - mCocoJsonVariant{cocoJsonVariant}, - mJsonOfstream{filePathToSave, humanReadable}, - mFirstElementAdded{false} + mCocoJsonVariant{cocoJsonVariant} { try { - // Sanity check + // Sanity checks if (filePathToSave.empty()) error("Empty path given as output file path for saving COCO JSON format.", __LINE__, __FUNCTION__, __FILE__); + if (cocoJsonVariants >= 32) + error("Unkown value for cocoJsonFormat (flag `--write_coco_json_variants`).", + __LINE__, __FUNCTION__, __FILE__); + // Open mJsonOfstreams + const auto filePath = getFullFilePathNoExtension(filePathToSave); + const auto extension = getFileExtension(filePathToSave); + // Body/cars + if (cocoJsonVariants % 2 == 1 || cocoJsonVariants < 1) + mJsonOfstreams.emplace_back( + std::make_tuple(JsonOfstream{filePathToSave, humanReadable}, cocoJsonFormat, false)); + // Foot + if ((cocoJsonVariants/2) % 2 == 1 || cocoJsonVariants < 1) + mJsonOfstreams.emplace_back( + std::make_tuple(JsonOfstream{filePath+"_foot."+extension, humanReadable}, CocoJsonFormat::Foot, + false)); + // Face + if ((cocoJsonVariants/4) % 2 == 1 || cocoJsonVariants < 1) + mJsonOfstreams.emplace_back( + std::make_tuple(JsonOfstream{filePath+"_face."+extension, humanReadable}, CocoJsonFormat::Face, + false)); + // Hand21 + if ((cocoJsonVariants/8) % 2 == 1 || cocoJsonVariants < 1) + mJsonOfstreams.emplace_back( + std::make_tuple(JsonOfstream{filePath+"_hand21."+extension, humanReadable}, CocoJsonFormat::Hand21, + false)); + // Hand42 + if ((cocoJsonVariants/16) % 2 == 1 || cocoJsonVariants < 1) + mJsonOfstreams.emplace_back( + std::make_tuple(JsonOfstream{filePath+"_hand42."+extension, humanReadable}, CocoJsonFormat::Hand42, + false)); // Open array - mJsonOfstream.arrayOpen(); + for (auto& jsonOfstream : mJsonOfstreams) + std::get<0>(jsonOfstream).arrayOpen(); } catch (const std::exception& e) { error(e.what(), __LINE__, __FUNCTION__, __FILE__); } } + CocoJsonSaver::~CocoJsonSaver() { try { - mJsonOfstream.arrayClose(); + for (auto& jsonOfstream : mJsonOfstreams) + std::get<0>(jsonOfstream).arrayClose(); } catch (const std::exception& e) { @@ -54,153 +85,171 @@ namespace op if (numberPeople > 0) { const auto numberBodyParts = poseKeypoints.getSize(1); - // Get indexesInCocoOrder - std::vector indexesInCocoOrder; - // Body/car - auto imageId = getLastNumber(imageName); - if (mCocoJsonFormat == CocoJsonFormat::Body) + // Iterate over all JsonOfstreams + for (auto& jsonOfstreamAndFormat : mJsonOfstreams) { - // Body - if (numberBodyParts == 23) - indexesInCocoOrder = std::vector{0, 14,13,16,15, 4,1,5,2,6, 3,10,7,11, 8, 12, 9}; - else if (numberBodyParts == 18) - indexesInCocoOrder = std::vector{0, 15,14,17,16, 5,2,6,3,7, 4,11,8,12, 9, 13,10}; - else if (mPoseModel == PoseModel::BODY_25B || mPoseModel == PoseModel::BODY_95 - || mPoseModel == PoseModel::BODY_135) + auto& jsonOfstream = std::get<0>(jsonOfstreamAndFormat); + const auto cocoJsonFormat = std::get<1>(jsonOfstreamAndFormat); + auto& firstElementAdded = std::get<2>(jsonOfstreamAndFormat); + // Get indexesInCocoOrder + std::vector indexesInCocoOrder; + // Body/car + auto imageId = frameNumber; + if (cocoJsonFormat == CocoJsonFormat::Body) { - indexesInCocoOrder = std::vector(17); - std::iota(indexesInCocoOrder.begin(), indexesInCocoOrder.end(), 0); - } - else if (numberBodyParts == 19 || numberBodyParts == 25 || numberBodyParts == 59) - indexesInCocoOrder = std::vector{0, 16,15,18,17, 5,2,6,3,7, 4,12,9,13,10, 14,11}; - // else if (numberBodyParts == 23) - // indexesInCocoOrder = std::vector{18,21,19,22,20, 4,1,5,2,6, 3,13,8,14, 9, 15,10}; - } - // Hand - else if (mCocoJsonFormat == CocoJsonFormat::Hand) - { - imageId = frameNumber; - if (numberBodyParts == 135) - { - indexesInCocoOrder = std::vector(42); - indexesInCocoOrder[0] = 9; - std::iota(indexesInCocoOrder.begin()+1, indexesInCocoOrder.end(), H135); - indexesInCocoOrder[21] = 10; - std::iota(indexesInCocoOrder.begin()+2, indexesInCocoOrder.end(), H135+20); - } - } - // Face - else if (mCocoJsonFormat == CocoJsonFormat::Face) - { - imageId = frameNumber; - if (numberBodyParts == 135) - { - indexesInCocoOrder = std::vector(70); - std::iota(indexesInCocoOrder.begin(), indexesInCocoOrder.end(), F135); - } - } - // Foot - else if (mCocoJsonFormat == CocoJsonFormat::Foot) - { - if (numberBodyParts == 25 || numberBodyParts > 60) - indexesInCocoOrder = std::vector{19,20,21, 22,23,24}; - else if (numberBodyParts == 23) - indexesInCocoOrder = std::vector{17,18,19, 20,21,22}; - } - // Car - else if (mCocoJsonFormat == CocoJsonFormat::Car) - { - // Car12 - if (numberBodyParts == 12) - indexesInCocoOrder = std::vector{0,1,2,3, 4,5,6,7, 8, 8,9,10,11, 11}; - // Car22 - else if (numberBodyParts == 22) - { - // Dataset 1 - if (mCocoJsonVariant == 0) - indexesInCocoOrder = std::vector{0,1,2,3, 6,7, 12,13,14,15, 16,17}; - // Dataset 2 - else if (mCocoJsonVariant == 1) - indexesInCocoOrder = std::vector{0,1,2,3, 6,7, 12,13,14,15, 20,21}; - // Dataset 3 - else if (mCocoJsonVariant == 2) - for (auto i = 0 ; i < 20 ; i++) - indexesInCocoOrder.emplace_back(i); - } - } - // Sanity check - if (indexesInCocoOrder.empty()) - error("Invalid number of body parts (" + std::to_string(numberBodyParts) + ").", - __LINE__, __FUNCTION__, __FILE__); - // Save on JSON file - for (auto person = 0 ; person < numberPeople ; person++) - { - bool foundAtLeast1Keypoint = true; - // Foot - if (mCocoJsonFormat == CocoJsonFormat::Foot) - { - // At least 1 valid keypoint? - foundAtLeast1Keypoint = false; - for (auto bodyPart = 0u ; bodyPart < indexesInCocoOrder.size() ; bodyPart++) + imageId = getLastNumber(imageName); + // Body + if (numberBodyParts == 23) + indexesInCocoOrder = std::vector{0, 14,13,16,15, 4,1,5,2,6, 3,10,7,11, 8, 12, 9}; + else if (numberBodyParts == 18) + indexesInCocoOrder = std::vector{0, 15,14,17,16, 5,2,6,3,7, 4,11,8,12, 9, 13,10}; + else if (mPoseModel == PoseModel::BODY_25B || mPoseModel == PoseModel::BODY_95 + || mPoseModel == PoseModel::BODY_135) { - const auto finalIndex = 3*(person*numberBodyParts + indexesInCocoOrder.at(bodyPart)); - const auto validPoint = (poseKeypoints[finalIndex+2] > 0.f); - if (validPoint) + indexesInCocoOrder = std::vector(17); + std::iota(indexesInCocoOrder.begin(), indexesInCocoOrder.end(), 0); + } + else if (numberBodyParts == 19 || numberBodyParts == 25 || numberBodyParts == 59) + indexesInCocoOrder = std::vector{0, 16,15,18,17, 5,2,6,3,7, 4,12,9,13,10, 14,11}; + // else if (numberBodyParts == 23) + // indexesInCocoOrder = std::vector{18,21,19,22,20, 4,1,5,2,6, 3,13,8,14, 9, 15,10}; + } + // Foot + else if (cocoJsonFormat == CocoJsonFormat::Foot) + { + imageId = getLastNumber(imageName); + if (numberBodyParts == 25 || numberBodyParts > 60) + indexesInCocoOrder = std::vector{19,20,21, 22,23,24}; + else if (numberBodyParts == 23) + indexesInCocoOrder = std::vector{17,18,19, 20,21,22}; + } + // Face + else if (cocoJsonFormat == CocoJsonFormat::Face) + { + if (numberBodyParts == 135) + { + indexesInCocoOrder = std::vector(70); + std::iota(indexesInCocoOrder.begin(), indexesInCocoOrder.end(), F135); + } + } + // Hand21 + else if (cocoJsonFormat == CocoJsonFormat::Hand21) + { + if (numberBodyParts == 135) + { + indexesInCocoOrder = std::vector(21); + indexesInCocoOrder[0] = 10; + std::iota(indexesInCocoOrder.begin()+1, indexesInCocoOrder.end(), H135+20); + } + } + // Hand42 + else if (cocoJsonFormat == CocoJsonFormat::Hand42) + { + if (numberBodyParts == 135) + { + indexesInCocoOrder = std::vector(42); + indexesInCocoOrder[0] = 9; + std::iota(indexesInCocoOrder.begin()+1, indexesInCocoOrder.end(), H135); + indexesInCocoOrder[21] = 10; + std::iota(indexesInCocoOrder.begin()+22, indexesInCocoOrder.end(), H135+20); + } + } + // Car + else if (cocoJsonFormat == CocoJsonFormat::Car) + { + imageId = getLastNumber(imageName); + // Car12 + if (numberBodyParts == 12) + indexesInCocoOrder = std::vector{0,1,2,3, 4,5,6,7, 8, 8,9,10,11, 11}; + // Car22 + else if (numberBodyParts == 22) + { + // Dataset 1 + if (mCocoJsonVariant == 0) + indexesInCocoOrder = std::vector{0,1,2,3, 6,7, 12,13,14,15, 16,17}; + // Dataset 2 + else if (mCocoJsonVariant == 1) + indexesInCocoOrder = std::vector{0,1,2,3, 6,7, 12,13,14,15, 20,21}; + // Dataset 3 + else if (mCocoJsonVariant == 2) + for (auto i = 0 ; i < 20 ; i++) + indexesInCocoOrder.emplace_back(i); + } + } + // Sanity check + if (indexesInCocoOrder.empty()) + error("Invalid number of body parts (" + std::to_string(numberBodyParts) + ").", + __LINE__, __FUNCTION__, __FILE__); + // Save on JSON file + for (auto person = 0 ; person < numberPeople ; person++) + { + bool foundAtLeast1Keypoint = true; + // Foot + if (cocoJsonFormat == CocoJsonFormat::Foot) + { + // At least 1 valid keypoint? + foundAtLeast1Keypoint = false; + for (auto bodyPart = 0u ; bodyPart < indexesInCocoOrder.size() ; bodyPart++) { - foundAtLeast1Keypoint = true; - break; + const auto finalIndex = 3*(person*numberBodyParts + indexesInCocoOrder.at(bodyPart)); + const auto validPoint = (poseKeypoints[finalIndex+2] > 0.f); + if (validPoint) + { + foundAtLeast1Keypoint = true; + break; + } } } - } - if (foundAtLeast1Keypoint) - { - // Comma at any moment but first element - if (mFirstElementAdded) + if (foundAtLeast1Keypoint) { - mJsonOfstream.comma(); - mJsonOfstream.enter(); + // Comma at any moment but first element + if (firstElementAdded) + { + jsonOfstream.comma(); + jsonOfstream.enter(); + } + else + firstElementAdded = true; + + // New element + jsonOfstream.objectOpen(); + + // image_id + jsonOfstream.key("image_id"); + jsonOfstream.plainText(imageId); + jsonOfstream.comma(); + + // category_id + jsonOfstream.key("category_id"); + jsonOfstream.plainText("1"); + jsonOfstream.comma(); + + // keypoints - i.e., poseKeypoints + jsonOfstream.key("keypoints"); + jsonOfstream.arrayOpen(); + for (auto bodyPart = 0u ; bodyPart < indexesInCocoOrder.size() ; bodyPart++) + { + const auto finalIndex = 3*(person*numberBodyParts + indexesInCocoOrder.at(bodyPart)); + const auto validPoint = (poseKeypoints[finalIndex+2] > 0.f); + jsonOfstream.plainText(validPoint ? poseKeypoints[finalIndex] : -1.f); + jsonOfstream.comma(); + jsonOfstream.plainText(validPoint ? poseKeypoints[finalIndex+1] : -1.f); + jsonOfstream.comma(); + jsonOfstream.plainText(validPoint ? 1 : 0); + // jsonOfstream.plainText(poseKeypoints[finalIndex+2]); // For debugging + if (bodyPart < indexesInCocoOrder.size() - 1u) + jsonOfstream.comma(); + } + jsonOfstream.arrayClose(); + jsonOfstream.comma(); + + // score + jsonOfstream.key("score"); + jsonOfstream.plainText(poseScores[person]); + + jsonOfstream.objectClose(); } - else - mFirstElementAdded = true; - - // New element - mJsonOfstream.objectOpen(); - - // image_id - mJsonOfstream.key("image_id"); - mJsonOfstream.plainText(imageId); - mJsonOfstream.comma(); - - // category_id - mJsonOfstream.key("category_id"); - mJsonOfstream.plainText("1"); - mJsonOfstream.comma(); - - // keypoints - i.e., poseKeypoints - mJsonOfstream.key("keypoints"); - mJsonOfstream.arrayOpen(); - for (auto bodyPart = 0u ; bodyPart < indexesInCocoOrder.size() ; bodyPart++) - { - const auto finalIndex = 3*(person*numberBodyParts + indexesInCocoOrder.at(bodyPart)); - const auto validPoint = (poseKeypoints[finalIndex+2] > 0.f); - mJsonOfstream.plainText(validPoint ? poseKeypoints[finalIndex] : -1.f); - mJsonOfstream.comma(); - mJsonOfstream.plainText(validPoint ? poseKeypoints[finalIndex+1] : -1.f); - mJsonOfstream.comma(); - mJsonOfstream.plainText(validPoint ? 1 : 0); - // mJsonOfstream.plainText(poseKeypoints[finalIndex+2]); // For debugging - if (bodyPart < indexesInCocoOrder.size() - 1u) - mJsonOfstream.comma(); - } - mJsonOfstream.arrayClose(); - mJsonOfstream.comma(); - - // score - mJsonOfstream.key("score"); - mJsonOfstream.plainText(poseScores[person]); - - mJsonOfstream.objectClose(); } } } diff --git a/src/openpose/filestream/jsonOfstream.cpp b/src/openpose/filestream/jsonOfstream.cpp index 81b7c4ea..61a63fd9 100644 --- a/src/openpose/filestream/jsonOfstream.cpp +++ b/src/openpose/filestream/jsonOfstream.cpp @@ -37,6 +37,39 @@ namespace op } } + JsonOfstream::JsonOfstream(JsonOfstream&& jsonOfstream) : + mHumanReadable{jsonOfstream.mHumanReadable}, + mBracesCounter{jsonOfstream.mBracesCounter}, + mBracketsCounter{jsonOfstream.mBracketsCounter} + { + try + { + std::swap(mOfstream, jsonOfstream.mOfstream); + } + catch (const std::exception& e) + { + error(e.what(), __LINE__, __FUNCTION__, __FILE__); + } + } + + JsonOfstream& JsonOfstream::operator=(JsonOfstream&& jsonOfstream) + { + try + { + mHumanReadable = jsonOfstream.mHumanReadable; + mBracesCounter = jsonOfstream.mBracesCounter; + mBracketsCounter = jsonOfstream.mBracketsCounter; + std::swap(mOfstream, jsonOfstream.mOfstream); + // Return + return *this; + } + catch (const std::exception& e) + { + error(e.what(), __LINE__, __FUNCTION__, __FILE__); + return *this; + } + } + JsonOfstream::~JsonOfstream() { try diff --git a/src/openpose/unity/unityBinding.cpp b/src/openpose/unity/unityBinding.cpp index f0f0f721..24d26ed1 100644 --- a/src/openpose/unity/unityBinding.cpp +++ b/src/openpose/unity/unityBinding.cpp @@ -636,7 +636,7 @@ namespace op OP_API void _OPConfigureOutput( double verbose, char* writeKeypoint, uchar writeKeypointFormat, // DataFormat - char* writeJson, char* writeCocoJson, char* writeCocoFootJson, int writeCocoJsonVariant, char* writeImages, + char* writeJson, char* writeCocoJson, int writeCocoJsonVariants, int writeCocoJsonVariant, char* writeImages, char* writeImagesFormat, char* writeVideo, double writeVideoFps, bool writeVideoWithAudio, char* writeHeatMaps, char* writeHeatMapsFormat, char* writeVideo3D, char* writeVideoAdam, char* writeBvh, char* udpHost, char* udpPort) @@ -645,7 +645,7 @@ namespace op { spWrapperStructOutput = std::make_shared( verbose, writeKeypoint, (DataFormat) writeKeypointFormat, writeJson, writeCocoJson, - writeCocoFootJson, writeCocoJsonVariant, writeImages, writeImagesFormat, writeVideo, writeVideoFps, + writeCocoJsonVariants, writeCocoJsonVariant, writeImages, writeImagesFormat, writeVideo, writeVideoFps, writeVideoWithAudio, writeHeatMaps, writeHeatMapsFormat, writeVideo3D, writeVideoAdam, writeBvh, udpHost, udpPort); } diff --git a/src/openpose/utilities/fileSystem.cpp b/src/openpose/utilities/fileSystem.cpp index 314ba1a7..c66bd6ff 100644 --- a/src/openpose/utilities/fileSystem.cpp +++ b/src/openpose/utilities/fileSystem.cpp @@ -13,6 +13,39 @@ namespace op { + bool compareNat(const std::string& a, const std::string& b) + { + if (a.empty()) + return true; + else if (b.empty()) + return false; + else if (std::isdigit(a[0]) && !std::isdigit(b[0])) + return true; + else if (!std::isdigit(a[0]) && std::isdigit(b[0])) + return false; + else if (!std::isdigit(a[0]) && !std::isdigit(b[0])) + { + if (std::toupper(a[0]) == std::toupper(b[0])) + return compareNat(a.substr(1), b.substr(1)); + return (std::toupper(a[0]) < std::toupper(b[0])); + } + + // Both strings begin with digit --> parse both numbers + std::istringstream issa(a); + std::istringstream issb(b); + int ia, ib; + issa >> ia; + issb >> ib; + if (ia != ib) + return ia < ib; + + // Numbers are the same --> remove numbers and recurse + std::string anew, bnew; + std::getline(issa, anew); + std::getline(issb, bnew); + return (compareNat(anew, bnew)); + } + void makeDirectory(const std::string& directoryPath) { try @@ -321,8 +354,10 @@ namespace op specificExtensionPaths.emplace_back(filePath); std::swap(filePaths, specificExtensionPaths); } - // Sort alphabetically - std::sort(filePaths.begin(), filePaths.end()); + // // Sort alphabetically + // std::sort(filePaths.begin(), filePaths.end()); + // Natural sort + std::sort(filePaths.begin(), filePaths.end(), compareNat); // Return result return filePaths; } diff --git a/src/openpose/wrapper/wrapperAuxiliary.cpp b/src/openpose/wrapper/wrapperAuxiliary.cpp index 618f8a6b..2fcc1b32 100644 --- a/src/openpose/wrapper/wrapperAuxiliary.cpp +++ b/src/openpose/wrapper/wrapperAuxiliary.cpp @@ -58,7 +58,6 @@ namespace op !wrapperStructOutput.writeImages.empty() || !wrapperStructOutput.writeVideo.empty() || !wrapperStructOutput.writeKeypoint.empty() || !wrapperStructOutput.writeJson.empty() || !wrapperStructOutput.writeCocoJson.empty() || !wrapperStructOutput.writeHeatMaps.empty() - || !wrapperStructOutput.writeCocoFootJson.empty() ); const auto savingCvOutput = ( !wrapperStructOutput.writeImages.empty() || !wrapperStructOutput.writeVideo.empty() diff --git a/src/openpose/wrapper/wrapperStructOutput.cpp b/src/openpose/wrapper/wrapperStructOutput.cpp index 3ca1303e..c19b3610 100644 --- a/src/openpose/wrapper/wrapperStructOutput.cpp +++ b/src/openpose/wrapper/wrapperStructOutput.cpp @@ -4,7 +4,7 @@ namespace op { WrapperStructOutput::WrapperStructOutput( const double verbose_, const std::string& writeKeypoint_, const DataFormat writeKeypointFormat_, - const std::string& writeJson_, const std::string& writeCocoJson_, const std::string& writeCocoFootJson_, + const std::string& writeJson_, const std::string& writeCocoJson_, const int writeCocoJsonVariants_, const int writeCocoJsonVariant_, const std::string& writeImages_, const std::string& writeImagesFormat_, const std::string& writeVideo_, const double writeVideoFps_, const bool writeVideoWithAudio_, const std::string& writeHeatMaps_, const std::string& writeHeatMapsFormat_, const std::string& writeVideo3D_, @@ -15,7 +15,7 @@ namespace op writeKeypointFormat{writeKeypointFormat_}, writeJson{writeJson_}, writeCocoJson{writeCocoJson_}, - writeCocoFootJson{writeCocoFootJson_}, + writeCocoJsonVariants{writeCocoJsonVariants_}, writeCocoJsonVariant{writeCocoJsonVariant_}, writeImages{writeImages_}, writeImagesFormat{writeImagesFormat_},