首页 > 解决方案 > OpenCV - 确定手腕的位置

问题描述

我需要确定手腕在框架中的位置,其中包含人体的部分手臂和匹配的手。到目前为止,我已经隔离了手和手臂,并且能够在其周围绘制多边形和船体曲线:

在此处输入图像描述

我通过简单的二进制阈值和自动轮廓拟合来实现这个结果。

基于此,我想提取手腕的位置。这需要适用于手/手腕的所有方向。

然而,对于使用 OpenCV 来说相当新,我不清楚确定/隔离手腕位置的最佳方法是什么。我对此有各种想法:

不幸的是,我缺乏在这里做出正确选择的经验——甚至没有想出更好的主意。

我将不胜感激任何实现这一目标的想法和指示。在使用 Haar 级联进行手部检测和跟踪以及基本身体部位匹配时,我可以找到很多有价值的研究材料。不幸的是,我找不到将这些技术应用于我的用例的方法。

这里有一些可以使用的原材料(图片和视频):(Google Drive Link!):https ://drive.google.com/drive/folders/1hU4hGw5dYtVrcXTq8TYWCWfcLWjT-ZJU?usp=sharing

标签: opencv

解决方案


做法:我利用了手臂侧的优势。直到碰到手,手臂的厚度几乎相同。

假设:我假设手臂将垂直进入屏幕进行编码。否则我的代码可能不起作用。我尝试了您共享的所有图像,并且它对所有人都正常工作。

我的步骤:

  • 制作一个简单的分割方法,只获取图像的所需部分
  • 从手臂一侧开始计算每列的非黑色像素。
  • 直到击中与先前列计数不同的列,您仍处于手臂一侧。当你击球时,你到达了手腕。

注意:我通过实验确定了阈值。

以下是结果和代码:

输入图像:

在此处输入图像描述

分割后:

在此处输入图像描述

算法后的输出:

在此处输入图像描述

代码:

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <cstdlib>

using namespace cv;
using namespace std;

int main() {

    Mat src, gray, blur_image, threshold_output;

    // take input image
    src = imread("/ur/image/directory/image_01.jpg", 1);

    // convert to grayscale
    cvtColor(src, gray, COLOR_BGR2GRAY);

    // add blurring to the input image
    medianBlur(gray,gray,9);

    // Apply a segmentation to arm
    for(int i=0; i<gray.rows; i++)
        for(int j=0;j<gray.cols; j++)
            if(gray.at<uchar>(Point(j,i))<110)
                gray.at<uchar>(Point(j,i)) = 0;

    //Creat a bgr mat to show the results clearly
    Mat copy_gray = gray;
    cvtColor(copy_gray,copy_gray,CV_GRAY2BGR);

    double sum = 0;
    int loop_cnt = 0,enter = 1;
    Point first,second;

    for(int j=gray.cols-1; j>=0; j--)
    {
        loop_cnt++;
        int counter = 0,ff=1,enter2 = 1;
        for(int i=0;i<gray.rows; i++)
        {
            if(gray.at<uchar>(Point(j,i))!=0 && enter)
            {
                if(ff)
                    first = Point(j,i);
                counter++;
                ff = 0;
            }
            if(!ff && gray.at<uchar>(Point(j,i))==0 && enter2)
            {
                second = Point(j,i);
                enter2 = 0;
            }
        }

        sum += (double)counter;
        double average = sum/(double)(loop_cnt);

        if(abs(average-counter)>20.0 && enter)
        {
            line(copy_gray,Point(j,0),Point(j,500),Scalar(0,255,0),5);
            enter = 0;
        }
    }

    int distance = norm(second-first)/2;
    circle(copy_gray,Point(first.x,first.y+distance),20,Scalar(0,0,255),5);

    imshow("Result",copy_gray);

    waitKey(0);
    return 0;
}

推荐阅读