samples/dnn/openpose.cpp#

  1//
  2//  this sample demonstrates the use of pretrained openpose networks with opencv's dnn module.
  3//
  4//  it can be used for body pose detection, using either the COCO model(18 parts):
  5//  http://posefs1.perception.cs.cmu.edu/OpenPose/models/pose/coco/pose_iter_440000.caffemodel
  6//  https://raw.githubusercontent.com/opencv/opencv_extra/5.x/testdata/dnn/openpose_pose_coco.prototxt
  7//
  8//  or the MPI model(16 parts):
  9//  http://posefs1.perception.cs.cmu.edu/OpenPose/models/pose/mpi/pose_iter_160000.caffemodel
 10//  https://raw.githubusercontent.com/opencv/opencv_extra/5.x/testdata/dnn/openpose_pose_mpi_faster_4_stages.prototxt
 11//
 12//  (to simplify this sample, the body models are restricted to a single person.)
 13//
 14//
 15//  you can also try the hand pose model:
 16//  http://posefs1.perception.cs.cmu.edu/OpenPose/models/hand/pose_iter_102000.caffemodel
 17//  https://raw.githubusercontent.com/CMU-Perceptual-Computing-Lab/openpose/master/models/hand/pose_deploy.prototxt
 18//
 19
 20#include <opencv2/dnn.hpp>
 21#include <opencv2/imgproc.hpp>
 22#include <opencv2/highgui.hpp>
 23using namespace cv;
 24using namespace cv::dnn;
 25
 26#include <iostream>
 27using namespace std;
 28
 29
 30// connection table, in the format [model_id][pair_id][from/to]
 31// please look at the nice explanation at the bottom of:
 32// https://github.com/CMU-Perceptual-Computing-Lab/openpose/blob/master/doc/output.md
 33//
 34const int POSE_PAIRS[3][20][2] = {
 35{   // COCO body
 36    {1,2}, {1,5}, {2,3},
 37    {3,4}, {5,6}, {6,7},
 38    {1,8}, {8,9}, {9,10},
 39    {1,11}, {11,12}, {12,13},
 40    {1,0}, {0,14},
 41    {14,16}, {0,15}, {15,17}
 42},
 43{   // MPI body
 44    {0,1}, {1,2}, {2,3},
 45    {3,4}, {1,5}, {5,6},
 46    {6,7}, {1,14}, {14,8}, {8,9},
 47    {9,10}, {14,11}, {11,12}, {12,13}
 48},
 49{   // hand
 50    {0,1}, {1,2}, {2,3}, {3,4},         // thumb
 51    {0,5}, {5,6}, {6,7}, {7,8},         // pinkie
 52    {0,9}, {9,10}, {10,11}, {11,12},    // middle
 53    {0,13}, {13,14}, {14,15}, {15,16},  // ring
 54    {0,17}, {17,18}, {18,19}, {19,20}   // small
 55}};
 56
 57int main(int argc, char **argv)
 58{
 59    CommandLineParser parser(argc, argv,
 60        "{ h help           | false     | print this help message }"
 61        "{ p proto          |           | (required) model configuration, e.g. hand/pose.prototxt }"
 62        "{ m model          |           | (required) model weights, e.g. hand/pose_iter_102000.caffemodel }"
 63        "{ i image          |           | (required) path to image file (containing a single person, or hand) }"
 64        "{ d dataset        |           | specify what kind of model was trained. It could be (COCO, MPI, HAND) depends on dataset. }"
 65        "{ width            |  368      | Preprocess input image by resizing to a specific width. }"
 66        "{ height           |  368      | Preprocess input image by resizing to a specific height. }"
 67        "{ t threshold      |  0.1      | threshold or confidence value for the heatmap }"
 68        "{ s scale          |  0.003922 | scale for blob }"
 69    );
 70
 71    String modelTxt = samples::findFile(parser.get<string>("proto"));
 72    String modelBin = samples::findFile(parser.get<string>("model"));
 73    String imageFile = samples::findFile(parser.get<String>("image"));
 74    String dataset = parser.get<String>("dataset");
 75    int W_in = parser.get<int>("width");
 76    int H_in = parser.get<int>("height");
 77    float thresh = parser.get<float>("threshold");
 78    float scale  = parser.get<float>("scale");
 79
 80    if (parser.get<bool>("help") || modelTxt.empty() || modelBin.empty() || imageFile.empty())
 81    {
 82        cout << "A sample app to demonstrate human or hand pose detection with a pretrained OpenPose dnn." << endl;
 83        parser.printMessage();
 84        return 0;
 85    }
 86
 87    int midx, npairs, nparts;
 88         if (!dataset.compare("COCO")) {  midx = 0; npairs = 17; nparts = 18; }
 89    else if (!dataset.compare("MPI"))  {  midx = 1; npairs = 14; nparts = 16; }
 90    else if (!dataset.compare("HAND")) {  midx = 2; npairs = 20; nparts = 22; }
 91    else
 92    {
 93        std::cerr << "Can't interpret dataset parameter: " << dataset << std::endl;
 94        exit(-1);
 95    }
 96
 97    // read the network model
 98    Net net = readNet(modelBin, modelTxt);
 99    // and the image
100    Mat img = imread(imageFile);
101    if (img.empty())
102    {
103        std::cerr << "Can't read image from the file: " << imageFile << std::endl;
104        exit(-1);
105    }
106
107    // send it through the network
108    Mat inputBlob = blobFromImage(img, scale, Size(W_in, H_in), Scalar(0, 0, 0), false, false);
109    net.setInput(inputBlob);
110    Mat result = net.forward();
111    // the result is an array of "heatmaps", the probability of a body part being in location x,y
112
113    int H = result.size[2];
114    int W = result.size[3];
115
116    // find the position of the body parts
117    vector<Point> points(22);
118    for (int n=0; n<nparts; n++)
119    {
120        // Slice heatmap of corresponding body's part.
121        Mat heatMap(H, W, CV_32F, result.ptr(0,n));
122        // 1 maximum per heatmap
123        Point p(-1,-1),pm;
124        double conf;
125        minMaxLoc(heatMap, 0, &conf, 0, &pm);
126        if (conf > thresh)
127            p = pm;
128        points[n] = p;
129    }
130
131    // connect body parts and draw it !
132    float SX = float(img.cols) / W;
133    float SY = float(img.rows) / H;
134    for (int n=0; n<npairs; n++)
135    {
136        // lookup 2 connected body/hand parts
137        Point2f a = points[POSE_PAIRS[midx][n][0]];
138        Point2f b = points[POSE_PAIRS[midx][n][1]];
139
140        // we did not find enough confidence before
141        if (a.x<=0 || a.y<=0 || b.x<=0 || b.y<=0)
142            continue;
143
144        // scale to image size
145        a.x*=SX; a.y*=SY;
146        b.x*=SX; b.y*=SY;
147
148        line(img, a, b, Scalar(0,200,0), 2);
149        circle(img, a, 3, Scalar(0,0,200), -1);
150        circle(img, b, 3, Scalar(0,0,200), -1);
151    }
152
153    imshow("OpenPose", img);
154    waitKey();
155
156    return 0;
157}