├── gen-vs2015.bat ├── bin ├── person.jpg └── openpose.cfg ├── doc ├── gaga1.gif ├── coco-final-layer.jpg └── mpi-final-layer.jpg ├── .vscode ├── settings.json ├── launch.json └── tasks.json ├── .gitignore ├── caffe2darknet.bat ├── LICENSE ├── src ├── post_process.h ├── openpose │ ├── enumClasses.hpp │ ├── poseParameters.hpp │ ├── poseParametersRender.hpp │ └── poseParameters.cpp ├── main.cpp └── post_process.cpp ├── premake5.lua └── README.md /gen-vs2015.bat: -------------------------------------------------------------------------------- 1 | premake5 vs2015 -------------------------------------------------------------------------------- /bin/person.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jing-interactive/DancingGaga/HEAD/bin/person.jpg -------------------------------------------------------------------------------- /doc/gaga1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jing-interactive/DancingGaga/HEAD/doc/gaga1.gif -------------------------------------------------------------------------------- /doc/coco-final-layer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jing-interactive/DancingGaga/HEAD/doc/coco-final-layer.jpg -------------------------------------------------------------------------------- /doc/mpi-final-layer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jing-interactive/DancingGaga/HEAD/doc/mpi-final-layer.jpg -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "C_Cpp.clang_format_style": "{AllowShortIfStatementsOnASingleLine: true, PointerBindsToType: true, ColumnLimit: 100, IndentWidth: 4, UseTab: Never, NamespaceIndentation: All, BreakBeforeBraces: Allman}" 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | *.ilk 35 | *.pdb 36 | 37 | vs201* 38 | *.weight 39 | *.mp4 40 | _releases -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "(Windows) Launch", 9 | "type": "cppvsdbg", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/bin/${workspaceFolderBasename}-d.exe", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${workspaceFolder}/bin", 15 | "environment": [], 16 | "externalConsole": true 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /caffe2darknet.bat: -------------------------------------------------------------------------------- 1 | set OUTPUT=body_25 2 | set PROTO=../openpose/models/pose/body_25/pose_deploy.prototxt 3 | set MODEL=../openpose/models/pose/body_25/pose_iter_584000.caffemodel 4 | REM python ../lightnet/modules/pytorch-caffe-darknet-convert/caffe2darknet.py %PROTO% %MODEL% %OUTPUT%.cfg %OUTPUT%.weights 5 | 6 | set OUTPUT=coco 7 | set PROTO=../openpose/models/pose/coco/pose_deploy_linevec.prototxt 8 | set MODEL=../openpose/models/pose/coco/pose_iter_440000.caffemodel 9 | REM python ../lightnet/modules/pytorch-caffe-darknet-convert/caffe2darknet.py %PROTO% %MODEL% %OUTPUT%.cfg %OUTPUT%.weights 10 | 11 | set OUTPUT=mpi 12 | set PROTO=../openpose/models/pose/mpi/pose_deploy_linevec.prototxt 13 | set MODEL=../openpose/models/pose/mpi/pose_iter_160000.caffemodel 14 | python ../lightnet/modules/pytorch-caffe-darknet-convert/caffe2darknet.py %PROTO% %MODEL% %OUTPUT%.cfg %OUTPUT%.weights 15 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "msbuild", 8 | "type": "shell", 9 | "command": "msbuild", 10 | "args": [ 11 | // Ask msbuild to generate full paths for file names. 12 | "${workspaceFolder}/vs2015/${workspaceFolderBasename}.sln", 13 | "/property:GenerateFullPaths=true", 14 | "/t:build" 15 | ], 16 | "group": "build", 17 | "presentation": { 18 | // Reveal the output only if unrecognized errors occur. 19 | "reveal": "silent" 20 | }, 21 | // Use the standard MS compiler pattern to detect errors, warnings and infos 22 | "problemMatcher": "$msCompile" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jing Interactive | 静动 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/post_process.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "openpose/enumClasses.hpp" 4 | 5 | #define POSE_MAX_PEOPLE 127 6 | 7 | void setPoseModel(op::PoseModel model); 8 | 9 | uint32_t getNetOutChannels(); 10 | 11 | void render_pose_keypoints( 12 | cv::Mat &frame, 13 | const std::vector &keypoints, 14 | std::vector keyshape, 15 | const float threshold, 16 | float scale); 17 | 18 | void connect_bodyparts( 19 | std::vector &pose_keypoints, 20 | const float *const map, 21 | const float *const peaks, 22 | int mapw, 23 | int maph, 24 | const int inter_min_above_th, 25 | const float inter_th, 26 | const int min_subset_cnt, 27 | const float min_subset_score, 28 | std::vector &keypoint_shape); 29 | 30 | void find_heatmap_peaks( 31 | const float *src, 32 | float *dst, 33 | const int SRCW, 34 | const int SRCH, 35 | const int SRC_CH, 36 | const float TH); 37 | 38 | void create_netsize_im( 39 | const cv::Mat &intput, 40 | cv::Mat& out, 41 | const int netw, 42 | const int neth, 43 | float *scale); -------------------------------------------------------------------------------- /src/openpose/enumClasses.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OPENPOSE_POSE_ENUM_CLASSES_HPP 2 | #define OPENPOSE_POSE_ENUM_CLASSES_HPP 3 | 4 | namespace op 5 | { 6 | /** 7 | * An enum class in which all the possible type of pose estimation models are included. 8 | */ 9 | enum class PoseModel : unsigned char 10 | { 11 | /** 12 | * COCO + 6 foot keypoints + neck + lower abs model, with 25+1 components (see poseParameters.hpp for details). 13 | */ 14 | BODY_25 = 0, 15 | COCO_18, /**< COCO model + neck, with 18+1 components (see poseParameters.hpp for details). */ 16 | MPI_15, /**< MPI model, with 15+1 components (see poseParameters.hpp for details). */ 17 | MPI_15_4, /**< Variation of the MPI model, reduced number of CNN stages to 4: faster but less accurate.*/ 18 | BODY_19, /**< Experimental. Do not use. */ 19 | BODY_19_X2, /**< Experimental. Do not use. */ 20 | BODY_59, /**< Experimental. Do not use. */ 21 | BODY_19N, /**< Experimental. Do not use. */ 22 | BODY_19b, /**< Experimental. Do not use. */ 23 | BODY_25_19, /**< Experimental. Do not use. */ 24 | BODY_65, /**< Experimental. Do not use. */ 25 | CAR_12, /**< Experimental. Do not use. */ 26 | Size, 27 | }; 28 | 29 | enum class PoseProperty : unsigned char 30 | { 31 | NMSThreshold = 0, 32 | ConnectInterMinAboveThreshold, 33 | ConnectInterThreshold, 34 | ConnectMinSubsetCnt, 35 | ConnectMinSubsetScore, 36 | Size, 37 | }; 38 | } 39 | 40 | #endif // OPENPOSE_POSE_ENUM_CLASSES_HPP 41 | -------------------------------------------------------------------------------- /src/openpose/poseParameters.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OPENPOSE_POSE_POSE_PARAMETERS_HPP 2 | #define OPENPOSE_POSE_POSE_PARAMETERS_HPP 3 | 4 | #include 5 | #include 6 | #include "enumClasses.hpp" 7 | 8 | #define OP_API 9 | 10 | namespace op 11 | { 12 | // Constant Global Parameters 13 | // For OpenCL-NMS in Ubuntu, (POSE_MAX_PEOPLE+1)*3(x,y,score) must be divisible by 32. Easy fix: 14 | // POSE_MAX_PEOPLE = 32n - 1 15 | // For OpenCL-NMS in Windows, it must be by 64, so 64n - 1 16 | #define POSE_MAX_PEOPLE 127 17 | 18 | // Model functions 19 | OP_API const std::map& getPoseBodyPartMapping(const PoseModel poseModel); 20 | OP_API const std::string& getPoseProtoTxt(const PoseModel poseModel); 21 | OP_API const std::string& getPoseTrainedModel(const PoseModel poseModel); 22 | OP_API unsigned int getPoseNumberBodyParts(const PoseModel poseModel); 23 | OP_API const std::vector& getPosePartPairs(const PoseModel poseModel); 24 | OP_API const std::vector& getPoseMapIndex(const PoseModel poseModel); 25 | OP_API unsigned int getPoseMaxPeaks(const PoseModel poseModel); 26 | OP_API float getPoseNetDecreaseFactor(const PoseModel poseModel); 27 | OP_API unsigned int poseBodyPartMapStringToKey(const PoseModel poseModel, const std::string& string); 28 | OP_API unsigned int poseBodyPartMapStringToKey(const PoseModel poseModel, const std::vector& strings); 29 | 30 | // Default NSM and body connector parameters 31 | OP_API float getPoseDefaultNmsThreshold(const PoseModel poseModel); 32 | OP_API float getPoseDefaultConnectInterMinAboveThreshold(const PoseModel poseModel); 33 | OP_API float getPoseDefaultConnectInterThreshold(const PoseModel poseModel); 34 | OP_API unsigned int getPoseDefaultMinSubsetCnt(const PoseModel poseModel); 35 | OP_API float getPoseDefaultConnectMinSubsetScore(const PoseModel poseModel); 36 | 37 | // const bool COCO_CHALLENGE = true; 38 | const bool COCO_CHALLENGE = false; 39 | } 40 | 41 | #endif // OPENPOSE_POSE_POSE_PARAMETERS_HPP 42 | -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | -- http://industriousone.com/scripting-reference 2 | 3 | local action = _ACTION or "" 4 | 5 | local OPENCV_PATH = "d:/opencv/build" 6 | 7 | solution "DancingGaga" 8 | location (action) 9 | configurations { "Debug", "Profile", "Release" } 10 | platforms {"x64"} 11 | language "C" 12 | kind "StaticLib" 13 | 14 | filter "system:windows" 15 | defines { 16 | "_CRT_SECURE_NO_WARNINGS", 17 | "WIN32", 18 | "_TIMESPEC_DEFINED", 19 | "OPENCV", 20 | "GPU", 21 | -- "CV_IGNORE_DEBUG_BUILD_GUARD", 22 | } 23 | 24 | configuration "x64" 25 | libdirs { 26 | "../lightnet/bin", 27 | path.join(OPENCV_PATH, "x64/vc14/lib") 28 | } 29 | targetdir ("bin/") 30 | 31 | configuration "Debug" 32 | defines { "DEBUG" } 33 | symbols "On" 34 | targetsuffix "-d" 35 | 36 | configuration "Profile" 37 | defines { "NDEBUG", "MTR_ENABLED" } 38 | flags { "No64BitChecks" } 39 | editandcontinue "Off" 40 | optimize "Speed" 41 | optimize "On" 42 | editandcontinue "Off" 43 | 44 | configuration "Release" 45 | defines { "NDEBUG" } 46 | flags { "No64BitChecks" } 47 | editandcontinue "Off" 48 | optimize "Speed" 49 | optimize "On" 50 | editandcontinue "Off" 51 | 52 | project "DancingGaga" 53 | kind "ConsoleApp" 54 | includedirs { 55 | "../lightnet/modules", 56 | "../lightnet/modules/darknet/include", 57 | "../lightnet/modules/darknet/3rdparty/pthreads/include", 58 | "../lightnet/modules/darknet/src", 59 | "src", 60 | "../lightnet/include", 61 | path.join("$(CUDA_PATH)", "include"), 62 | path.join(OPENCV_PATH, "include") 63 | } 64 | debugdir "bin" 65 | files { 66 | "src/**", 67 | "../lightnet/src/**", 68 | "../lightnet/modules/minitrace/**", 69 | "../lightnet/modules/PDollar/**", 70 | } 71 | configuration "Debug" 72 | links { 73 | "opencv_world340d.lib", 74 | "yolo_cpp_dll-d.lib", 75 | } 76 | configuration "Profile" 77 | links { 78 | "opencv_world340.lib", 79 | "yolo_cpp_dll.lib", 80 | } 81 | configuration "Release" 82 | links { 83 | "opencv_world340.lib", 84 | "yolo_cpp_dll.lib", 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DancingGaga 2 | [Openpose](https://github.com/CMU-Perceptual-Computing-Lab/openpose 3 | ) implementation using darknet framework, originated from [openpose-darknet](https://github.com/lincolnhard/openpose-darknet) 4 | 5 | # Result 6 | 7 | ![demo](https://raw.githubusercontent.com/jing-interactive/DancingGaga/master/doc/gaga1.gif) 8 | 9 | # Steps to build from Visual Studio 2015 10 | 11 | - First you need to build [lightnet](https://github.com/jing-vision/lightnet) 12 | - `git clone --recurse-submodules https://github.com/jing-vision/lightnet.git` 13 | - Follow [lightnet's building steps](https://github.com/jing-vision/lightnet#how-to-build-from-visual-studio-2015) 14 | - Then you need to have [premake](https://premake.github.io/download.html) installed and execute `DancingGaga/gen-vs2015.bat` to generate `DancingGaga/vs2015` folder 15 | - You can find `DancingGaga/vs2015/DancingGaga.sln`, you should be able to build it w/o errors. (If you are lucky like me.) 16 | 17 | 18 | # Steps to run 19 | 20 | - Download [weight file](https://drive.google.com/open?id=1BfY0Hx2d2nm3I4JFh0W1cK2aHD1FSGea) and copy it as `bin/openpose.weight` 21 | 22 | - Usage 23 | ``` 24 | DancingGaga.exe -cfg=[openpose.cfg] -weights=[openpose.weight] media-source 25 | ``` 26 | e.g you can detect pose from a video 27 | ``` 28 | DancingGaga.exe pickme-101.mp4 29 | ``` 30 | Or from an image 31 | ``` 32 | DancingGaga.exe person.jpg 33 | ``` 34 | Or even from your default camera (index #0) 35 | ``` 36 | DancingGaga.exe 0 37 | ``` 38 | - Other network models 39 | ``` 40 | DancingGaga.exe -cfg=..\coco.cfg -weights=..\coco.weights person.jpg 41 | DancingGaga.exe -cfg=..\mpi.cfg -weights=..\mpi.weights person.jpg 42 | DancingGaga.exe -cfg=..\body_25.cfg -weights=..\body_25.weights person.jpg 43 | ``` 44 | # network layout 45 | 46 | ``` 47 | layer filters size input output 48 | 0 conv 64 3 x 3 / 1 200 x 200 x 3 -> 200 x 200 x 64 0.138 BF 49 | 1 conv 64 3 x 3 / 1 200 x 200 x 64 -> 200 x 200 x 64 2.949 BF 50 | 2 max 2 x 2 / 2 200 x 200 x 64 -> 100 x 100 x 64 0.003 BF 51 | 3 conv 128 3 x 3 / 1 100 x 100 x 64 -> 100 x 100 x 128 1.475 BF 52 | 4 conv 128 3 x 3 / 1 100 x 100 x 128 -> 100 x 100 x 128 2.949 BF 53 | 5 max 2 x 2 / 2 100 x 100 x 128 -> 50 x 50 x 128 0.001 BF 54 | 6 conv 256 3 x 3 / 1 50 x 50 x 128 -> 50 x 50 x 256 1.475 BF 55 | 7 conv 256 3 x 3 / 1 50 x 50 x 256 -> 50 x 50 x 256 2.949 BF 56 | 8 conv 256 3 x 3 / 1 50 x 50 x 256 -> 50 x 50 x 256 2.949 BF 57 | 9 conv 256 3 x 3 / 1 50 x 50 x 256 -> 50 x 50 x 256 2.949 BF 58 | 10 max 2 x 2 / 2 50 x 50 x 256 -> 25 x 25 x 256 0.001 BF 59 | 11 conv 512 3 x 3 / 1 25 x 25 x 256 -> 25 x 25 x 512 1.475 BF 60 | 12 conv 512 3 x 3 / 1 25 x 25 x 512 -> 25 x 25 x 512 2.949 BF 61 | 13 conv 256 3 x 3 / 1 25 x 25 x 512 -> 25 x 25 x 256 1.475 BF 62 | 14 conv 128 3 x 3 / 1 25 x 25 x 256 -> 25 x 25 x 128 0.369 BF 63 | 15 conv 128 3 x 3 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.184 BF 64 | 16 conv 128 3 x 3 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.184 BF 65 | 17 conv 128 3 x 3 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.184 BF 66 | 18 conv 512 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 512 0.082 BF 67 | 19 conv 38 1 x 1 / 1 25 x 25 x 512 -> 25 x 25 x 38 0.024 BF 68 | 20 route 14 69 | 21 conv 128 3 x 3 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.184 BF 70 | 22 conv 128 3 x 3 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.184 BF 71 | 23 conv 128 3 x 3 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.184 BF 72 | 24 conv 512 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 512 0.082 BF 73 | 25 conv 19 1 x 1 / 1 25 x 25 x 512 -> 25 x 25 x 19 0.012 BF 74 | 26 route 19 25 14 75 | 27 conv 128 7 x 7 / 1 25 x 25 x 185 -> 25 x 25 x 128 1.450 BF 76 | 28 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 77 | 29 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 78 | 30 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 79 | 31 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 80 | 32 conv 128 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.020 BF 81 | 33 conv 38 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 38 0.006 BF 82 | 34 route 26 83 | 35 conv 128 7 x 7 / 1 25 x 25 x 185 -> 25 x 25 x 128 1.450 BF 84 | 36 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 85 | 37 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 86 | 38 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 87 | 39 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 88 | 40 conv 128 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.020 BF 89 | 41 conv 19 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 19 0.003 BF 90 | 42 route 33 41 14 91 | 43 conv 128 7 x 7 / 1 25 x 25 x 185 -> 25 x 25 x 128 1.450 BF 92 | 44 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 93 | 45 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 94 | 46 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 95 | 47 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 96 | 48 conv 128 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.020 BF 97 | 49 conv 38 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 38 0.006 BF 98 | 50 route 42 99 | 51 conv 128 7 x 7 / 1 25 x 25 x 185 -> 25 x 25 x 128 1.450 BF 100 | 52 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 101 | 53 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 102 | 54 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 103 | 55 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 104 | 56 conv 128 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.020 BF 105 | 57 conv 19 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 19 0.003 BF 106 | 58 route 49 57 14 107 | 59 conv 128 7 x 7 / 1 25 x 25 x 185 -> 25 x 25 x 128 1.450 BF 108 | 60 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 109 | 61 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 110 | 62 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 111 | 63 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 112 | 64 conv 128 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.020 BF 113 | 65 conv 38 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 38 0.006 BF 114 | 66 route 58 115 | 67 conv 128 7 x 7 / 1 25 x 25 x 185 -> 25 x 25 x 128 1.450 BF 116 | 68 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 117 | 69 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 118 | 70 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 119 | 71 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 120 | 72 conv 128 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.020 BF 121 | 73 conv 19 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 19 0.003 BF 122 | 74 route 65 73 14 123 | 75 conv 128 7 x 7 / 1 25 x 25 x 185 -> 25 x 25 x 128 1.450 BF 124 | 76 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 125 | 77 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 126 | 78 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 127 | 79 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 128 | 80 conv 128 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.020 BF 129 | 81 conv 38 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 38 0.006 BF 130 | 82 route 74 131 | 83 conv 128 7 x 7 / 1 25 x 25 x 185 -> 25 x 25 x 128 1.450 BF 132 | 84 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 133 | 85 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 134 | 86 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 135 | 87 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 136 | 88 conv 128 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.020 BF 137 | 89 conv 19 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 19 0.003 BF 138 | 90 route 81 89 14 139 | 91 conv 128 7 x 7 / 1 25 x 25 x 185 -> 25 x 25 x 128 1.450 BF 140 | 92 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 141 | 93 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 142 | 94 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 143 | 95 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 144 | 96 conv 128 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.020 BF 145 | 97 conv 38 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 38 0.006 BF 146 | 98 route 90 147 | 99 conv 128 7 x 7 / 1 25 x 25 x 185 -> 25 x 25 x 128 1.450 BF 148 | 100 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 149 | 101 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 150 | 102 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 151 | 103 conv 128 7 x 7 / 1 25 x 25 x 128 -> 25 x 25 x 128 1.004 BF 152 | 104 conv 128 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 128 0.020 BF 153 | 105 conv 19 1 x 1 / 1 25 x 25 x 128 -> 25 x 25 x 19 0.003 BF 154 | 106 route 105 97 155 | ``` 156 | 157 | # Note 158 | 159 | 1. Darknet version openpose.cfg and openpose.weight are ported from COCO version 160 | 161 | [pose_deploy_linevec.prototxt](https://github.com/ZheC/Realtime_Multi-Person_Pose_Estimation/tree/master/model/_trained_COCO) and [pose_iter_440000.caffemodel]( http://posefs1.perception.cs.cmu.edu/Users/ZheCao/pose_iter_440000.caffemodel). 162 | 163 | 2. You could change net input width, height in openpose.cfg. 164 | -------------------------------------------------------------------------------- /bin/openpose.cfg: -------------------------------------------------------------------------------- 1 | [net] 2 | width=200 3 | height=200 4 | channels=3 5 | 6 | [convolutional] 7 | batch_normalize=0 8 | filters=64 9 | size=3 10 | stride=1 11 | pad=1 12 | activation=relu 13 | 14 | [convolutional] 15 | batch_normalize=0 16 | filters=64 17 | size=3 18 | stride=1 19 | pad=1 20 | activation=relu 21 | 22 | [maxpool] 23 | size=2 24 | stride=2 25 | 26 | [convolutional] 27 | batch_normalize=0 28 | filters=128 29 | size=3 30 | stride=1 31 | pad=1 32 | activation=relu 33 | 34 | [convolutional] 35 | batch_normalize=0 36 | filters=128 37 | size=3 38 | stride=1 39 | pad=1 40 | activation=relu 41 | 42 | [maxpool] 43 | size=2 44 | stride=2 45 | 46 | [convolutional] 47 | batch_normalize=0 48 | filters=256 49 | size=3 50 | stride=1 51 | pad=1 52 | activation=relu 53 | 54 | [convolutional] 55 | batch_normalize=0 56 | filters=256 57 | size=3 58 | stride=1 59 | pad=1 60 | activation=relu 61 | 62 | [convolutional] 63 | batch_normalize=0 64 | filters=256 65 | size=3 66 | stride=1 67 | pad=1 68 | activation=relu 69 | 70 | [convolutional] 71 | batch_normalize=0 72 | filters=256 73 | size=3 74 | stride=1 75 | pad=1 76 | activation=relu 77 | 78 | [maxpool] 79 | size=2 80 | stride=2 81 | 82 | [convolutional] 83 | batch_normalize=0 84 | filters=512 85 | size=3 86 | stride=1 87 | pad=1 88 | activation=relu 89 | 90 | [convolutional] 91 | batch_normalize=0 92 | filters=512 93 | size=3 94 | stride=1 95 | pad=1 96 | activation=relu 97 | 98 | [convolutional] 99 | batch_normalize=0 100 | filters=256 101 | size=3 102 | stride=1 103 | pad=1 104 | activation=relu 105 | 106 | [convolutional] 107 | batch_normalize=0 108 | filters=128 109 | size=3 110 | stride=1 111 | pad=1 112 | activation=relu 113 | 114 | ####### 115 | 116 | [convolutional] 117 | batch_normalize=0 118 | filters=128 119 | size=3 120 | stride=1 121 | pad=1 122 | activation=relu 123 | 124 | [convolutional] 125 | batch_normalize=0 126 | filters=128 127 | size=3 128 | stride=1 129 | pad=1 130 | activation=relu 131 | 132 | [convolutional] 133 | batch_normalize=0 134 | filters=128 135 | size=3 136 | stride=1 137 | pad=1 138 | activation=relu 139 | 140 | [convolutional] 141 | batch_normalize=0 142 | filters=512 143 | size=1 144 | stride=1 145 | pad=0 146 | activation=relu 147 | 148 | [convolutional] 149 | batch_normalize=0 150 | filters=38 151 | size=1 152 | stride=1 153 | pad=0 154 | activation=linear 155 | 156 | [route] 157 | layers=-6 158 | 159 | [convolutional] 160 | batch_normalize=0 161 | filters=128 162 | size=3 163 | stride=1 164 | pad=1 165 | activation=relu 166 | 167 | [convolutional] 168 | batch_normalize=0 169 | filters=128 170 | size=3 171 | stride=1 172 | pad=1 173 | activation=relu 174 | 175 | [convolutional] 176 | batch_normalize=0 177 | filters=128 178 | size=3 179 | stride=1 180 | pad=1 181 | activation=relu 182 | 183 | [convolutional] 184 | batch_normalize=0 185 | filters=512 186 | size=1 187 | stride=1 188 | pad=0 189 | activation=relu 190 | 191 | [convolutional] 192 | batch_normalize=0 193 | filters=19 194 | size=1 195 | stride=1 196 | pad=0 197 | activation=linear 198 | 199 | [route] 200 | layers=-7,-1,-12 201 | 202 | ###concat_stage2### 203 | 204 | [convolutional] 205 | batch_normalize=0 206 | filters=128 207 | size=7 208 | stride=1 209 | pad=3 210 | activation=relu 211 | 212 | [convolutional] 213 | batch_normalize=0 214 | filters=128 215 | size=7 216 | stride=1 217 | pad=3 218 | activation=relu 219 | 220 | [convolutional] 221 | batch_normalize=0 222 | filters=128 223 | size=7 224 | stride=1 225 | pad=3 226 | activation=relu 227 | 228 | [convolutional] 229 | batch_normalize=0 230 | filters=128 231 | size=7 232 | stride=1 233 | pad=3 234 | activation=relu 235 | 236 | [convolutional] 237 | batch_normalize=0 238 | filters=128 239 | size=7 240 | stride=1 241 | pad=3 242 | activation=relu 243 | 244 | [convolutional] 245 | batch_normalize=0 246 | filters=128 247 | size=1 248 | stride=1 249 | pad=0 250 | activation=relu 251 | 252 | [convolutional] 253 | batch_normalize=0 254 | filters=38 255 | size=1 256 | stride=1 257 | pad=0 258 | activation=linear 259 | 260 | [route] 261 | layers=-8 262 | 263 | [convolutional] 264 | batch_normalize=0 265 | filters=128 266 | size=7 267 | stride=1 268 | pad=3 269 | activation=relu 270 | 271 | [convolutional] 272 | batch_normalize=0 273 | filters=128 274 | size=7 275 | stride=1 276 | pad=3 277 | activation=relu 278 | 279 | [convolutional] 280 | batch_normalize=0 281 | filters=128 282 | size=7 283 | stride=1 284 | pad=3 285 | activation=relu 286 | 287 | [convolutional] 288 | batch_normalize=0 289 | filters=128 290 | size=7 291 | stride=1 292 | pad=3 293 | activation=relu 294 | 295 | [convolutional] 296 | batch_normalize=0 297 | filters=128 298 | size=7 299 | stride=1 300 | pad=3 301 | activation=relu 302 | 303 | [convolutional] 304 | batch_normalize=0 305 | filters=128 306 | size=1 307 | stride=1 308 | pad=0 309 | activation=relu 310 | 311 | [convolutional] 312 | batch_normalize=0 313 | filters=19 314 | size=1 315 | stride=1 316 | pad=0 317 | activation=linear 318 | 319 | [route] 320 | layers=-9,-1,-28 321 | 322 | ###concat_stage3### 323 | 324 | [convolutional] 325 | batch_normalize=0 326 | filters=128 327 | size=7 328 | stride=1 329 | pad=3 330 | activation=relu 331 | 332 | [convolutional] 333 | batch_normalize=0 334 | filters=128 335 | size=7 336 | stride=1 337 | pad=3 338 | activation=relu 339 | 340 | [convolutional] 341 | batch_normalize=0 342 | filters=128 343 | size=7 344 | stride=1 345 | pad=3 346 | activation=relu 347 | 348 | [convolutional] 349 | batch_normalize=0 350 | filters=128 351 | size=7 352 | stride=1 353 | pad=3 354 | activation=relu 355 | 356 | [convolutional] 357 | batch_normalize=0 358 | filters=128 359 | size=7 360 | stride=1 361 | pad=3 362 | activation=relu 363 | 364 | [convolutional] 365 | batch_normalize=0 366 | filters=128 367 | size=1 368 | stride=1 369 | pad=0 370 | activation=relu 371 | 372 | [convolutional] 373 | batch_normalize=0 374 | filters=38 375 | size=1 376 | stride=1 377 | pad=0 378 | activation=linear 379 | 380 | [route] 381 | layers=-8 382 | 383 | [convolutional] 384 | batch_normalize=0 385 | filters=128 386 | size=7 387 | stride=1 388 | pad=3 389 | activation=relu 390 | 391 | [convolutional] 392 | batch_normalize=0 393 | filters=128 394 | size=7 395 | stride=1 396 | pad=3 397 | activation=relu 398 | 399 | [convolutional] 400 | batch_normalize=0 401 | filters=128 402 | size=7 403 | stride=1 404 | pad=3 405 | activation=relu 406 | 407 | [convolutional] 408 | batch_normalize=0 409 | filters=128 410 | size=7 411 | stride=1 412 | pad=3 413 | activation=relu 414 | 415 | [convolutional] 416 | batch_normalize=0 417 | filters=128 418 | size=7 419 | stride=1 420 | pad=3 421 | activation=relu 422 | 423 | [convolutional] 424 | batch_normalize=0 425 | filters=128 426 | size=1 427 | stride=1 428 | pad=0 429 | activation=relu 430 | 431 | [convolutional] 432 | batch_normalize=0 433 | filters=19 434 | size=1 435 | stride=1 436 | pad=0 437 | activation=linear 438 | 439 | [route] 440 | layers=-9,-1,-44 441 | 442 | ###concat_stage4### 443 | 444 | [convolutional] 445 | batch_normalize=0 446 | filters=128 447 | size=7 448 | stride=1 449 | pad=3 450 | activation=relu 451 | 452 | [convolutional] 453 | batch_normalize=0 454 | filters=128 455 | size=7 456 | stride=1 457 | pad=3 458 | activation=relu 459 | 460 | [convolutional] 461 | batch_normalize=0 462 | filters=128 463 | size=7 464 | stride=1 465 | pad=3 466 | activation=relu 467 | 468 | [convolutional] 469 | batch_normalize=0 470 | filters=128 471 | size=7 472 | stride=1 473 | pad=3 474 | activation=relu 475 | 476 | [convolutional] 477 | batch_normalize=0 478 | filters=128 479 | size=7 480 | stride=1 481 | pad=3 482 | activation=relu 483 | 484 | [convolutional] 485 | batch_normalize=0 486 | filters=128 487 | size=1 488 | stride=1 489 | pad=0 490 | activation=relu 491 | 492 | [convolutional] 493 | batch_normalize=0 494 | filters=38 495 | size=1 496 | stride=1 497 | pad=0 498 | activation=linear 499 | 500 | [route] 501 | layers=-8 502 | 503 | [convolutional] 504 | batch_normalize=0 505 | filters=128 506 | size=7 507 | stride=1 508 | pad=3 509 | activation=relu 510 | 511 | [convolutional] 512 | batch_normalize=0 513 | filters=128 514 | size=7 515 | stride=1 516 | pad=3 517 | activation=relu 518 | 519 | [convolutional] 520 | batch_normalize=0 521 | filters=128 522 | size=7 523 | stride=1 524 | pad=3 525 | activation=relu 526 | 527 | [convolutional] 528 | batch_normalize=0 529 | filters=128 530 | size=7 531 | stride=1 532 | pad=3 533 | activation=relu 534 | 535 | [convolutional] 536 | batch_normalize=0 537 | filters=128 538 | size=7 539 | stride=1 540 | pad=3 541 | activation=relu 542 | 543 | [convolutional] 544 | batch_normalize=0 545 | filters=128 546 | size=1 547 | stride=1 548 | pad=0 549 | activation=relu 550 | 551 | [convolutional] 552 | batch_normalize=0 553 | filters=19 554 | size=1 555 | stride=1 556 | pad=0 557 | activation=linear 558 | 559 | [route] 560 | layers=-9,-1,-60 561 | 562 | ###concat_stage5### 563 | 564 | [convolutional] 565 | batch_normalize=0 566 | filters=128 567 | size=7 568 | stride=1 569 | pad=3 570 | activation=relu 571 | 572 | [convolutional] 573 | batch_normalize=0 574 | filters=128 575 | size=7 576 | stride=1 577 | pad=3 578 | activation=relu 579 | 580 | [convolutional] 581 | batch_normalize=0 582 | filters=128 583 | size=7 584 | stride=1 585 | pad=3 586 | activation=relu 587 | 588 | [convolutional] 589 | batch_normalize=0 590 | filters=128 591 | size=7 592 | stride=1 593 | pad=3 594 | activation=relu 595 | 596 | [convolutional] 597 | batch_normalize=0 598 | filters=128 599 | size=7 600 | stride=1 601 | pad=3 602 | activation=relu 603 | 604 | [convolutional] 605 | batch_normalize=0 606 | filters=128 607 | size=1 608 | stride=1 609 | pad=0 610 | activation=relu 611 | 612 | [convolutional] 613 | batch_normalize=0 614 | filters=38 615 | size=1 616 | stride=1 617 | pad=0 618 | activation=linear 619 | 620 | [route] 621 | layers=-8 622 | 623 | [convolutional] 624 | batch_normalize=0 625 | filters=128 626 | size=7 627 | stride=1 628 | pad=3 629 | activation=relu 630 | 631 | [convolutional] 632 | batch_normalize=0 633 | filters=128 634 | size=7 635 | stride=1 636 | pad=3 637 | activation=relu 638 | 639 | [convolutional] 640 | batch_normalize=0 641 | filters=128 642 | size=7 643 | stride=1 644 | pad=3 645 | activation=relu 646 | 647 | [convolutional] 648 | batch_normalize=0 649 | filters=128 650 | size=7 651 | stride=1 652 | pad=3 653 | activation=relu 654 | 655 | [convolutional] 656 | batch_normalize=0 657 | filters=128 658 | size=7 659 | stride=1 660 | pad=3 661 | activation=relu 662 | 663 | [convolutional] 664 | batch_normalize=0 665 | filters=128 666 | size=1 667 | stride=1 668 | pad=0 669 | activation=relu 670 | 671 | [convolutional] 672 | batch_normalize=0 673 | filters=19 674 | size=1 675 | stride=1 676 | pad=0 677 | activation=linear 678 | 679 | [route] 680 | layers=-9,-1,-76 681 | 682 | ###concat_stage6### 683 | 684 | [convolutional] 685 | batch_normalize=0 686 | filters=128 687 | size=7 688 | stride=1 689 | pad=3 690 | activation=relu 691 | 692 | [convolutional] 693 | batch_normalize=0 694 | filters=128 695 | size=7 696 | stride=1 697 | pad=3 698 | activation=relu 699 | 700 | [convolutional] 701 | batch_normalize=0 702 | filters=128 703 | size=7 704 | stride=1 705 | pad=3 706 | activation=relu 707 | 708 | [convolutional] 709 | batch_normalize=0 710 | filters=128 711 | size=7 712 | stride=1 713 | pad=3 714 | activation=relu 715 | 716 | [convolutional] 717 | batch_normalize=0 718 | filters=128 719 | size=7 720 | stride=1 721 | pad=3 722 | activation=relu 723 | 724 | [convolutional] 725 | batch_normalize=0 726 | filters=128 727 | size=1 728 | stride=1 729 | pad=0 730 | activation=relu 731 | 732 | [convolutional] 733 | batch_normalize=0 734 | filters=38 735 | size=1 736 | stride=1 737 | pad=0 738 | activation=linear 739 | 740 | [route] 741 | layers=-8 742 | 743 | [convolutional] 744 | batch_normalize=0 745 | filters=128 746 | size=7 747 | stride=1 748 | pad=3 749 | activation=relu 750 | 751 | [convolutional] 752 | batch_normalize=0 753 | filters=128 754 | size=7 755 | stride=1 756 | pad=3 757 | activation=relu 758 | 759 | [convolutional] 760 | batch_normalize=0 761 | filters=128 762 | size=7 763 | stride=1 764 | pad=3 765 | activation=relu 766 | 767 | [convolutional] 768 | batch_normalize=0 769 | filters=128 770 | size=7 771 | stride=1 772 | pad=3 773 | activation=relu 774 | 775 | [convolutional] 776 | batch_normalize=0 777 | filters=128 778 | size=7 779 | stride=1 780 | pad=3 781 | activation=relu 782 | 783 | [convolutional] 784 | batch_normalize=0 785 | filters=128 786 | size=1 787 | stride=1 788 | pad=0 789 | activation=relu 790 | 791 | [convolutional] 792 | batch_normalize=0 793 | filters=19 794 | size=1 795 | stride=1 796 | pad=0 797 | activation=linear 798 | 799 | [route] 800 | layers=-1,-9 801 | -------------------------------------------------------------------------------- /src/openpose/poseParametersRender.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OPENPOSE_POSE_POSE_PARAMETERS_RENDER_HPP 2 | #define OPENPOSE_POSE_POSE_PARAMETERS_RENDER_HPP 3 | 4 | #include "poseParameters.hpp" 5 | 6 | namespace op 7 | { 8 | // Rendering parameters 9 | const auto POSE_DEFAULT_ALPHA_KEYPOINT = 0.6f; 10 | const auto POSE_DEFAULT_ALPHA_HEAT_MAP = 0.7f; 11 | 12 | // Model-Dependent Parameters 13 | // CUDA-code Model-Dependent Parameters must be defined with #define 14 | // BODY_25 15 | #define POSE_BODY_25_PAIRS_RENDER_GPU \ 16 | 1,8, 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0, 0,15, 15,17, 0,16, 16,18, 14,19,19,20,14,21, 11,22,22,23,11,24 17 | #define POSE_BODY_25_SCALES_RENDER_GPU 1 18 | #define POSE_BODY_25_COLORS_RENDER_GPU \ 19 | 255.f, 0.f, 85.f, \ 20 | 255.f, 0.f, 0.f, \ 21 | 255.f, 85.f, 0.f, \ 22 | 255.f, 170.f, 0.f, \ 23 | 255.f, 255.f, 0.f, \ 24 | 170.f, 255.f, 0.f, \ 25 | 85.f, 255.f, 0.f, \ 26 | 0.f, 255.f, 0.f, \ 27 | 255.f, 0.f, 0.f, \ 28 | 0.f, 255.f, 85.f, \ 29 | 0.f, 255.f, 170.f, \ 30 | 0.f, 255.f, 255.f, \ 31 | 0.f, 170.f, 255.f, \ 32 | 0.f, 85.f, 255.f, \ 33 | 0.f, 0.f, 255.f, \ 34 | 255.f, 0.f, 170.f, \ 35 | 170.f, 0.f, 255.f, \ 36 | 255.f, 0.f, 255.f, \ 37 | 85.f, 0.f, 255.f, \ 38 | 0.f, 0.f, 255.f, \ 39 | 0.f, 0.f, 255.f, \ 40 | 0.f, 0.f, 255.f, \ 41 | 0.f, 255.f, 255.f, \ 42 | 0.f, 255.f, 255.f, \ 43 | 0.f, 255.f, 255.f 44 | // COCO 45 | #define POSE_COCO_PAIRS_RENDER_GPU \ 46 | 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 1,8, 8,9, 9,10, 1,11, 11,12, 12,13, 1,0, 0,14, 14,16, 0,15, 15,17 47 | #define POSE_COCO_SCALES_RENDER_GPU 1 48 | #define POSE_COCO_COLORS_RENDER_GPU \ 49 | 255.f, 0.f, 85.f, \ 50 | 255.f, 0.f, 0.f, \ 51 | 255.f, 85.f, 0.f, \ 52 | 255.f, 170.f, 0.f, \ 53 | 255.f, 255.f, 0.f, \ 54 | 170.f, 255.f, 0.f, \ 55 | 85.f, 255.f, 0.f, \ 56 | 0.f, 255.f, 0.f, \ 57 | 0.f, 255.f, 85.f, \ 58 | 0.f, 255.f, 170.f, \ 59 | 0.f, 255.f, 255.f, \ 60 | 0.f, 170.f, 255.f, \ 61 | 0.f, 85.f, 255.f, \ 62 | 0.f, 0.f, 255.f, \ 63 | 255.f, 0.f, 170.f, \ 64 | 170.f, 0.f, 255.f, \ 65 | 255.f, 0.f, 255.f, \ 66 | 85.f, 0.f, 255.f 67 | // MPI 68 | // MPI colors chosen such that they are closed to COCO colors 69 | #define POSE_MPI_PAIRS_RENDER_GPU \ 70 | 0,1, 1,2, 2,3, 3,4, 1,5, 5,6, 6,7, 1,14, 14,8, 8,9, 9,10, 14,11, 11,12, 12,13 71 | #define POSE_MPI_SCALES_RENDER_GPU 1 72 | #define POSE_MPI_COLORS_RENDER_GPU \ 73 | 255.f, 0.f, 85.f, \ 74 | 255.f, 0.f, 0.f, \ 75 | 255.f, 85.f, 0.f, \ 76 | 255.f, 170.f, 0.f, \ 77 | 255.f, 255.f, 0.f, \ 78 | 170.f, 255.f, 0.f, \ 79 | 85.f, 255.f, 0.f, \ 80 | 43.f, 255.f, 0.f, \ 81 | 0.f, 255.f, 0.f, \ 82 | 0.f, 255.f, 85.f, \ 83 | 0.f, 255.f, 170.f, \ 84 | 0.f, 255.f, 255.f, \ 85 | 0.f, 170.f, 255.f, \ 86 | 0.f, 85.f, 255.f, \ 87 | 0.f, 0.f, 255.f 88 | // BODY_19 89 | #define POSE_BODY_19_PAIRS_RENDER_GPU \ 90 | 1,8, 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0, 0,15, 15,17, 0,16, 16,18 91 | #define POSE_BODY_19_SCALES_RENDER_GPU 1 92 | #define POSE_BODY_19_COLORS_RENDER_GPU \ 93 | 255.f, 0.f, 85.f, \ 94 | 255.f, 0.f, 0.f, \ 95 | 255.f, 85.f, 0.f, \ 96 | 255.f, 170.f, 0.f, \ 97 | 255.f, 255.f, 0.f, \ 98 | 170.f, 255.f, 0.f, \ 99 | 85.f, 255.f, 0.f, \ 100 | 0.f, 255.f, 0.f, \ 101 | 255.f, 0.f, 0.f, \ 102 | 0.f, 255.f, 85.f, \ 103 | 0.f, 255.f, 170.f, \ 104 | 0.f, 255.f, 255.f, \ 105 | 0.f, 170.f, 255.f, \ 106 | 0.f, 85.f, 255.f, \ 107 | 0.f, 0.f, 255.f, \ 108 | 255.f, 0.f, 170.f, \ 109 | 170.f, 0.f, 255.f, \ 110 | 255.f, 0.f, 255.f, \ 111 | 85.f, 0.f, 255.f 112 | // BODY_19b 113 | #define POSE_BODY_19b_PAIRS_RENDER_GPU \ 114 | 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0, 0,15, 15,17, 0,16, 16,18, 2,9, 5,12 115 | #define POSE_BODY_19b_SCALES_RENDER_GPU 1 116 | #define POSE_BODY_19b_COLORS_RENDER_GPU \ 117 | 255.f, 0.f, 85.f, \ 118 | 255.f, 0.f, 0.f, \ 119 | 255.f, 0.f, 0.f, \ 120 | 255.f, 85.f, 0.f, \ 121 | 255.f, 170.f, 0.f, \ 122 | 255.f, 0.f, 0.f, \ 123 | 255.f, 255.f, 0.f, \ 124 | 85.f, 255.f, 0.f, \ 125 | 255.f, 0.f, 0.f, \ 126 | 255.f, 0.f, 0.f, \ 127 | 0.f, 255.f, 0.f, \ 128 | 0.f, 255.f, 255.f, \ 129 | 255.f, 0.f, 0.f, \ 130 | 0.f, 85.f, 255.f, \ 131 | 0.f, 0.f, 255.f, \ 132 | 255.f, 0.f, 170.f, \ 133 | 170.f, 0.f, 255.f, \ 134 | 255.f, 0.f, 255.f, \ 135 | 85.f, 0.f, 255.f 136 | // BODY_59 137 | // Body + left hand + right hand 138 | #define POSE_BODY_59_PAIRS_RENDER_GPU \ 139 | 1,8, 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0, 0,15, 15,17, 0,16, 16,18, \ 140 | 7,19, 19,20, 20,21, 21,22, 7,23, 23,24, 24,25, 25,26, 7,27, 27,28, 28,29, 29,30, 7,31, 31,32, 32,33, 33,34, 7,35, 35,36, 36,37, 37,38, \ 141 | 4,39, 39,40, 40,41, 41,42, 4,43, 43,44, 44,45, 45,46, 4,47, 47,48, 48,49, 49,50, 4,51, 51,52, 52,53, 53,54, 4,55, 55,56, 56,57, 57,58 142 | #define POSE_BODY_59_SCALES_RENDER_GPU \ 143 | 1.f,1.f,1.f,1.f,1.f, 1.f,1.f,1.f,1.f,1.f, 1.f,1.f,1.f,1.f,1.f, 1.f,1.f,1.f,1.f, \ 144 | 0.75f,0.75f,0.75f,0.75f,0.75f, 0.75f,0.75f,0.75f,0.75f,0.75f, 0.75f,0.75f,0.75f,0.75f,0.75f, 0.75f,0.75f,0.75f,0.75f,0.75f, \ 145 | 0.75f,0.75f,0.75f,0.75f,0.75f, 0.75f,0.75f,0.75f,0.75f,0.75f, 0.75f,0.75f,0.75f,0.75f,0.75f, 0.75f,0.75f,0.75f,0.75f,0.75f 146 | #define POSE_BODY_59_COLORS_RENDER_GPU \ 147 | 255.f, 0.f, 85.f, \ 148 | 255.f, 0.f, 0.f, \ 149 | 255.f, 85.f, 0.f, \ 150 | 255.f, 170.f, 0.f, \ 151 | 255.f, 255.f, 0.f, \ 152 | 170.f, 255.f, 0.f, \ 153 | 85.f, 255.f, 0.f, \ 154 | 0.f, 255.f, 0.f, \ 155 | 255.f, 0.f, 0.f, \ 156 | 0.f, 255.f, 85.f, \ 157 | 0.f, 255.f, 170.f, \ 158 | 0.f, 255.f, 255.f, \ 159 | 0.f, 170.f, 255.f, \ 160 | 0.f, 85.f, 255.f, \ 161 | 0.f, 0.f, 255.f, \ 162 | 255.f, 0.f, 170.f, \ 163 | 170.f, 0.f, 255.f, \ 164 | 255.f, 0.f, 255.f, \ 165 | 85.f, 0.f, 255.f, \ 166 | \ 167 | 255.f, 0.f, 0.f, \ 168 | 191.f, 47.f, 47.f, \ 169 | 127.f, 63.f, 63.f, \ 170 | 63.f, 47.f, 47.f, \ 171 | 255.f, 76.f, 0.f, \ 172 | 191.f, 57.f, 0.f, \ 173 | 127.f, 38.f, 0.f, \ 174 | 63.f, 19.f, 0.f, \ 175 | 255.f, 152.f, 0.f, \ 176 | 191.f, 114.f, 0.f, \ 177 | 127.f, 76.f, 0.f, \ 178 | 63.f, 38.f, 0.f, \ 179 | 255.f, 255.f, 0.f, \ 180 | 191.f, 191.f, 0.f, \ 181 | 127.f, 127.f, 0.f, \ 182 | 63.f, 63.f, 0.f, \ 183 | 0.f, 255.f, 0.f, \ 184 | 0.f, 191.f, 0.f, \ 185 | 0.f, 127.f, 0.f, \ 186 | 0.f, 63.f, 0.f, \ 187 | \ 188 | 255.f, 0.f, 153.f, \ 189 | 191.f, 0.f, 114.f, \ 190 | 127.f, 0.f, 76.f, \ 191 | 63.f, 0.f, 38.f, \ 192 | 203.f, 0.f, 255.f, \ 193 | 152.f, 0.f, 191.f, \ 194 | 101.f, 0.f, 127.f, \ 195 | 50.f, 0.f, 63.f, \ 196 | 50.f, 0.f, 255.f, \ 197 | 37.f, 0.f, 191.f, \ 198 | 25.f, 0.f, 127.f, \ 199 | 12.f, 0.f, 63.f, \ 200 | 0.f, 102.f, 255.f, \ 201 | 0.f, 76.f, 191.f, \ 202 | 0.f, 51.f, 127.f, \ 203 | 0.f, 25.f, 63.f, \ 204 | 0.f, 255.f, 255.f, \ 205 | 0.f, 191.f, 191.f, \ 206 | 0.f, 127.f, 127.f, \ 207 | 0.f, 63.f, 63.f 208 | // BODY_65 209 | // Body + left hand + right hand 210 | #define POSE_BODY_65_PAIRS_RENDER_GPU \ 211 | 1,8, 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0, 0,15, 15,17, 0,16, 16,18, 14,19,19,20,14,21, 11,22,22,23,11,24, \ 212 | 7,25, 25,26, 26,27, 27,28, 7,29, 29,30, 30,31, 31,32, 7,33, 33,34, 34,35, 35,36, 7,37, 37,38, 38,39, 39,40, 7,41, 41,42, 42,43, 43,44, \ 213 | 4,45, 45,46, 46,47, 47,48, 4,49, 49,50, 50,51, 51,52, 4,53, 53,54, 54,55, 55,56, 4,57, 57,58, 58,59, 59,60, 4,61, 61,62, 62,63, 63,64 214 | #define POSE_BODY_65_SCALES_RENDER_GPU \ 215 | 1.f,1.f,1.f,1.f,1.f, 1.f,1.f,1.f,1.f,1.f, 1.f,1.f,1.f,1.f,1.f, 1.f,1.f,1.f,1.f,1.f,1.f,1.f,1.f,1.f,1.f, \ 216 | 0.75f,0.75f,0.75f,0.75f,0.75f, 0.75f,0.75f,0.75f,0.75f,0.75f, 0.75f,0.75f,0.75f,0.75f,0.75f, 0.75f,0.75f,0.75f,0.75f,0.75f, \ 217 | 0.75f,0.75f,0.75f,0.75f,0.75f, 0.75f,0.75f,0.75f,0.75f,0.75f, 0.75f,0.75f,0.75f,0.75f,0.75f, 0.75f,0.75f,0.75f,0.75f,0.75f 218 | #define POSE_BODY_65_COLORS_RENDER_GPU \ 219 | 255.f, 0.f, 85.f, \ 220 | 255.f, 0.f, 0.f, \ 221 | 255.f, 85.f, 0.f, \ 222 | 255.f, 170.f, 0.f, \ 223 | 255.f, 255.f, 0.f, \ 224 | 170.f, 255.f, 0.f, \ 225 | 85.f, 255.f, 0.f, \ 226 | 0.f, 255.f, 0.f, \ 227 | 255.f, 0.f, 0.f, \ 228 | 0.f, 255.f, 85.f, \ 229 | 0.f, 255.f, 170.f, \ 230 | 0.f, 255.f, 255.f, \ 231 | 0.f, 170.f, 255.f, \ 232 | 0.f, 85.f, 255.f, \ 233 | 0.f, 0.f, 255.f, \ 234 | 255.f, 0.f, 170.f, \ 235 | 170.f, 0.f, 255.f, \ 236 | 255.f, 0.f, 255.f, \ 237 | 85.f, 0.f, 255.f, \ 238 | 0.f, 0.f, 255.f, \ 239 | 0.f, 0.f, 255.f, \ 240 | 0.f, 0.f, 255.f, \ 241 | 0.f, 255.f, 255.f, \ 242 | 0.f, 255.f, 255.f, \ 243 | 0.f, 255.f, 255.f, \ 244 | \ 245 | 255.f, 0.f, 0.f, \ 246 | 191.f, 47.f, 47.f, \ 247 | 127.f, 63.f, 63.f, \ 248 | 63.f, 47.f, 47.f, \ 249 | 255.f, 76.f, 0.f, \ 250 | 191.f, 57.f, 0.f, \ 251 | 127.f, 38.f, 0.f, \ 252 | 63.f, 19.f, 0.f, \ 253 | 255.f, 152.f, 0.f, \ 254 | 191.f, 114.f, 0.f, \ 255 | 127.f, 76.f, 0.f, \ 256 | 63.f, 38.f, 0.f, \ 257 | 255.f, 255.f, 0.f, \ 258 | 191.f, 191.f, 0.f, \ 259 | 127.f, 127.f, 0.f, \ 260 | 63.f, 63.f, 0.f, \ 261 | 0.f, 255.f, 0.f, \ 262 | 0.f, 191.f, 0.f, \ 263 | 0.f, 127.f, 0.f, \ 264 | 0.f, 63.f, 0.f, \ 265 | \ 266 | 255.f, 0.f, 153.f, \ 267 | 191.f, 0.f, 114.f, \ 268 | 127.f, 0.f, 76.f, \ 269 | 63.f, 0.f, 38.f, \ 270 | 203.f, 0.f, 255.f, \ 271 | 152.f, 0.f, 191.f, \ 272 | 101.f, 0.f, 127.f, \ 273 | 50.f, 0.f, 63.f, \ 274 | 50.f, 0.f, 255.f, \ 275 | 37.f, 0.f, 191.f, \ 276 | 25.f, 0.f, 127.f, \ 277 | 12.f, 0.f, 63.f, \ 278 | 0.f, 102.f, 255.f, \ 279 | 0.f, 76.f, 191.f, \ 280 | 0.f, 51.f, 127.f, \ 281 | 0.f, 25.f, 63.f, \ 282 | 0.f, 255.f, 255.f, \ 283 | 0.f, 191.f, 191.f, \ 284 | 0.f, 127.f, 127.f, \ 285 | 0.f, 63.f, 63.f 286 | // Hand color selection 287 | // http://www.perbang.dk/rgbgradient/ 288 | // 1. Main color 289 | // - Each finger of the right hand: 11 steps from FF0000 to FF0001 and pick last 5 from HSV gradient. 290 | // - Each finger of the left hand: 21 steps from FF0000 to FF0001, choosing 4 among first 6 (HSV grad.), 291 | // and then green. 292 | // Note: Choosing first 5 from 11 steps was giving 2 very close greens 293 | // 2. Gradient color from wrist to finger tips 294 | // - Inside each finger: 5 steps from main color to 000000, and selecting first 4 from RGB gradient. 295 | // Note: Used HSV gradient for red finger. 296 | 297 | // CAR_12 298 | #define POSE_CAR_12_PAIRS_RENDER_GPU \ 299 | 4,5, 4,6, 4,0, 0,2, 4,8, 8,10, 5,7, 5,1, 1,3, 5,9, 9,11, 2,3, 6,7, 10,11, 6,2,7,3, 6,10,7,11 300 | // 4,5, 4,6, 4,0, 0,2, 4,8, 8,10, 5,7, 5,1, 1,3, 5,9, 9,11 301 | #define POSE_CAR_12_SCALES_RENDER_GPU 1 302 | #define POSE_CAR_12_COLORS_RENDER_GPU \ 303 | 0.f, 255.f, 0.f, \ 304 | 0.f, 255.f, 0.f, \ 305 | 255.f, 255.f, 0.f, \ 306 | 255.f, 255.f, 0.f, \ 307 | \ 308 | 255.f, 0.f, 0.f, \ 309 | 255.f, 0.f, 0.f, \ 310 | 255.f, 75.f, 75.f, \ 311 | 255.f, 75.f, 75.f, \ 312 | \ 313 | 0.f, 0.f, 255.f, \ 314 | 0.f, 0.f, 255.f, \ 315 | 255.f, 0.f, 255.f, \ 316 | 255.f, 0.f, 255.f 317 | 318 | // Rendering functions 319 | OP_API const std::vector& getPoseScales(const PoseModel poseModel); 320 | OP_API const std::vector& getPoseColors(const PoseModel poseModel); 321 | OP_API const std::vector& getPoseBodyPartPairsRender(const PoseModel poseModel); 322 | OP_API unsigned int getNumberElementsToRender(const PoseModel poseModel); 323 | } 324 | 325 | #endif // OPENPOSE_POSE_POSE_PARAMETERS_RENDER_HPP 326 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | using namespace cv; 11 | 12 | #include "lightnet.h" 13 | #include "post_process.h" 14 | #include "os_hal.h" 15 | #include "VideoHelper.h" 16 | 17 | #include "MiniTraceHelper.h" 18 | #include "readerwriterqueue/readerwriterqueue.h" 19 | 20 | #define CVUI_IMPLEMENTATION 21 | #include "cvui/cvui.h" 22 | 23 | //#define PARALLEL_GRAB_VIDEO 24 | #define PARALLEL_RESIZE 25 | 26 | using namespace moodycamel; 27 | 28 | const char* params = 29 | "{ h help ? | false | print usage }" 30 | "{ cfg |openpose.cfg | model configuration }" 31 | "{ weights |openpose.weight | model weights }" 32 | "{@source1 |0 | source1 for processing }" 33 | "{@source2 | | source2 for processing (optional) }" 34 | "{ width | 0 | width of video or camera device}" 35 | "{ height | 0 | height of video or camera device}" 36 | "{ g gui | true | show gui, press g to toggle }" 37 | "{ f fullscreen | false | show in fullscreen, press f to toggle }" 38 | "{ fps | 0 | fps of video or camera device }" 39 | "{ single_step | | single step mode, press any key to move to next frame }" 40 | "{ l loop | true | whether to loop the video}" 41 | "{ video_pos | 0 | current position of the video file in milliseconds. }" 42 | "{ player | 1 | current position for player, press p to toggle. }" 43 | ; 44 | 45 | bool is_gui_visible = false; 46 | bool is_fullscreen = false; 47 | 48 | #define APP_NAME "Dancing Gaga" 49 | #define VER_MAJOR 0 50 | #define VER_MINOR 2 51 | #define VER_PATCH 0 52 | 53 | #define TITLE APP_NAME " " CVAUX_STR(VER_MAJOR) "." CVAUX_STR(VER_MINOR) "." CVAUX_STR(VER_PATCH) 54 | 55 | cv::Rect dancer_rois[] = 56 | { 57 | { 67,0, 240,360 }, 58 | { 335,0, 240,360 }, 59 | }; 60 | 61 | #define CONCURRENT_PKT_COUNT 1 62 | 63 | struct NetOutpus 64 | { 65 | vector net_outputs; 66 | Mat frame; 67 | int idx; 68 | }; 69 | 70 | ReaderWriterQueue q_output(CONCURRENT_PKT_COUNT); 71 | 72 | struct ControlPanel 73 | { 74 | void setup() 75 | { 76 | cvui::init(WINDOW_NAME); 77 | } 78 | 79 | void update() 80 | { 81 | int x = 10; 82 | int y = 0; 83 | int dy_small = 16; 84 | int dy_large = 50; 85 | int width = 300; 86 | frame = cv::Scalar(49, 52, 49); 87 | 88 | cvui::text(frame, x, y += dy_large, "find_heatmap_peaks_thresh"); 89 | cvui::trackbar(frame, x, y += dy_small, width, &find_heatmap_peaks_thresh, 0.0f, 1.0f); 90 | 91 | y += dy_small; 92 | 93 | cvui::text(frame, x, y += dy_large, "body_inter_min_above_th"); 94 | cvui::trackbar(frame, x, y += dy_small, width, &body_inter_min_above_th, 0, 20); 95 | 96 | cvui::text(frame, x, y += dy_large, "body_inter_th"); 97 | cvui::trackbar(frame, x, y += dy_small, width, &body_inter_th, 0.0f, 1.0f); 98 | 99 | cvui::text(frame, x, y += dy_large, "body_min_subset_cnt"); 100 | cvui::trackbar(frame, x, y += dy_small, width, &body_min_subset_cnt, 0, 20); 101 | 102 | cvui::text(frame, x, y += dy_large, "body_min_subset_score"); 103 | cvui::trackbar(frame, x, y += dy_small, width, &body_min_subset_score, 0.0f, 1.0f); 104 | 105 | y += dy_small; 106 | 107 | cvui::text(frame, x, y += dy_large, "render_thresh"); 108 | cvui::trackbar(frame, x, y += dy_small, width, &render_thresh, 0.0f, 1.0f); 109 | 110 | y += dy_small; 111 | 112 | cvui::update(); 113 | cv::imshow(WINDOW_NAME, frame); 114 | } 115 | 116 | const String WINDOW_NAME = "param"; 117 | cv::Mat frame = cv::Mat(770, 350, CV_8UC3); 118 | 119 | // param 120 | float find_heatmap_peaks_thresh = 0.05; 121 | 122 | int body_inter_min_above_th = 9; 123 | float body_inter_th = 0.05; 124 | int body_min_subset_cnt = 6; 125 | float body_min_subset_score = 0.4; 126 | 127 | float render_thresh = 0.05; 128 | }; 129 | 130 | int main(int argc, char **argv) 131 | { 132 | MiniTraceHelper mr_hepler; 133 | ControlPanel param_window; 134 | 135 | CommandLineParser parser(argc, argv, params); 136 | if (parser.get("help")) 137 | { 138 | parser.printMessage(); 139 | return 0; 140 | } 141 | 142 | auto cfg_path = parser.get("cfg"); 143 | auto weights_path = parser.get("weights"); 144 | 145 | if (cfg_path.find("body_25") != string::npos) 146 | { 147 | setPoseModel(op::PoseModel::BODY_25); 148 | cout << "setPoseModel BODY_25" << endl; 149 | } 150 | else if (cfg_path.find("mpi") != string::npos) 151 | { 152 | setPoseModel(op::PoseModel::MPI_15); 153 | cout << "setPoseModel MPI" << endl; 154 | } 155 | 156 | uint32_t NET_OUT_CHANNELS = getNetOutChannels(); 157 | 158 | Mat frame; 159 | 160 | // 1. read args 161 | is_gui_visible = parser.get("gui"); 162 | is_fullscreen = parser.get("fullscreen"); 163 | Mat upscale_frame; 164 | 165 | int player = parser.get("player"); 166 | 167 | String sources[] = { 168 | parser.get("@source1"), 169 | parser.get("@source2"), 170 | }; 171 | 172 | bool source_is_camera[] = { 173 | false, 174 | false, 175 | }; 176 | 177 | VideoCapture captures[] = { 178 | safe_open_video(parser, sources[0], &source_is_camera[0]), 179 | safe_open_video(parser, sources[1], &source_is_camera[1]), 180 | }; 181 | 182 | bool is_running = true; 183 | 184 | // 2. initialize net 185 | int net_inw = 0; 186 | int net_inh = 0; 187 | int net_outw = 0; 188 | int net_outh = 0; 189 | { 190 | MTR_SCOPE(__FILE__, "init_net"); 191 | init_net(cfg_path.c_str(), weights_path.c_str(), &net_inw, &net_inh, &net_outw, &net_outh); 192 | } 193 | 194 | float scale = 0.0f; 195 | 196 | vector net_inputs(net_inw * net_inh * 3); 197 | float* net_inputs_ptr = net_inputs.data(); 198 | 199 | std::thread CUDA([&] { 200 | MTR_META_THREAD_NAME("2) CUDA"); 201 | int frame_count = 0; 202 | 203 | Mat frames[2]; 204 | Mat input_frame; 205 | Mat input_blob; 206 | 207 | while (is_running) 208 | { 209 | MTR_SCOPE_FUNC_I("frame", frame_count); 210 | 211 | { 212 | MTR_SCOPE(__FILE__, "pre process"); 213 | 214 | #ifdef PARALLEL_GRAB_VIDEO 215 | parallel_for_(Range(0, 2), [&](const Range& range) { for (int i = range.start; i < range.end; i++) 216 | #else 217 | for (int i = 0; i < 2; i++) 218 | #endif 219 | { 220 | if (!safe_grab_video(captures[i], parser, frames[i], sources[i], source_is_camera[i])) 221 | { 222 | is_running = false; 223 | } 224 | } 225 | #ifdef PARALLEL_GRAB_VIDEO 226 | }); 227 | #endif 228 | 229 | if (!is_running) break; 230 | 231 | { 232 | if (captures[1].isOpened()) 233 | { 234 | MTR_SCOPE(__FILE__, "mix"); 235 | 236 | float ar = dancer_rois[player].width / (float)dancer_rois[player].height; 237 | 238 | int crop_h = frames[0].rows; 239 | int crop_w = ar * crop_h; 240 | int crop_x = (frames[0].cols - crop_w) * 0.5f; 241 | int crop_y = 0; 242 | Rect src_crop{ 243 | crop_x, crop_y, 244 | crop_w, crop_h, 245 | }; 246 | Rect dst_crop = dancer_rois[player]; 247 | frame = frames[1]; 248 | 249 | resize(frames[0](src_crop), frame(dst_crop), dst_crop.size()); 250 | } 251 | else 252 | { 253 | frame = frames[0]; 254 | } 255 | } 256 | 257 | { 258 | MTR_SCOPE(__FILE__, "Mat to float*"); 259 | 260 | // 3. resize to net input size, put scaled image on the top left 261 | create_netsize_im(frame, input_frame, net_inw, net_inh, &scale); 262 | input_blob = dnn::blobFromImage(input_frame, 1.0f / 255, Size(net_inw, net_inh), Scalar(127, 127, 127), false); 263 | } 264 | } 265 | 266 | // 6. feed forward 267 | float *netoutdata = NULL; 268 | TickMeter tick; 269 | { 270 | MTR_SCOPE(__FILE__, "run_net"); 271 | tick.start(); 272 | netoutdata = run_net(input_blob); 273 | tick.stop(); 274 | cout << "forward fee: " << tick.getTimeMilli() << "ms" << endl; 275 | } 276 | 277 | NetOutpus pkt; 278 | pkt.net_outputs = { netoutdata, netoutdata + net_outh*net_outw*NET_OUT_CHANNELS }; 279 | pkt.idx = frame_count; 280 | pkt.frame = frame; 281 | q_output.try_emplace(pkt); 282 | 283 | frame_count++; 284 | } 285 | 286 | is_running = false; 287 | }); 288 | 289 | std::thread postCUDA([&]() { 290 | int frame_count = 0; 291 | MTR_META_THREAD_NAME("3) post CUDA"); 292 | 293 | vector heatmap_peaks(3 * (POSE_MAX_PEOPLE + 1) * (NET_OUT_CHANNELS - 1)); 294 | vector heatmap(net_inw * net_inh * NET_OUT_CHANNELS); 295 | 296 | param_window.setup(); 297 | 298 | while (is_running) 299 | { 300 | NetOutpus pkt; 301 | if (!q_output.try_dequeue(pkt)) 302 | continue; 303 | 304 | MTR_SCOPE_FUNC_I("frame", pkt.idx); 305 | frame_count++; 306 | 307 | float* netoutdata = pkt.net_outputs.data(); 308 | 309 | vector keypoints; 310 | vector keyshape; 311 | { 312 | MTR_SCOPE(__FILE__, "post process"); 313 | 314 | // 7. resize net output back to input size to get heatmap 315 | #ifdef PARALLEL_RESIZE 316 | parallel_for_(Range(0, NET_OUT_CHANNELS), [&](const Range& range) { for (int i = range.start; i < range.end; i++) 317 | #else 318 | for (int i = 0; i < NET_OUT_CHANNELS; ++i) 319 | #endif 320 | { 321 | MTR_SCOPE(__FILE__, "resize"); 322 | Mat netout(net_outh, net_outw, CV_32F, (netoutdata + net_outh*net_outw*i)); 323 | Mat nmsin(net_inh, net_inw, CV_32F, heatmap.data() + net_inh*net_inw*i); 324 | resize(netout, nmsin, Size(net_inw, net_inh), 0, 0, CV_INTER_CUBIC); 325 | } 326 | #ifdef PARALLEL_RESIZE 327 | }); 328 | #endif 329 | // 8. get heatmap peaks 330 | find_heatmap_peaks(heatmap.data(), heatmap_peaks.data(), net_inw, net_inh, NET_OUT_CHANNELS, param_window.find_heatmap_peaks_thresh); 331 | 332 | // 9. link parts 333 | connect_bodyparts(keypoints, heatmap.data(), heatmap_peaks.data(), net_inw, net_inh, 334 | param_window.body_inter_min_above_th, 335 | param_window.body_inter_th, 336 | param_window.body_min_subset_cnt, 337 | param_window.body_min_subset_score, 338 | keyshape); 339 | } 340 | 341 | { 342 | MTR_SCOPE(__FILE__, "viz"); 343 | // 10. draw result 344 | if (is_fullscreen) 345 | { 346 | if (upscale_frame.empty()) 347 | { 348 | int w, h; 349 | getScreenResolution(w, h); 350 | float ar = frame.cols / (float)frame.rows; 351 | upscale_frame = Mat(h, h * ar, CV_8UC3); 352 | 353 | setWindowProperty(TITLE, WND_PROP_FULLSCREEN, WINDOW_FULLSCREEN); 354 | moveWindow(TITLE, 0, 0); 355 | } 356 | 357 | MTR_SCOPE(__FILE__, "upscale"); 358 | resize(pkt.frame, upscale_frame, upscale_frame.size()); 359 | pkt.frame = upscale_frame; 360 | scale = upscale_frame.cols / (float)net_inw; 361 | } 362 | render_pose_keypoints(pkt.frame, keypoints, keyshape, param_window.render_thresh, scale); 363 | 364 | { 365 | int num_persons = keyshape[0]; 366 | int num_joints = keyshape[1]; 367 | int dim_joint = keyshape[2]; 368 | for (int person = 0; person < num_persons; ++person) 369 | { 370 | for (int part = 0; part < num_joints; ++part) 371 | { 372 | int index = (person * num_joints + part) * dim_joint; 373 | if (keypoints[index + 2] > param_window.render_thresh) 374 | { 375 | //Point center{keypoints[index] * scale, keypoints[index + 1] * scale}; 376 | //if (center.y < 200) 377 | //{ 378 | //} 379 | } 380 | } 381 | } 382 | } 383 | 384 | // 11. show and save result 385 | { 386 | MTR_SCOPE(__FILE__, "imshow"); 387 | cout << "people: " << keyshape[0] << endl; 388 | 389 | imshow(TITLE, pkt.frame); 390 | if (is_gui_visible) 391 | { 392 | param_window.update(); 393 | } 394 | } 395 | 396 | { 397 | MTR_SCOPE(__FILE__, "waitkey"); 398 | int key = waitKey(1); 399 | if (key == 27) break; 400 | if (key == 'f') is_fullscreen = !is_fullscreen; 401 | if (key == 'g') is_gui_visible = !is_gui_visible; 402 | if (key == 'p') player = 1 - player; 403 | } 404 | } 405 | } 406 | is_running = false; 407 | }); 408 | 409 | CUDA.join(); 410 | postCUDA.join(); 411 | 412 | return 0; 413 | } 414 | -------------------------------------------------------------------------------- /src/post_process.cpp: -------------------------------------------------------------------------------- 1 | #include "post_process.h" 2 | #include "minitrace/minitrace.h" 3 | #include "openpose/poseParameters.hpp" 4 | #include "openpose/poseParametersRender.hpp" 5 | 6 | using namespace std; 7 | using namespace cv; 8 | using namespace op; 9 | 10 | template 11 | inline int intRound(const T a) 12 | { 13 | return int(a + 0.5f); 14 | } 15 | 16 | template 17 | inline T fastMin(const T a, const T b) 18 | { 19 | return (a < b ? a : b); 20 | } 21 | 22 | static PoseModel s_model = PoseModel::COCO_18; 23 | 24 | void setPoseModel(PoseModel model) 25 | { 26 | s_model = model; 27 | } 28 | 29 | uint32_t getNetOutChannels() 30 | { 31 | // #define NET_OUT_CHANNELS 57 // 38 for pafs, 19 for parts 32 | return getPoseNumberBodyParts(s_model) + 1 + getPoseMapIndex(s_model).size(); 33 | } 34 | 35 | void render_pose_keypoints( 36 | Mat &frame, 37 | const vector &keypoints, 38 | vector keyshape, 39 | const float threshold, 40 | float scale) 41 | { 42 | MTR_SCOPE_FUNC(); 43 | 44 | const int num_keypoints = keyshape[1]; 45 | 46 | vector pairs; 47 | vector colors; 48 | if (s_model == PoseModel::BODY_25) 49 | { 50 | pairs = { 51 | POSE_BODY_25_PAIRS_RENDER_GPU 52 | }; 53 | colors = { 54 | POSE_BODY_25_COLORS_RENDER_GPU 55 | }; 56 | } 57 | else if (s_model == PoseModel::MPI_15) 58 | { 59 | pairs = { 60 | POSE_MPI_PAIRS_RENDER_GPU 61 | }; 62 | colors = { 63 | POSE_MPI_COLORS_RENDER_GPU 64 | }; 65 | } 66 | else /*if (s_model == PoseModel::COCO_18)*/ 67 | { 68 | pairs = { 69 | POSE_COCO_PAIRS_RENDER_GPU 70 | }; 71 | colors = { 72 | POSE_COCO_COLORS_RENDER_GPU 73 | }; 74 | } 75 | 76 | const int pairs_size = pairs.size(); 77 | const int number_colors = colors.size(); 78 | 79 | for (int person = 0; person < keyshape[0]; ++person) 80 | { 81 | // Draw lines 82 | for (int pair = 0u; pair < pairs_size; pair += 2) 83 | { 84 | const int index1 = (person * num_keypoints + pairs[pair]) * keyshape[2]; 85 | const int index2 = (person * num_keypoints + pairs[pair + 1]) * keyshape[2]; 86 | if (keypoints[index1 + 2] > threshold && keypoints[index2 + 2] > threshold) 87 | { 88 | const int color_index = pairs[pair + 1] * 3; 89 | Scalar color{colors[(color_index + 2) % number_colors], 90 | colors[(color_index + 1) % number_colors], 91 | colors[(color_index + 0) % number_colors]}; 92 | Point keypoint1{intRound(keypoints[index1] * scale), intRound(keypoints[index1 + 1] * scale)}; 93 | Point keypoint2{intRound(keypoints[index2] * scale), intRound(keypoints[index2 + 1] * scale)}; 94 | line(frame, keypoint1, keypoint2, color, 2); 95 | } 96 | } 97 | // Draw circles 98 | for (int part = 0; part < num_keypoints; ++part) 99 | { 100 | const int index = (person * num_keypoints + part) * keyshape[2]; 101 | if (keypoints[index + 2] > threshold) 102 | { 103 | const int color_index = part * 3; 104 | Scalar color{colors[(color_index + 2) % number_colors], 105 | colors[(color_index + 1) % number_colors], 106 | colors[(color_index + 0) % number_colors]}; 107 | Point center{intRound(keypoints[index] * scale), intRound(keypoints[index + 1] * scale)}; 108 | circle(frame, center, 3, color, -1); 109 | } 110 | } 111 | } 112 | } 113 | 114 | void connect_bodyparts( 115 | vector &pose_keypoints, 116 | const float *const map, 117 | const float *const peaks, 118 | int mapw, 119 | int maph, 120 | const int inter_min_above_th, 121 | const float inter_th, 122 | const int min_subset_cnt, 123 | const float min_subset_score, 124 | vector &keypoint_shape) 125 | { 126 | MTR_SCOPE_FUNC(); 127 | 128 | keypoint_shape.resize(3); 129 | 130 | const vector& body_part_pairs = getPosePartPairs(s_model); 131 | const vector& limb_idx = getPoseMapIndex(s_model); 132 | const int num_body_parts = getPoseNumberBodyParts(s_model); 133 | const int num_body_part_pairs = body_part_pairs.size() / 2; 134 | std::vector, double>> subset; 135 | const int subset_counter_index = num_body_parts; 136 | const int subset_size = num_body_parts + 1; 137 | const int peaks_offset = 3 * (POSE_MAX_PEOPLE + 1); 138 | const int map_offset = mapw * maph; 139 | 140 | for (unsigned int pair_index = 0u; pair_index < num_body_part_pairs; ++pair_index) 141 | { 142 | const int body_partA = body_part_pairs[2 * pair_index]; 143 | const int body_partB = body_part_pairs[2 * pair_index + 1]; 144 | const float *candidateA = peaks + body_partA * peaks_offset; 145 | const float *candidateB = peaks + body_partB * peaks_offset; 146 | const int nA = (int)(candidateA[0]); // number of part A candidates 147 | const int nB = (int)(candidateB[0]); // number of part B candidates 148 | 149 | // add parts into the subset in special case 150 | if (nA == 0 || nB == 0) 151 | { 152 | // Change w.r.t. other 153 | if (nA == 0) // nB == 0 or not 154 | { 155 | for (int i = 1; i <= nB; ++i) 156 | { 157 | bool num = false; 158 | for (unsigned int j = 0u; j < subset.size(); ++j) 159 | { 160 | const int off = body_partB * peaks_offset + i * 3 + 2; 161 | if (subset[j].first[body_partB] == off) 162 | { 163 | num = true; 164 | break; 165 | } 166 | } 167 | if (!num) 168 | { 169 | std::vector row_vector(subset_size, 0); 170 | // store the index 171 | row_vector[body_partB] = body_partB * peaks_offset + i * 3 + 2; 172 | // the parts number of that person 173 | row_vector[subset_counter_index] = 1; 174 | // total score 175 | const float subsetScore = candidateB[i * 3 + 2]; 176 | subset.emplace_back(std::make_pair(row_vector, subsetScore)); 177 | } 178 | } 179 | } 180 | else // if (nA != 0 && nB == 0) 181 | { 182 | for (int i = 1; i <= nA; i++) 183 | { 184 | bool num = false; 185 | for (unsigned int j = 0u; j < subset.size(); ++j) 186 | { 187 | const int off = body_partA * peaks_offset + i * 3 + 2; 188 | if (subset[j].first[body_partA] == off) 189 | { 190 | num = true; 191 | break; 192 | } 193 | } 194 | if (!num) 195 | { 196 | std::vector row_vector(subset_size, 0); 197 | // store the index 198 | row_vector[body_partA] = body_partA * peaks_offset + i * 3 + 2; 199 | // parts number of that person 200 | row_vector[subset_counter_index] = 1; 201 | // total score 202 | const float subsetScore = candidateA[i * 3 + 2]; 203 | subset.emplace_back(std::make_pair(row_vector, subsetScore)); 204 | } 205 | } 206 | } 207 | } 208 | else // if (nA != 0 && nB != 0) 209 | { 210 | std::vector> temp; 211 | const int num_inter = 10; 212 | // limb PAF x-direction heatmap 213 | const float *const mapX = map + (num_body_part_pairs + limb_idx[2 * pair_index]) * map_offset; 214 | // limb PAF y-direction heatmap 215 | const float *const mapY = map + (num_body_part_pairs + limb_idx[2 * pair_index + 1]) * map_offset; 216 | // start greedy algorithm 217 | for (int i = 1; i <= nA; i++) 218 | { 219 | for (int j = 1; j <= nB; j++) 220 | { 221 | const int dX = candidateB[j * 3] - candidateA[i * 3]; 222 | const int dY = candidateB[j * 3 + 1] - candidateA[i * 3 + 1]; 223 | const float norm_vec = float(std::sqrt(dX * dX + dY * dY)); 224 | // If the peaksPtr are coincident. Don't connect them. 225 | if (norm_vec > 1e-6) 226 | { 227 | const float sX = candidateA[i * 3]; 228 | const float sY = candidateA[i * 3 + 1]; 229 | const float vecX = dX / norm_vec; 230 | const float vecY = dY / norm_vec; 231 | float sum = 0.; 232 | int count = 0; 233 | for (int lm = 0; lm < num_inter; lm++) 234 | { 235 | const int mX = fastMin(mapw - 1, intRound(sX + lm * dX / num_inter)); 236 | const int mY = fastMin(maph - 1, intRound(sY + lm * dY / num_inter)); 237 | const int idx = mY * mapw + mX; 238 | const float score = (vecX * mapX[idx] + vecY * mapY[idx]); 239 | if (score > inter_th) 240 | { 241 | sum += score; 242 | ++count; 243 | } 244 | } 245 | 246 | // parts score + connection score 247 | if (count > inter_min_above_th) 248 | { 249 | temp.emplace_back(std::make_tuple(sum / count, i, j)); 250 | } 251 | } 252 | } 253 | } 254 | // select the top minAB connection, assuming that each part occur only once 255 | // sort rows in descending order based on parts + connection score 256 | if (!temp.empty()) 257 | { 258 | std::sort(temp.begin(), temp.end(), std::greater>()); 259 | } 260 | std::vector> connectionK; 261 | 262 | const int minAB = fastMin(nA, nB); 263 | // assuming that each part occur only once, filter out same part1 to different part2 264 | std::vector occurA(nA, 0); 265 | std::vector occurB(nB, 0); 266 | int counter = 0; 267 | for (unsigned int row = 0u; row < temp.size(); row++) 268 | { 269 | const float score = std::get<0>(temp[row]); 270 | const int aidx = std::get<1>(temp[row]); 271 | const int bidx = std::get<2>(temp[row]); 272 | if (!occurA[aidx - 1] && !occurB[bidx - 1]) 273 | { 274 | // save two part score "position" and limb mean PAF score 275 | connectionK.emplace_back(std::make_tuple(body_partA * peaks_offset + aidx * 3 + 2, 276 | body_partB * peaks_offset + bidx * 3 + 2, score)); 277 | ++counter; 278 | if (counter == minAB) 279 | { 280 | break; 281 | } 282 | occurA[aidx - 1] = 1; 283 | occurB[bidx - 1] = 1; 284 | } 285 | } 286 | // Cluster all the body part candidates into subset based on the part connection 287 | // initialize first body part connection 288 | if (pair_index == 0) 289 | { 290 | for (const auto connectionKI : connectionK) 291 | { 292 | std::vector row_vector(num_body_parts + 3, 0); 293 | const int indexA = std::get<0>(connectionKI); 294 | const int indexB = std::get<1>(connectionKI); 295 | const double score = std::get<2>(connectionKI); 296 | row_vector[body_part_pairs[0]] = indexA; 297 | row_vector[body_part_pairs[1]] = indexB; 298 | row_vector[subset_counter_index] = 2; 299 | // add the score of parts and the connection 300 | const double subset_score = peaks[indexA] + peaks[indexB] + score; 301 | subset.emplace_back(std::make_pair(row_vector, subset_score)); 302 | } 303 | } 304 | // Add ears connections (in case person is looking to opposite direction to camera) 305 | else if (pair_index == 17 || pair_index == 18) 306 | { 307 | for (const auto &connectionKI : connectionK) 308 | { 309 | const int indexA = std::get<0>(connectionKI); 310 | const int indexB = std::get<1>(connectionKI); 311 | for (auto &subsetJ : subset) 312 | { 313 | auto &subsetJ_first = subsetJ.first[body_partA]; 314 | auto &subsetJ_first_plus1 = subsetJ.first[body_partB]; 315 | if (subsetJ_first == indexA && subsetJ_first_plus1 == 0) 316 | { 317 | subsetJ_first_plus1 = indexB; 318 | } 319 | else if (subsetJ_first_plus1 == indexB && subsetJ_first == 0) 320 | { 321 | subsetJ_first = indexA; 322 | } 323 | } 324 | } 325 | } 326 | else 327 | { 328 | if (!connectionK.empty()) 329 | { 330 | for (unsigned int i = 0u; i < connectionK.size(); ++i) 331 | { 332 | const int indexA = std::get<0>(connectionK[i]); 333 | const int indexB = std::get<1>(connectionK[i]); 334 | const double score = std::get<2>(connectionK[i]); 335 | int num = 0; 336 | // if A is already in the subset, add B 337 | for (unsigned int j = 0u; j < subset.size(); j++) 338 | { 339 | if (subset[j].first[body_partA] == indexA) 340 | { 341 | subset[j].first[body_partB] = indexB; 342 | ++num; 343 | subset[j].first[subset_counter_index] = subset[j].first[subset_counter_index] + 1; 344 | subset[j].second = subset[j].second + peaks[indexB] + score; 345 | } 346 | } 347 | // if A is not found in the subset, create new one and add both 348 | if (num == 0) 349 | { 350 | std::vector row_vector(subset_size, 0); 351 | row_vector[body_partA] = indexA; 352 | row_vector[body_partB] = indexB; 353 | row_vector[subset_counter_index] = 2; 354 | const float subsetScore = peaks[indexA] + peaks[indexB] + score; 355 | subset.emplace_back(std::make_pair(row_vector, subsetScore)); 356 | } 357 | } 358 | } 359 | } 360 | } 361 | } 362 | 363 | // Delete people below thresholds, and save to output 364 | int number_people = 0; 365 | std::vector valid_subset_indexes; 366 | valid_subset_indexes.reserve(fastMin((size_t)POSE_MAX_PEOPLE, subset.size())); 367 | for (unsigned int index = 0; index < subset.size(); ++index) 368 | { 369 | const int subset_counter = subset[index].first[subset_counter_index]; 370 | const double subset_score = subset[index].second; 371 | if (subset_counter >= min_subset_cnt && (subset_score / subset_counter) > min_subset_score) 372 | { 373 | ++number_people; 374 | valid_subset_indexes.emplace_back(index); 375 | if (number_people == POSE_MAX_PEOPLE) 376 | { 377 | break; 378 | } 379 | } 380 | } 381 | 382 | // Fill and return pose_keypoints 383 | keypoint_shape = {number_people, (int)num_body_parts, 3}; 384 | if (number_people > 0) 385 | { 386 | pose_keypoints.resize(number_people * (int)num_body_parts * 3); 387 | } 388 | else 389 | { 390 | pose_keypoints.clear(); 391 | } 392 | for (unsigned int person = 0u; person < valid_subset_indexes.size(); ++person) 393 | { 394 | const auto &subsetI = subset[valid_subset_indexes[person]].first; 395 | for (int bodyPart = 0u; bodyPart < num_body_parts; bodyPart++) 396 | { 397 | const int base_offset = (person * num_body_parts + bodyPart) * 3; 398 | const int body_part_index = subsetI[bodyPart]; 399 | if (body_part_index > 0) 400 | { 401 | pose_keypoints[base_offset] = peaks[body_part_index - 2]; 402 | pose_keypoints[base_offset + 1] = peaks[body_part_index - 1]; 403 | pose_keypoints[base_offset + 2] = peaks[body_part_index]; 404 | } 405 | else 406 | { 407 | pose_keypoints[base_offset] = 0.f; 408 | pose_keypoints[base_offset + 1] = 0.f; 409 | pose_keypoints[base_offset + 2] = 0.f; 410 | } 411 | } 412 | } 413 | } 414 | 415 | void find_heatmap_peaks( 416 | const float *src, 417 | float *dst, 418 | const int SRCW, 419 | const int SRCH, 420 | const int SRC_CH, 421 | const float TH) 422 | { 423 | MTR_SCOPE_FUNC(); 424 | 425 | // find peaks (8-connected neighbor), weights with 7 by 7 area to get sub-pixel location and response 426 | const int SRC_PLANE_OFFSET = SRCW * SRCH; 427 | // add 1 for saving total people count, 3 for x, y, score 428 | const int DST_PLANE_OFFSET = (POSE_MAX_PEOPLE + 1) * 3; 429 | float *dstptr = dst; 430 | int c = 0; 431 | int x = 0; 432 | int y = 0; 433 | int i = 0; 434 | int j = 0; 435 | // TODO: reduce multiplication by using pointer 436 | for (c = 0; c < SRC_CH - 1; ++c) 437 | { 438 | int num_people = 0; 439 | for (y = 1; y < SRCH - 1 && num_people != POSE_MAX_PEOPLE; ++y) 440 | { 441 | for (x = 1; x < SRCW - 1 && num_people != POSE_MAX_PEOPLE; ++x) 442 | { 443 | int idx = y * SRCW + x; 444 | float value = src[idx]; 445 | if (value > TH) 446 | { 447 | const float TOPLEFT = src[idx - SRCW - 1]; 448 | const float TOP = src[idx - SRCW]; 449 | const float TOPRIGHT = src[idx - SRCW + 1]; 450 | const float LEFT = src[idx - 1]; 451 | const float RIGHT = src[idx + 1]; 452 | const float BUTTOMLEFT = src[idx + SRCW - 1]; 453 | const float BUTTOM = src[idx + SRCW]; 454 | const float BUTTOMRIGHT = src[idx + SRCW + 1]; 455 | if (value > TOPLEFT && value > TOP && value > TOPRIGHT && value > LEFT && 456 | value > RIGHT && value > BUTTOMLEFT && value > BUTTOM && value > BUTTOMRIGHT) 457 | { 458 | float x_acc = 0; 459 | float y_acc = 0; 460 | float score_acc = 0; 461 | for (i = -3; i <= 3; ++i) 462 | { 463 | int ux = x + i; 464 | if (ux >= 0 && ux < SRCW) 465 | { 466 | for (j = -3; j <= 3; ++j) 467 | { 468 | int uy = y + j; 469 | if (uy >= 0 && uy < SRCH) 470 | { 471 | float score = src[uy * SRCW + ux]; 472 | x_acc += ux * score; 473 | y_acc += uy * score; 474 | score_acc += score; 475 | } 476 | } 477 | } 478 | } 479 | x_acc /= score_acc; 480 | y_acc /= score_acc; 481 | score_acc = value; 482 | dstptr[(num_people + 1) * 3 + 0] = x_acc; 483 | dstptr[(num_people + 1) * 3 + 1] = y_acc; 484 | dstptr[(num_people + 1) * 3 + 2] = score_acc; 485 | ++num_people; 486 | } 487 | } 488 | } 489 | } 490 | dstptr[0] = num_people; 491 | src += SRC_PLANE_OFFSET; 492 | dstptr += DST_PLANE_OFFSET; 493 | } 494 | } 495 | 496 | void create_netsize_im( 497 | const Mat &input, 498 | Mat &output, 499 | const int netw, 500 | const int neth, 501 | float *scale) 502 | { 503 | MTR_SCOPE_FUNC(); 504 | 505 | CV_Assert(!input.empty()); 506 | 507 | // for tall image 508 | int newh = neth; 509 | float s = newh / (float)input.rows; 510 | int neww = input.cols * s; 511 | if (neww > netw) 512 | { 513 | //for fat image 514 | neww = netw; 515 | s = neww / (float)input.cols; 516 | newh = input.rows * s; 517 | } 518 | 519 | *scale = 1 / s; 520 | Rect dst_area(0, 0, neww, newh); 521 | if (output.empty()) 522 | { 523 | output = Mat::zeros(neth, netw, CV_8UC3); 524 | } 525 | 526 | resize(input, output(dst_area), Size(neww, newh)); 527 | } 528 | -------------------------------------------------------------------------------- /src/openpose/poseParameters.cpp: -------------------------------------------------------------------------------- 1 | #include "poseParameters.hpp" 2 | #include "poseParametersRender.hpp" 3 | #include 4 | #include "opencv2/core.hpp" 5 | 6 | namespace op 7 | { 8 | // Body parts mapping 9 | const std::map POSE_BODY_25_BODY_PARTS { 10 | {0, "Nose"}, 11 | {1, "Neck"}, 12 | {2, "RShoulder"}, 13 | {3, "RElbow"}, 14 | {4, "RWrist"}, 15 | {5, "LShoulder"}, 16 | {6, "LElbow"}, 17 | {7, "LWrist"}, 18 | {8, "MidHip"}, 19 | {9, "RHip"}, 20 | {10, "RKnee"}, 21 | {11, "RAnkle"}, 22 | {12, "LHip"}, 23 | {13, "LKnee"}, 24 | {14, "LAnkle"}, 25 | {15, "REye"}, 26 | {16, "LEye"}, 27 | {17, "REar"}, 28 | {18, "LEar"}, 29 | {19, "LBigToe"}, 30 | {20, "LSmallToe"}, 31 | {21, "LHeel"}, 32 | {22, "RBigToe"}, 33 | {23, "RSmallToe"}, 34 | {24, "RHeel"}, 35 | {25, "Background"} 36 | }; 37 | const std::map POSE_COCO_BODY_PARTS { 38 | {0, "Nose"}, 39 | {1, "Neck"}, 40 | {2, "RShoulder"}, 41 | {3, "RElbow"}, 42 | {4, "RWrist"}, 43 | {5, "LShoulder"}, 44 | {6, "LElbow"}, 45 | {7, "LWrist"}, 46 | {8, "RHip"}, 47 | {9, "RKnee"}, 48 | {10, "RAnkle"}, 49 | {11, "LHip"}, 50 | {12, "LKnee"}, 51 | {13, "LAnkle"}, 52 | {14, "REye"}, 53 | {15, "LEye"}, 54 | {16, "REar"}, 55 | {17, "LEar"}, 56 | {18, "Background"} 57 | }; 58 | const std::map POSE_MPI_BODY_PARTS { 59 | {0, "Head"}, 60 | {1, "Neck"}, 61 | {2, "RShoulder"}, 62 | {3, "RElbow"}, 63 | {4, "RWrist"}, 64 | {5, "LShoulder"}, 65 | {6, "LElbow"}, 66 | {7, "LWrist"}, 67 | {8, "RHip"}, 68 | {9, "RKnee"}, 69 | {10, "RAnkle"}, 70 | {11, "LHip"}, 71 | {12, "LKnee"}, 72 | {13, "LAnkle"}, 73 | {14, "Chest"}, 74 | {15, "Background"} 75 | }; 76 | const std::map POSE_BODY_19_BODY_PARTS { 77 | {0, "Nose"}, 78 | {1, "Neck"}, 79 | {2, "RShoulder"}, 80 | {3, "RElbow"}, 81 | {4, "RWrist"}, 82 | {5, "LShoulder"}, 83 | {6, "LElbow"}, 84 | {7, "LWrist"}, 85 | {8, "MidHip"}, 86 | {9, "RHip"}, 87 | {10, "RKnee"}, 88 | {11, "RAnkle"}, 89 | {12, "LHip"}, 90 | {13, "LKnee"}, 91 | {14, "LAnkle"}, 92 | {15, "REye"}, 93 | {16, "LEye"}, 94 | {17, "REar"}, 95 | {18, "LEar"}, 96 | {19, "Background"} 97 | }; 98 | const std::map POSE_BODY_59_BODY_PARTS { 99 | // Body 100 | {0, "Nose"}, 101 | {1, "Neck"}, 102 | {2, "RShoulder"}, 103 | {3, "RElbow"}, 104 | {4, "RWrist"}, 105 | {5, "LShoulder"}, 106 | {6, "LElbow"}, 107 | {7, "LWrist"}, 108 | {8, "MidHip"}, 109 | {9, "RHip"}, 110 | {10, "RKnee"}, 111 | {11, "RAnkle"}, 112 | {12, "LHip"}, 113 | {13, "LKnee"}, 114 | {14, "LAnkle"}, 115 | {15, "REye"}, 116 | {16, "LEye"}, 117 | {17, "REar"}, 118 | {18, "LEar"}, 119 | // Left hand 120 | {19, "LThumb1CMC"}, {20, "LThumb2Knuckles"},{21, "LThumb3IP"}, {22, "LThumb4FingerTip"}, 121 | {23, "LIndex1Knuckles"}, {24, "LIndex2PIP"}, {25, "LIndex3DIP"}, {26, "LIndex4FingerTip"}, 122 | {27, "LMiddle1Knuckles"}, {28, "LMiddle2PIP"}, {29, "LMiddle3DIP"},{30, "LMiddle4FingerTip"}, 123 | {31, "LRing1Knuckles"}, {32, "LRing2PIP"}, {33, "LRing3DIP"}, {34, "LRing4FingerTip"}, 124 | {35, "LPinky1Knuckles"}, {36, "LPinky2PIP"}, {37, "LPinky3DIP"}, {38, "LPinky4FingerTip"}, 125 | // Right hand 126 | {39, "RThumb1CMC"}, {40, "RThumb2Knuckles"},{41, "RThumb3IP"}, {42, "RThumb4FingerTip"}, 127 | {43, "RIndex1Knuckles"}, {44, "RIndex2PIP"}, {45, "RIndex3DIP"}, {46, "RIndex4FingerTip"}, 128 | {47, "RMiddle1Knuckles"}, {48, "RMiddle2PIP"}, {49, "RMiddle3DIP"},{50, "RMiddle4FingerTip"}, 129 | {51, "RRing1Knuckles"}, {52, "RRing2PIP"}, {53, "RRing3DIP"}, {54, "RRing4FingerTip"}, 130 | {55, "RPinky1Knuckles"}, {56, "RPinky2PIP"}, {57, "RPinky3DIP"}, {58, "RPinky4FingerTip"}, 131 | // Background 132 | {59, "Background"}, 133 | }; 134 | const std::map POSE_BODY_65_BODY_PARTS { 135 | // Body 136 | {0, "Nose"}, 137 | {1, "Neck"}, 138 | {2, "RShoulder"}, 139 | {3, "RElbow"}, 140 | {4, "RWrist"}, 141 | {5, "LShoulder"}, 142 | {6, "LElbow"}, 143 | {7, "LWrist"}, 144 | {8, "MidHip"}, 145 | {9, "RHip"}, 146 | {10, "RKnee"}, 147 | {11, "RAnkle"}, 148 | {12, "LHip"}, 149 | {13, "LKnee"}, 150 | {14, "LAnkle"}, 151 | {15, "REye"}, 152 | {16, "LEye"}, 153 | {17, "REar"}, 154 | {18, "LEar"}, 155 | {19, "LBigToe"}, 156 | {20, "LSmallToe"}, 157 | {21, "LHeel"}, 158 | {22, "RBigToe"}, 159 | {23, "RSmallToe"}, 160 | {24, "RHeel"}, 161 | // Left hand 162 | {25, "LThumb1CMC"}, {26, "LThumb2Knuckles"},{27, "LThumb3IP"}, {28, "LThumb4FingerTip"}, 163 | {29, "LIndex1Knuckles"}, {30, "LIndex2PIP"}, {31, "LIndex3DIP"}, {32, "LIndex4FingerTip"}, 164 | {33, "LMiddle1Knuckles"}, {34, "LMiddle2PIP"}, {35, "LMiddle3DIP"},{36, "LMiddle4FingerTip"}, 165 | {37, "LRing1Knuckles"}, {38, "LRing2PIP"}, {39, "LRing3DIP"}, {40, "LRing4FingerTip"}, 166 | {41, "LPinky1Knuckles"}, {42, "LPinky2PIP"}, {43, "LPinky3DIP"}, {44, "LPinky4FingerTip"}, 167 | // Right hand 168 | {45, "RThumb1CMC"}, {46, "RThumb2Knuckles"},{47, "RThumb3IP"}, {48, "RThumb4FingerTip"}, 169 | {49, "RIndex1Knuckles"}, {50, "RIndex2PIP"}, {51, "RIndex3DIP"}, {52, "RIndex4FingerTip"}, 170 | {53, "RMiddle1Knuckles"}, {54, "RMiddle2PIP"}, {55, "RMiddle3DIP"},{56, "RMiddle4FingerTip"}, 171 | {57, "RRing1Knuckles"}, {58, "RRing2PIP"}, {59, "RRing3DIP"}, {60, "RRing4FingerTip"}, 172 | {61, "RPinky1Knuckles"}, {62, "RPinky2PIP"}, {63, "RPinky3DIP"}, {64, "RPinky4FingerTip"}, 173 | // Background 174 | {65, "Background"}, 175 | }; 176 | // Hand legend: 177 | // - Thumb: 178 | // - Carpometacarpal Joints (CMC) 179 | // - Interphalangeal Joints (IP) 180 | // - Other fingers: 181 | // - Knuckles or Metacarpophalangeal Joints (MCP) 182 | // - PIP (Proximal Interphalangeal Joints) 183 | // - DIP (Distal Interphalangeal Joints) 184 | // - All fingers: 185 | // - Fingertips 186 | // More information: Page 6 of http://www.mccc.edu/~behrensb/documents/TheHandbig.pdf 187 | const std::map POSE_CAR_12_PARTS { 188 | {0, "FRWheel"}, 189 | {1, "FLWheel"}, 190 | {2, "BRWheel"}, 191 | {3, "BLWheel"}, 192 | {4, "FRLight"}, 193 | {5, "FLLight"}, 194 | {6, "BRLight"}, 195 | {7, "BLLight"}, 196 | {8, "FRTop"}, 197 | {9, "FLTop"}, 198 | {10, "BRTop"}, 199 | {11, "BLTop"}, 200 | {12, "Background"}, 201 | }; 202 | const std::array, (int)PoseModel::Size> POSE_MAP_INDEX { 203 | // BODY_25 204 | std::vector{ 205 | 0,1, 14,15, 22,23, 16,17, 18,19, 24,25, 26,27, 6,7, 2,3, 4,5, 8,9, 10,11, 12,13, 30,31, 32,33, 36,37, 34,35, 38,39, 20,21, 28,29, 40,41,42,43,44,45, 46,47,48,49,50,51 206 | }, 207 | // COCO 208 | std::vector{ 209 | 12,13, 20,21, 14,15, 16,17, 22,23, 24,25, 0,1, 2,3, 4,5, 6,7, 8,9, 10,11, 28,29, 30,31, 34,35, 32,33, 36,37, 18,19, 26,27 210 | }, 211 | // MPI_15 212 | std::vector{ 213 | 0,1, 2,3, 4,5, 6,7, 8,9, 10,11, 12,13, 14,15, 16,17, 18,19, 20,21, 22,23, 24,25, 26,27 214 | }, 215 | // MPI_15_4 216 | std::vector{ 217 | 0,1, 2,3, 4,5, 6,7, 8,9, 10,11, 12,13, 14,15, 16,17, 18,19, 20,21, 22,23, 24,25, 26,27 218 | }, 219 | // BODY_19 220 | std::vector{ 221 | 0,1, 14,15, 22,23, 16,17, 18,19, 24,25, 26,27, 6,7, 2,3, 4,5, 8,9, 10,11, 12,13, 30,31, 32,33, 36,37, 34,35, 38,39, 20,21, 28,29 222 | }, 223 | // BODY_19_X2 224 | std::vector{ 225 | 0,1, 14,15, 22,23, 16,17, 18,19, 24,25, 26,27, 6,7, 2,3, 4,5, 8,9, 10,11, 12,13, 30,31, 32,33, 36,37, 34,35, 38,39, 20,21, 28,29 226 | }, 227 | // BODY_59 228 | std::vector{ 229 | 0,1, 14,15, 22,23, 16,17, 18,19, 24,25, 26,27, 6,7, 2,3, 4,5, 8,9, 10,11, 12,13, 30,31, 32,33, 36,37, 34,35, 38,39, 20,21, 28,29, // Body 230 | 40,41, 42,43, 44,45, 46,47, 48,49, 14,51, 52,53, 54,55, 56,57, 58,59, 231 | 60,61, 62,63, 64,65, 66,67, 68,69, 70,71, 72,73, 74,75, 76,77, 78,79,// Left hand 232 | 80,81, 82,83, 84,85, 86,87, 88,89, 90,91, 92,93, 94,95, 96,97, 98,99, 233 | 100,101, 102,103, 104,105, 106,107, 108,109, 110,111, 112,113, 114,115, 116,117, 118,119 // Right hand 234 | }, 235 | // BODY_19N 236 | std::vector{ 237 | 0,1, 14,15, 22,23, 16,17, 18,19, 24,25, 26,27, 6,7, 2,3, 4,5, 8,9, 10,11, 12,13, 30,31, 32,33, 36,37, 34,35, 38,39, 20,21, 28,29 238 | }, 239 | // BODY_19b 240 | std::vector{ 241 | 0,1, 14,15, 22,23, 16,17, 18,19, 24,25, 26,27, 6,7, 2,3, 4,5, 8,9, 10,11, 12,13, 30,31, 32,33, 36,37, 34,35, 38,39, 20,21, 28,29, 60,61, 62,63 242 | }, 243 | // BODY_25_19 244 | std::vector{ 245 | 0,1, 14,15, 22,23, 16,17, 18,19, 24,25, 26,27, 6,7, 2,3, 4,5, 8,9, 10,11, 12,13, 30,31, 32,33, 36,37, 34,35, 38,39, 20,21, 28,29, 40,41,42,43,44,45, 46,47,48,49,50,51 246 | }, 247 | // BODY_65 248 | std::vector{ 249 | 0,1, 14,15, 22,23, 16,17, 18,19, 24,25, 26,27, 6,7, 2,3, 4,5, 8,9, 10,11, 12,13, 30,31, 32,33, 36,37, 34,35, 38,39, 20,21, 28,29, 40,41,42,43,44,45, 46,47,48,49,50,51, // Body 250 | 52,53, 54,55, 56,57, 58,59, 60,61, 62,63, 64,65, 66,67, 68,69, 70,71, 251 | 72,73, 74,75, 76,77, 78,79, 80,81, 82,83, 84,85, 86,87, 88,89, 90,91, // Left hand 252 | 92,93, 94,95, 96,97, 98,99, 100,101, 102,103, 104,105, 106,107, 108,109, 110,111, 253 | 112,113, 114,115, 116,117, 118,119, 120,121, 122,123, 124,125, 126,127, 128,129, 130,131 // Right hand 254 | }, 255 | // CAR_12 256 | std::vector{ 257 | 0,1, 2,3, 4,5, 6,7, 8,9, 10,11, 12,13, 14,15, 16,17, 18,19, 20,21 258 | }, 259 | }; 260 | // POSE_BODY_PART_MAPPING on HPP crashes on Windows at dynamic initialization if it's on hpp 261 | const std::array, (int)PoseModel::Size> POSE_BODY_PART_MAPPING{ 262 | POSE_BODY_25_BODY_PARTS,POSE_COCO_BODY_PARTS, POSE_MPI_BODY_PARTS, POSE_MPI_BODY_PARTS, 263 | POSE_BODY_19_BODY_PARTS,POSE_BODY_19_BODY_PARTS,POSE_BODY_59_BODY_PARTS,POSE_BODY_19_BODY_PARTS, 264 | POSE_BODY_19_BODY_PARTS,POSE_BODY_25_BODY_PARTS,POSE_BODY_65_BODY_PARTS,POSE_CAR_12_PARTS 265 | }; 266 | 267 | const std::array POSE_PROTOTXT{ 268 | "pose/body_25/pose_deploy.prototxt", 269 | "pose/coco/pose_deploy_linevec.prototxt", 270 | "pose/mpi/pose_deploy_linevec.prototxt", 271 | "pose/mpi/pose_deploy_linevec_faster_4_stages.prototxt", 272 | "pose/body_19/pose_deploy.prototxt", 273 | "pose/body_19_x2/pose_deploy.prototxt", 274 | "pose/body_59/pose_deploy.prototxt", 275 | "pose/body_19n/pose_deploy.prototxt", 276 | "pose/body_19b/pose_deploy.prototxt", 277 | "pose/body_19_25/pose_deploy_25.prototxt", 278 | "pose/body_65/pose_deploy.prototxt", 279 | "car/car_12/pose_deploy.prototxt", 280 | }; 281 | const std::array POSE_TRAINED_MODEL{ 282 | "pose/body_25/pose_iter_584000.caffemodel", 283 | "pose/coco/pose_iter_440000.caffemodel", 284 | "pose/mpi/pose_iter_160000.caffemodel", 285 | "pose/mpi/pose_iter_160000.caffemodel", 286 | "pose/body_19/pose_iter_XXXXXX.caffemodel", 287 | "pose/body_19_x2/pose_iter_XXXXXX.caffemodel", 288 | "pose/body_59/pose_iter_XXXXXX.caffemodel", 289 | "pose/body_19n/pose_iter_XXXXXX.caffemodel", 290 | "pose/body_19b/pose_iter_XXXXXX.caffemodel", 291 | "pose/body_19_25/pose_iter_XXXXXX.caffemodel", 292 | "pose/body_65/pose_iter_XXXXXX.caffemodel", 293 | "car/car_12/pose_iter_XXXXXX.caffemodel", 294 | }; 295 | 296 | // Constant Array Parameters 297 | // POSE_NUMBER_BODY_PARTS equivalent to size of std::map POSE_BODY_XX_BODY_PARTS - 1 (removing background) 298 | const std::array POSE_NUMBER_BODY_PARTS{ 299 | 25, 18, 15, 15, 19, 19, 59, 19, 19, 25, 65, 12 300 | }; 301 | const std::array, (int)PoseModel::Size> POSE_BODY_PART_PAIRS{ 302 | // BODY_25 303 | std::vector{ 304 | 1,8, 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0, 0,15, 15,17, 0,16, 16,18, 2,17, 5,18, 14,19,19,20,14,21, 11,22,22,23,11,24 305 | }, 306 | // COCO 307 | std::vector{ 308 | 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 1,8, 8,9, 9,10, 1,11, 11,12, 12,13, 1,0, 0,14, 14,16, 0,15, 15,17, 2,16, 5,17 309 | }, 310 | // MPI_15 311 | std::vector{POSE_MPI_PAIRS_RENDER_GPU}, 312 | // MPI_15_4 313 | std::vector{POSE_MPI_PAIRS_RENDER_GPU}, 314 | // BODY_19 315 | std::vector{ 316 | 1,8, 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0, 0,15, 15,17, 0,16, 16,18, 2,17, 5,18 317 | }, 318 | // BODY_19_X2 319 | std::vector{ 320 | 1,8, 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0, 0,15, 15,17, 0,16, 16,18, 2,17, 5,18 321 | }, 322 | // BODY_59 323 | std::vector{ 324 | 1,8, 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0, 0,15, 15,17, 0,16, 16,18, 2,17, 5,18,// Body 325 | 7,19, 19,20, 20,21, 21,22, 7,23, 23,24, 24,25, 25,26, 7,27, 27,28, 28,29, 29,30, 7,31, 31,32, 32,33, 33,34, 7,35, 35,36, 36,37, 37,38, // Left hand 326 | 4,39, 39,40, 40,41, 41,42, 4,43, 43,44, 44,45, 45,46, 4,47, 47,48, 48,49, 49,50, 4,51, 51,52, 52,53, 53,54, 4,55, 55,56, 56,57, 57,58 // Right hand 327 | }, 328 | // BODY_19N 329 | std::vector{ 330 | 1,8, 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0, 0,15, 15,17, 0,16, 16,18, 2,17, 5,18 331 | }, 332 | // BODY_19b 333 | std::vector{ 334 | 1,8, 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0, 0,15, 15,17, 0,16, 16,18, 2,17, 5,18, 2,9, 5,12 335 | }, 336 | // BODY_25_19 337 | std::vector{ 338 | 1,8, 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0, 0,15, 15,17, 0,16, 16,18, 2,17, 5,18, 14,19,19,20,14,21, 11,22,22,23,11,24 339 | }, 340 | // BODY_65 341 | std::vector{ 342 | 1,8, 1,2, 1,5, 2,3, 3,4, 5,6, 6,7, 8,9, 9,10, 10,11, 8,12, 12,13, 13,14, 1,0, 0,15, 15,17, 0,16, 16,18, 2,17, 5,18, 14,19,19,20,14,21, 11,22,22,23,11,24, 343 | 7,25, 25,26, 26,27, 27,28, 7,29, 29,30, 30,31, 31,32, 7,33, 33,34, 34,35, 35,36, 7,37, 37,38, 38,39, 39,40, 7,41, 41,42, 42,43, 43,44, // Left hand 344 | 4,45, 45,46, 46,47, 47,48, 4,49, 49,50, 50,51, 51,52, 4,53, 53,54, 54,55, 55,56, 4,57, 57,58, 58,59, 59,60, 4,61, 61,62, 62,63, 63,64 // Right hand 345 | }, 346 | // CAR_12 347 | std::vector{ 348 | 4,5, 4,6, 4,0, 0,2, 4,8, 8,10, 5,7, 5,1, 1,3, 5,9, 9,11 349 | }, 350 | }; 351 | const std::array POSE_MAX_PEAKS{ 352 | POSE_MAX_PEOPLE, // BODY_25 353 | POSE_MAX_PEOPLE, // COCO 354 | POSE_MAX_PEOPLE, // MPI_15 355 | POSE_MAX_PEOPLE, // MPI_15_4 356 | POSE_MAX_PEOPLE, // BODY_19 357 | POSE_MAX_PEOPLE, // BODY_19_X2 358 | POSE_MAX_PEOPLE, // BODY_59 359 | POSE_MAX_PEOPLE, // BODY_19N 360 | POSE_MAX_PEOPLE, // BODY_19b 361 | POSE_MAX_PEOPLE, // BODY_25_19 362 | POSE_MAX_PEOPLE, // BODY_65 363 | POSE_MAX_PEOPLE, // CAR_12 364 | }; 365 | const std::array POSE_CCN_DECREASE_FACTOR{ 366 | 8.f, // BODY_25 367 | 8.f, // COCO 368 | 8.f, // MPI_15 369 | 8.f, // MPI_15_4 370 | 8.f, // BODY_19 371 | 4.f, // BODY_19_X2 372 | 8.f, // BODY_59 373 | 8.f, // BODY_19N 374 | 8.f, // BODY_19b 375 | 8.f, // BODY_25_19 376 | 8.f, // BODY_65 377 | 8.f, // CAR_12 378 | }; 379 | 380 | // Default Model Parameters 381 | // They might be modified on running time 382 | const auto nmsT = (COCO_CHALLENGE ? 0.04f : 0.05f); 383 | const std::array POSE_DEFAULT_NMS_THRESHOLD{ 384 | nmsT, nmsT, 0.6f, 0.3f, nmsT, nmsT, nmsT, nmsT, nmsT, nmsT, nmsT, nmsT 385 | }; 386 | const auto minAT = (COCO_CHALLENGE ? 0.75f : 0.95f); // Matlab version: 0.85f 387 | const std::array POSE_DEFAULT_CONNECT_INTER_MIN_ABOVE_THRESHOLD{ 388 | minAT, minAT, minAT, minAT, minAT, minAT, minAT, minAT, minAT, minAT, minAT, minAT 389 | // 0.85f, 0.85f, 0.85f, 0.85f, 0.85f, 0.85f // Matlab version 390 | }; 391 | const auto conIT = (COCO_CHALLENGE ? 0.01f : 0.05f); 392 | const std::array POSE_DEFAULT_CONNECT_INTER_THRESHOLD{ 393 | conIT, conIT, 0.01f, 0.01f, conIT, conIT, conIT, conIT, conIT, conIT, conIT, conIT 394 | }; 395 | const auto minSC = (COCO_CHALLENGE ? 2 : 3); 396 | const std::array POSE_DEFAULT_CONNECT_MIN_SUBSET_CNT{ 397 | minSC, minSC, minSC, minSC, minSC, minSC, minSC, minSC, minSC, minSC, minSC, minSC 398 | }; 399 | const auto minSS = (COCO_CHALLENGE ? 0.05f : 0.4f); 400 | const std::array POSE_DEFAULT_CONNECT_MIN_SUBSET_SCORE{ 401 | minSS, minSS, minSS, minSS, minSS, minSS, minSS, minSS, minSS, minSS, minSS, minSS 402 | // 0.2f, 0.4f, 0.4f, 0.4f, 0.4f, 0.4f // Matlab version 403 | }; 404 | 405 | const std::map& getPoseBodyPartMapping(const PoseModel poseModel) 406 | { 407 | try 408 | { 409 | return POSE_BODY_PART_MAPPING.at((int)poseModel); 410 | } 411 | catch (const std::exception& e) 412 | { 413 | CV_Error(0, e.what()); 414 | return POSE_BODY_PART_MAPPING[(int)poseModel]; 415 | } 416 | } 417 | 418 | const std::string& getPoseProtoTxt(const PoseModel poseModel) 419 | { 420 | try 421 | { 422 | return POSE_PROTOTXT.at((int)poseModel); 423 | } 424 | catch (const std::exception& e) 425 | { 426 | CV_Error(0, e.what()); 427 | return POSE_PROTOTXT[(int)poseModel]; 428 | } 429 | } 430 | 431 | const std::string& getPoseTrainedModel(const PoseModel poseModel) 432 | { 433 | try 434 | { 435 | return POSE_TRAINED_MODEL.at((int)poseModel); 436 | } 437 | catch (const std::exception& e) 438 | { 439 | CV_Error(0, e.what()); 440 | return POSE_TRAINED_MODEL[(int)poseModel]; 441 | } 442 | } 443 | 444 | unsigned int getPoseNumberBodyParts(const PoseModel poseModel) 445 | { 446 | try 447 | { 448 | return POSE_NUMBER_BODY_PARTS.at((int)poseModel); 449 | } 450 | catch (const std::exception& e) 451 | { 452 | CV_Error(0, e.what()); 453 | return 0u; 454 | } 455 | } 456 | 457 | const std::vector& getPosePartPairs(const PoseModel poseModel) 458 | { 459 | try 460 | { 461 | return POSE_BODY_PART_PAIRS.at((int)poseModel); 462 | } 463 | catch (const std::exception& e) 464 | { 465 | CV_Error(0, e.what()); 466 | return POSE_BODY_PART_PAIRS[(int)poseModel]; 467 | } 468 | } 469 | 470 | const std::vector& getPoseMapIndex(const PoseModel poseModel) 471 | { 472 | try 473 | { 474 | return POSE_MAP_INDEX.at((int)poseModel); 475 | } 476 | catch (const std::exception& e) 477 | { 478 | CV_Error(0, e.what()); 479 | return POSE_MAP_INDEX[(int)poseModel]; 480 | } 481 | } 482 | 483 | unsigned int getPoseMaxPeaks(const PoseModel poseModel) 484 | { 485 | try 486 | { 487 | return POSE_MAX_PEAKS.at((int)poseModel); 488 | } 489 | catch (const std::exception& e) 490 | { 491 | CV_Error(0, e.what()); 492 | return 0u; 493 | } 494 | } 495 | 496 | float getPoseNetDecreaseFactor(const PoseModel poseModel) 497 | { 498 | try 499 | { 500 | return POSE_CCN_DECREASE_FACTOR.at((int)poseModel); 501 | } 502 | catch (const std::exception& e) 503 | { 504 | CV_Error(0, e.what()); 505 | return 0.f; 506 | } 507 | } 508 | 509 | unsigned int poseBodyPartMapStringToKey(const PoseModel poseModel, const std::vector& strings) 510 | { 511 | try 512 | { 513 | const auto& poseBodyPartMapping = POSE_BODY_PART_MAPPING[(int)poseModel]; 514 | for (const auto& string : strings) 515 | for (const auto& pair : poseBodyPartMapping) 516 | if (pair.second == string) 517 | return pair.first; 518 | CV_Error(0, "String(s) could not be found."); 519 | return 0; 520 | } 521 | catch (const std::exception& e) 522 | { 523 | CV_Error(0, e.what()); 524 | return 0; 525 | } 526 | } 527 | 528 | unsigned int poseBodyPartMapStringToKey(const PoseModel poseModel, const std::string& string) 529 | { 530 | try 531 | { 532 | return poseBodyPartMapStringToKey(poseModel, std::vector{string}); 533 | } 534 | catch (const std::exception& e) 535 | { 536 | CV_Error(0, e.what()); 537 | return 0; 538 | } 539 | } 540 | 541 | // Default Model Parameters 542 | float getPoseDefaultNmsThreshold(const PoseModel poseModel) 543 | { 544 | try 545 | { 546 | return POSE_DEFAULT_NMS_THRESHOLD.at((int)poseModel); 547 | } 548 | catch (const std::exception& e) 549 | { 550 | CV_Error(0, e.what()); 551 | return 0.f; 552 | } 553 | } 554 | 555 | float getPoseDefaultConnectInterMinAboveThreshold(const PoseModel poseModel) 556 | { 557 | try 558 | { 559 | return POSE_DEFAULT_CONNECT_INTER_MIN_ABOVE_THRESHOLD.at((int)poseModel); 560 | } 561 | catch (const std::exception& e) 562 | { 563 | CV_Error(0, e.what()); 564 | return 0.f; 565 | } 566 | } 567 | 568 | float getPoseDefaultConnectInterThreshold(const PoseModel poseModel) 569 | { 570 | try 571 | { 572 | return POSE_DEFAULT_CONNECT_INTER_THRESHOLD.at((int)poseModel); 573 | } 574 | catch (const std::exception& e) 575 | { 576 | CV_Error(0, e.what()); 577 | return 0.f; 578 | } 579 | } 580 | 581 | unsigned int getPoseDefaultMinSubsetCnt(const PoseModel poseModel) 582 | { 583 | try 584 | { 585 | return POSE_DEFAULT_CONNECT_MIN_SUBSET_CNT.at((int)poseModel); 586 | } 587 | catch (const std::exception& e) 588 | { 589 | CV_Error(0, e.what()); 590 | return 0u; 591 | } 592 | } 593 | 594 | float getPoseDefaultConnectMinSubsetScore(const PoseModel poseModel) 595 | { 596 | try 597 | { 598 | return POSE_DEFAULT_CONNECT_MIN_SUBSET_SCORE.at((int)poseModel); 599 | } 600 | catch (const std::exception& e) 601 | { 602 | CV_Error(0, e.what()); 603 | return 0.f; 604 | } 605 | } 606 | } 607 | --------------------------------------------------------------------------------