【OpenPose 學習筆記-03】Example 1. Body from image

本文主要講解OpenPose開源框架提供的example,本系列先講解 /openpose/examples/tutorial_api_cpp/ 目錄下的17個開源代碼。如題,首先記錄個人對第一個Example的理解。

測試圖片如下:

代碼功能:

讀取一張圖片,進行處理,進行顯示以及打印pose關鍵點。直接上運行結果。根據測試圖片,以及輸出結果發現,代碼實現了對輸入圖片中的關鍵點進行檢測,並進行了顯示以及打印出來了關鍵點座標。我們會發現每個人會檢測出25個關鍵點,分別對應了身體的不同位置。關鍵點的輸出信息如下:437.255981 123.085121 0.906523,第一個值橫座標x,第二個代表縱座標y,第三個值爲置信度(取值範圍0到1)。備註:座標原點是圖片左上角點,橫座標軸爲水平向右,縱座標軸爲豎直向下。

那麼問題來了,這25個點座標分別代表人身上的那些關鍵點?

0->鼻子                                                                                       15->左眼

1->脖子                                                                                       16->右眼

2->左肩                                                                                       17->左耳

3->左肘                                                                                       18->右耳

4->左手                                                                                       19-21  在左腳上的三個點

5->右肩                                                                                       23-24  在右腳上的三個點

6->右肘

7->右手

8->褲帶標誌的那個點,肚臍往下一點

9->左大腿根部

10->左膝蓋

11->左腳

12-> 右大腿根部

13->右膝蓋

14->右腳

 

如果其中一個關鍵點沒有檢測出來,輸出的座標和置信度會是什麼呢?

輸出的是 (0.0000, 0.0000, 0.0000)。這樣會發現有時候檢測會出現與原點連接的直線。

 

如果你覺得輸出的圖不是想要的,可以在原圖的基礎上,根據檢測出來的關鍵點座標重新繪製改圖。

 

Starting OpenPose demo...
Configuring OpenPose...
Starting thread(s)...
Auto-detecting all available GPUs... Detected 1 GPU(s), using 1 of them starting at GPU 0.
Body keypoints: Array<T>::toString():
437.255981 123.085121 0.906523 
422.357300 175.192841 0.882059 
364.677948 171.437820 0.814926 
290.418488 227.148422 0.849849 
344.289673 286.660187 0.781581 
479.885468 182.572571 0.782618 
500.376831 253.212280 0.763941 
466.998169 303.359467 0.840747 
409.248596 348.029633 0.734004 
370.322815 349.846497 0.639143 
381.491455 496.625610 0.779169 
377.776337 619.336243 0.790947 
442.822021 348.051361 0.674805 
424.239502 476.230316 0.814295 
426.066895 611.862671 0.755358 
424.295624 110.124794 0.906900 
450.193604 111.934570 0.913698 
407.444244 111.940063 0.931875 
457.615601 113.889832 0.496016 
422.384033 630.541687 0.692417 
439.060333 630.438660 0.658018 
424.144196 619.291992 0.574923 
383.316071 632.364380 0.591681 
372.165527 632.325623 0.557938 
379.592560 630.421936 0.615449 

602.560242 186.393326 0.938347 
591.442383 245.786560 0.888576 
541.204773 245.778137 0.835189 
500.369904 327.570709 0.847654 
515.296631 394.398560 0.896734 
647.120605 245.777084 0.859364 
680.611206 318.214264 0.829531 
706.597290 383.324158 0.856119 
593.272339 388.860046 0.680254 
557.934448 390.729187 0.702126 
556.206360 526.369324 0.818692 
558.051697 632.265320 0.761809 
630.422180 385.165283 0.723132 
617.491333 496.603210 0.860527 
615.490601 615.614441 0.796588 
591.443176 175.210358 0.846590 
615.506775 180.785339 0.893679 
572.840881 184.411392 0.921707 
621.193604 186.370575 0.711615 
598.859558 634.155029 0.585496 
613.754395 634.227600 0.615592 
615.600830 623.015808 0.599560 
546.865784 643.416870 0.279773 
543.092712 641.576782 0.310959 
567.298340 637.879700 0.494990 


OpenPose demo successfully finished. Total time: 1.156978 seconds

代碼如下:

// ----------------------------- OpenPose C++ API Tutorial - Example 1 - Body from image -----------------------------
// It reads an image, process it, and displays it with the pose keypoints.

