【问题标题】:OpenCV - Determine position of wristOpenCV - 确定手腕的位置
【发布时间】:2020-09-20 22:12:09
【问题描述】:

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

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

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

但是,对于使用 OpenCV 来说还很陌生,我不清楚确定/隔离手腕位置的最佳方法是什么。我对此有各种想法:

  • 手臂部分相当直。也许在轮廓多边形上进行简单的线检测可能会完成获得腋下直线的工作。
  • 不知何故将轮廓多边形分割成多个部分。基本上,可以公平地假设手腕的位置在两臂之间的距离最小,轮廓在腋下。有没有办法沿着多边形找到那个点,然后“切割”或“分割”多边形以获得两个?从那里我有一个多边形代表一个应该很容易使用的矩形。
  • 使用一种方法,沿使用fitLine() 拟合的多边形的主轴进行迭代,测量多边形的两个相对点之间的距离,找到最短距离。

很遗憾,我缺乏在这里做出正确选择的经验 - 甚至无法想出更好的主意。

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

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

【问题讨论】:

  • 您正试图通过形态学运算找到手腕。仅当您使用多边形长度的比率时才有可能,但这只是假设,因为每只手都不会处于相同的方向。我认为你应该使用像openpose 这样的高级算法
  • 我已经在使用不同的框架/库/技术来进行实际的手部跟踪。我能够提取各种手指关节的地标。我想这样做的原因是因为我没有得到实际的手腕位置,而只有手指关节的位置。从这些信息中准确地确定手腕位置是很困难的。因此,我想使用普通的 OpenCV 方法来检测腋下,然后将信息融合在一起以获得更准确的手腕位置。
  • 直到手的手臂粗细几乎相同。手臂的终点是手腕。你可以使用这个算法逻辑来获取手腕
  • 好吧,我可以在评论中尝试我的方法,但我需要一些未处理的参考图像。如果你可以分享你的问题,我可以和他们一起尝试
  • @YunusTemurlenk 您有机会尝试一下您的想法吗?在任何情况下:您能否添加一个概述您想法的答案,以便我更好地理解您的方法并尝试遵循这条路?

标签: opencv


【解决方案1】:

方法:我利用了手臂侧的优势。直到碰到手为止,手臂的粗细几乎一样。

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

我的步骤:

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

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

以下是结果和代码:

输入图像:

分割后:

算法后的输出:

代码:

#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;
}

【讨论】:

  • 谢谢 - 你的例子帮助我按照我想要的方式工作。
  • 很高兴听到这个消息
猜你喜欢
  • 2012-07-31
  • 1970-01-01
  • 2021-11-06
  • 2022-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多