From 4f597f6c060812f8cfd749c5351874d706a56cd9 Mon Sep 17 00:00:00 2001 From: berak Date: Fri, 16 Mar 2018 15:06:09 +0100 Subject: [PATCH] dnn: add an openpose.cpp sample --- samples/dnn/openpose.cpp | 168 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 samples/dnn/openpose.cpp diff --git a/samples/dnn/openpose.cpp b/samples/dnn/openpose.cpp new file mode 100644 index 0000000000..bc95c60023 --- /dev/null +++ b/samples/dnn/openpose.cpp @@ -0,0 +1,168 @@ +// +// this sample demonstrates the use of pretrained openpose networks with opencv's dnn module. +// +// it can be used for body pose detection, using either the COCO model(18 parts): +// http://posefs1.perception.cs.cmu.edu/OpenPose/models/pose/coco/pose_iter_440000.caffemodel +// https://raw.githubusercontent.com/opencv/opencv_extra/master/testdata/dnn/openpose_pose_coco.prototxt +// +// or the MPI model(16 parts): +// http://posefs1.perception.cs.cmu.edu/OpenPose/models/pose/mpi/pose_iter_160000.caffemodel +// https://raw.githubusercontent.com/opencv/opencv_extra/master/testdata/dnn/openpose_pose_mpi_faster_4_stages.prototxt +// +// (to simplify this sample, the body models are restricted to a single person.) +// +// +// you can also try the hand pose model: +// http://posefs1.perception.cs.cmu.edu/OpenPose/models/hand/pose_iter_102000.caffemodel +// https://raw.githubusercontent.com/CMU-Perceptual-Computing-Lab/openpose/master/models/hand/pose_deploy.prototxt +// + +#include +#include +#include +using namespace cv; +using namespace cv::dnn; + +#include +using namespace std; + + +// connection table, in the format [model_id][pair_id][from/to] +// please look at the nice explanation at the bottom of: +// https://github.com/CMU-Perceptual-Computing-Lab/openpose/blob/master/doc/output.md +// +const int POSE_PAIRS[3][20][2] = { +{ // COCO body + {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} +}, +{ // MPI body + {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} +}, +{ // hand + {0,1}, {1,2}, {2,3}, {3,4}, // thumb + {0,5}, {5,6}, {6,7}, {7,8}, // pinkie + {0,9}, {9,10}, {10,11}, {11,12}, // middle + {0,13}, {13,14}, {14,15}, {15,16}, // ring + {0,17}, {17,18}, {18,19}, {19,20} // small +}}; + +int main(int argc, char **argv) +{ + CommandLineParser parser(argc, argv, + "{ h help | false | print this help message }" + "{ p proto | | (required) model configuration, e.g. hand/pose.prototxt }" + "{ m model | | (required) model weights, e.g. hand/pose_iter_102000.caffemodel }" + "{ i image | | (required) path to image file (containing a single person, or hand) }" + "{ t threshold | 0.1 | threshold or confidence value for the heatmap }" + ); + + String modelTxt = parser.get("proto"); + String modelBin = parser.get("model"); + String imageFile = parser.get("image"); + float thresh = parser.get("threshold"); + if (parser.get("help") || modelTxt.empty() || modelBin.empty() || imageFile.empty()) + { + cout << "A sample app to demonstrate human or hand pose detection with a pretrained OpenPose dnn." << endl; + parser.printMessage(); + return 0; + } + + // fixed input size for the pretrained network + int W_in = 368; + int H_in = 368; + + // read the network model + Net net = readNetFromCaffe(modelTxt, modelBin); + + // and the image + Mat img = imread(imageFile); + if (img.empty()) + { + std::cerr << "Can't read image from the file: " << imageFile << std::endl; + exit(-1); + } + + // send it through the network + Mat inputBlob = blobFromImage(img, 1.0 / 255, Size(W_in, H_in), Scalar(0, 0, 0), false, false); + net.setInput(inputBlob); + Mat result = net.forward(); + // the result is an array of "heatmaps", the probability of a body part being in location x,y + + int midx, npairs; + int nparts = result.size[1]; + int H = result.size[2]; + int W = result.size[3]; + + // find out, which model we have + if (nparts == 19) + { // COCO body + midx = 0; + npairs = 17; + nparts = 18; // skip background + } + else if (nparts == 16) + { // MPI body + midx = 1; + npairs = 14; + } + else if (nparts == 22) + { // hand + midx = 2; + npairs = 20; + } + else + { + cerr << "there should be 19 parts for the COCO model, 16 for MPI, or 22 for the hand one, but this model has " << nparts << " parts." << endl; + return (0); + } + + // find the position of the body parts + vector points(22); + for (int n=0; n thresh) + p = pm; + points[n] = p; + } + + // connect body parts and draw it ! + float SX = float(img.cols) / W; + float SY = float(img.rows) / H; + for (int n=0; n