// Command-line user intraface
#define OPENPOSE_FLAGS_DISABLE_POSE
#include <openpose/flags.hpp>
// OpenPose dependencies
#include <openpose/headers.hpp>

// Custom OpenPose flags
// Producer
DEFINE_string(image_path, "/home/wdong/0315/1212/test.jpg",
              "Process an image. Read all standard formats (jpg, png, bmp, etc.).");
// Display
DEFINE_bool(no_display,                 false,
            "Enable to disable the visual display.");

// This worker will just read and return all the jpg files in a directory
void display(const std::shared_ptr<std::vector<std::shared_ptr<op::Datum>>>& datumsPtr)
{
    try
    {
        // User's displaying/saving/other processing here
        // datum.cvOutputData: rendered frame with pose or heatmaps
        // datum.poseKeypoints: Array<float> with the estimated pose
        if (datumsPtr != nullptr && !datumsPtr->empty())
        {
            // Display image
            cv::imshow("01_body_from_image_default.cpp", datumsPtr->at(0)->cvOutputData);
            cv::waitKey(0);
        }
        else
            op::log("Nullptr or empty datumsPtr found.", op::Priority::High);
    }
    catch (const std::exception& e)
    {
        op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
    }
}

void printKeypoints(const std::shared_ptr<std::vector<std::shared_ptr<op::Datum>>>& datumsPtr)
{
    try
    {
        // Example: How to use the pose keypoints
        if (datumsPtr != nullptr && !datumsPtr->empty())
        {
            // Alternative 1
            op::log("Body keypoints: " + datumsPtr->at(0)->poseKeypoints.toString(), op::Priority::High);

            // // Alternative 2
            // op::log(datumsPtr->at(0).poseKeypoints, op::Priority::High);

            // // Alternative 3
            // std::cout << datumsPtr->at(0).poseKeypoints << std::endl;

            // // Alternative 4 - Accesing each element of the keypoints
            // op::log("\nKeypoints:", op::Priority::High);
            // const auto& poseKeypoints = datumsPtr->at(0).poseKeypoints;
            // op::log("Person pose keypoints:", op::Priority::High);
            // for (auto person = 0 ; person < poseKeypoints.getSize(0) ; person++)
            // {
            //     op::log("Person " + std::to_string(person) + " (x, y, score):", op::Priority::High);
            //     for (auto bodyPart = 0 ; bodyPart < poseKeypoints.getSize(1) ; bodyPart++)
            //     {
            //         std::string valueToPrint;
            //         for (auto xyscore = 0 ; xyscore < poseKeypoints.getSize(2) ; xyscore++)
            //             valueToPrint += std::to_string(   poseKeypoints[{person, bodyPart, xyscore}]   ) + " ";
            //         op::log(valueToPrint, op::Priority::High);
            //     }
            // }
            // op::log(" ", op::Priority::High);
        }
        else
            op::log("Nullptr or empty datumsPtr found.", op::Priority::High);
    }
    catch (const std::exception& e)
    {
        op::error(e.what(), __LINE__, __FUNCTION__, __FILE__);
    }
}

int tutorialApiCpp()
{
    try
    {
        op::log("Starting OpenPose demo...", op::Priority::High);
        const auto opTimer = op::getTimerInit();

        // Configuring OpenPose
        op::log("Configuring OpenPose...", op::Priority::High);
        op::Wrapper opWrapper{op::ThreadManagerMode::Asynchronous};
        // Set to single-thread (for sequential processing and/or debugging and/or reducing latency)
        if (FLAGS_disable_multi_thread)
            opWrapper.disableMultiThreading();

        // Starting OpenPose
        op::log("Starting thread(s)...", op::Priority::High);
        opWrapper.start();

        // Process and display image
        const auto imageToProcess = cv::imread(FLAGS_image_path);
        auto datumProcessed = opWrapper.emplaceAndPop(imageToProcess);
        if (datumProcessed != nullptr)
        {
            printKeypoints(datumProcessed);
            if (!FLAGS_no_display)
                display(datumProcessed);
        }
        else
            op::log("Image could not be processed.", op::Priority::High);

        // Measuring total time
        op::printTime(opTimer, "OpenPose demo successfully finished. Total time: ", " seconds.", op::Priority::High);

        // Return
        return 0;
    }
    catch (const std::exception& e)
    {
        return -1;
    }
}

int main(int argc, char *argv[])
{
    // Parsing command line flags
    gflags::ParseCommandLineFlags(&argc, &argv, true);

    // Running tutorialApiCpp
    return tutorialApiCpp();
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章