3D手势识别(一)顺/逆时针画圈判断

2024-02-20 08:30

本文主要是介绍3D手势识别(一)顺/逆时针画圈判断,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

场景:前装摄像头

检测动作:单手指画圈,需要判断画圈方向和圈数。

     

步骤: (1)取得3D图像序列最前点;

            (2)将最前点投影在2D平面上;

            (3)中值滤波和平滑处理;

            (4)得到2D点集进行线性插值;

            (5)以重心为中心判断是否闭环;

            (6)2D点集进行椭圆拟合,判断是否椭圆、椭圆半径和椭圆度范围;

    (7)  2D点集进行圆拟合,计算半径均值和标准差;

            (8)判断2D点集方向:顺/逆时针。

其中手的识别使用深度学习进行,根据TensorFlow训练完的模型判断出图像中有手且为单手指,
去掉背景、挖出只含有手的图像;中值滤波用的OpenCV medianBlur函数,其他主要函数算法如下:


Table of Contents

1、2D点集线性插值算法

2、计算重心

3、闭环判断

4、椭圆拟合

5、圆拟合

6、顺/逆时针方向判断


1、2D点集线性插值算法

//************************************
// Description: 插值,根据两点间距离线性插值,两点间距离越大插值越多,距离小于min_dis则不插值返回原值
// Method:    InterpCurve
// FullName:  InterpCurve
// Access:    private
// Parameter: 插值前二维点集 std::vector<cv::Point2f> &data
// Parameter: 插值后二维点集 std::vector<cv::Point2f> &result
// Parameter: 最小插值距离 float min_dis
// Returns:
// Author:    
// Date:      2018/08/28
// History:
//************************************
void InterpCurve(std::vector<cv::Point2f> &data, std::vector<cv::Point2f> &result, float min_dis) {result.clear();result.reserve(data.size());result.push_back(data.at(0));for (size_t i = 1; i < data.size(); i++) {float dis = Distance(data.at(i - 1), data.at(i));float num = dis / min_dis + 1;float step = 1.0f / num;float s = 0;while (s <= 1.0) {result.emplace_back(cv::Point2f((1 - s) * data.at(i - 1).x + s * data.at(i).x,(1.0f - s) * data.at(i - 1).y + s * data.at(i).y));s += step;}}//  vecp::print(result, "result");
}

2、计算重心

3D点计算方法类似。

//************************************
// Description: 将输入的point2d点集求和平均求重心
// Method:    CalcCentre
// FullName:  CalcCentre
// Access:    private
// Parameter: 二维点集 const std::vector<cv::Point2f> &point2ds
// Returns:   重心坐标 cv::Point2f
// Author:    
// Date:      2018/08/28
// History:
//************************************
cv::Point2f CalcCentre(const std::vector<cv::Point2f> &point2ds) {float x = 0, y = 0;for (auto &pt: point2ds) {x += pt.x;y += pt.y;}return cv::Point2f(x / point2ds.size(), y / point2ds.size());
}

3、闭环判断

//************************************
// Description: 将输入的point2d点集判断是否闭环
// Method:    FindOneCircleFromUnformInCircle
// FullName:  FindOneCircleFromUnformInCircle
// Access:    private
// Parameter: 二维点集 const std::vector<cv::Point2f> &point2ds
// Parameter: 判断闭环坐标中心 const cv::Point2f &centre
// Parameter: 最大无点角度0-360 float max_angle
// Parameter: 划分区域数量 int part_count
// Returns:   bool
// Author:    
// Date:      2018/08/28
// History:
//************************************
bool FindOneCircleFromUnformInCircle(const std::vector<cv::Point2f> &point2ds,const cv::Point2f &centre,float max_angle, int part_count) {double each_path_dog = 2.0f * M_PI / part_count;//cout<<"each_path_dog:"<<each_path_dog<<"  ";std::vector<int> counts(part_count, 0);int full_part_counts = 0;for (auto &pt: point2ds) {float alpha = atan2Ex(pt.x - centre.x, pt.y - centre.y);auto idx = static_cast<size_t>(alpha / each_path_dog);counts.at(idx)++;}//每个区域大于5个点算作填满for (auto &count: counts) {if (count > 5)full_part_counts++;}double dao_each_path_dog = 1.0 / each_path_dog;//填满区域大于需要填满的区域则返回truereturn full_part_counts  >= int(DegToRad(360.0 - max_angle) * dao_each_path_dog);
}

4、椭圆拟合

使用了OpenCV的fitEllipseEx函数。

//************************************
// Description: 将输入的point2d点集做椭圆拟合
// Method:    IsCircleFromEllipse
// FullName:  IsCircleFromEllipse
// Access:    private
// Parameter: 二维点集 const std::vector<cv::Point2f> &point2ds
// Parameter: 最小半径 float min_radius
// Parameter: 最大椭圆度(两半径比值) float min_ovality
// Parameter: 最大非拟合点 float min_error
// Returns:   bool
// Author:    
// Date:      2018/08/28
// History:
//************************************
bool IsCircleFromEllipse(const std::vector<cv::Point2f> &point2ds,float min_radius, float min_ovality, float min_error,cv::RotatedRect &ellipse) {//OpenCV椭圆拟合,要求至少有六个点输入float error = fitEllipseEx(point2ds, ellipse);float a = ellipse.size.width;float b = ellipse.size.height;//printf("a %f, b %f, ovality %f, error %f\n", a, b, a/b, error);return !(a < min_radius || b < min_radius || a / b < min_ovality || a / b > 1.0 / min_ovality ||error > min_error);
}

5、圆拟合

以重心为圆心设置半径均值和标准差阈值:

 /************************************Description: 将输入的point2d点集做圆拟合,根据圆心计算半径均值和标准差Method:    IsCircelFromDevFullName:  IsCircelFromDevAccess:    privateParameter: 最小半径均值 float min_radiusParameter: 最大半径标准差 float max_devReturns:   boolAuthor:    Date:      2018/10/17History:
************************************/
bool CircleAction::IsCircelFromDev(const std::vector<cv::Point2f> &point2ds, float min_radius, float max_dev) {cv::Point2f centre = CalcCentre(point2ds);std::vector<float> radius(point2ds.size(), 0.0f);for (size_t i = 0; i < point2ds.size(); i++) {radius.at(i) = Distance(centre, point2ds.at(i));}cv::Mat mean, dev;cv::meanStdDev(radius, mean, dev);double mean_radius = mean.at<double>(0, 0), dev_radius = dev.at<double>(0, 0);//std::cout << "radius mean---dev: " <<mean_radius << "dev_radius: " << dev_radius << std::endl;return (mean_radius > min_radius && dev_radius < max_dev);
}

6、顺/逆时针方向判断

//************************************
// Description: 将输入的point2d点集判断顺/逆时针方向
// Method:    IsClockwiseFromCross
// FullName:  IsClockwiseFromCross
// Access:    private
// Parameter: 二维点集 const std::vector<cv::Point2f> &point2ds
// Returns:   bool
// Author:    
// Date:      2018/08/28
// History:
//************************************
bool IsClockwiseFromCross(const std::vector<cv::Point2f> &point2ds) {int positive = 0, negative = 0;for (size_t i = 1; i < point2ds.size() - 1; i++) {//由i,i-1,i+1得到局部方向int status = WhichClockWise(point2ds.at(i - 1), point2ds.at(i), point2ds.at(i + 1));if (status == -1)negative++;else if (status == 1)positive++;}//  if (abs(positive - negative) < 5)//      std::cout << "[warning]: the clockwise may be wrong" << std::endl;//按正、反方向数量判断返回多的反向return (positive >= negative);
}
//************************************
// Description: 将输入的point2d点判断局部方向
// Method:    WhichClockWise
// FullName:  WhichClockWise
// Access:    private
// Parameter: 二维点a cv::Point2f a
// Parameter: 二维点b cv::Point2f b
// Parameter: 二维点c cv::Point2f c
// Returns:   int
// Author:    
// Date:      2018/08/28
// History:
//************************************
int WhichClockWise(cv::Point2f a, cv::Point2f b, cv::Point2f c) {double triangle_area = a.x * b.y - a.y * b.x + a.y * c.x - a.x * c.y + b.x * c.y - c.x * b.y;if (triangle_area < 0) return -1;else if (triangle_area > 0) return 1;return 0;
}

 

这篇关于3D手势识别(一)顺/逆时针画圈判断的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/727600

相关文章

python判断文件是否存在常用的几种方式

《python判断文件是否存在常用的几种方式》在Python中我们在读写文件之前,首先要做的事情就是判断文件是否存在,否则很容易发生错误的情况,:本文主要介绍python判断文件是否存在常用的几种... 目录1. 使用 os.path.exists()2. 使用 os.path.isfile()3. 使用

Python基于微信OCR引擎实现高效图片文字识别

《Python基于微信OCR引擎实现高效图片文字识别》这篇文章主要为大家详细介绍了一款基于微信OCR引擎的图片文字识别桌面应用开发全过程,可以实现从图片拖拽识别到文字提取,感兴趣的小伙伴可以跟随小编一... 目录一、项目概述1.1 开发背景1.2 技术选型1.3 核心优势二、功能详解2.1 核心功能模块2.

Go语言如何判断两张图片的相似度

《Go语言如何判断两张图片的相似度》这篇文章主要为大家详细介绍了Go语言如何中实现判断两张图片的相似度的两种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 在介绍技术细节前,我们先来看看图片对比在哪些场景下可以用得到:图片去重:自动删除重复图片,为存储空间"瘦身"。想象你是一个

Python验证码识别方式(使用pytesseract库)

《Python验证码识别方式(使用pytesseract库)》:本文主要介绍Python验证码识别方式(使用pytesseract库),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全... 目录1、安装Tesseract-OCR2、在python中使用3、本地图片识别4、结合playwrigh

Python如何判断字符串中是否包含特殊字符并替换

《Python如何判断字符串中是否包含特殊字符并替换》这篇文章主要为大家详细介绍了如何使用Python实现判断字符串中是否包含特殊字符并使用空字符串替换掉,文中的示例代码讲解详细,感兴趣的小伙伴可以了... 目录python判断字符串中是否包含特殊字符方法一:使用正则表达式方法二:手动检查特定字符Pytho

使用Python和PaddleOCR实现图文识别的代码和步骤

《使用Python和PaddleOCR实现图文识别的代码和步骤》在当今数字化时代,图文识别技术的应用越来越广泛,如文档数字化、信息提取等,PaddleOCR是百度开源的一款强大的OCR工具包,它集成了... 目录一、引言二、环境准备2.1 安装 python2.2 安装 PaddlePaddle2.3 安装

Python使用Matplotlib绘制3D曲面图详解

《Python使用Matplotlib绘制3D曲面图详解》:本文主要介绍Python使用Matplotlib绘制3D曲面图,在Python中,使用Matplotlib库绘制3D曲面图可以通过mpl... 目录准备工作绘制简单的 3D 曲面图绘制 3D 曲面图添加线框和透明度控制图形视角Matplotlib

判断PyTorch是GPU版还是CPU版的方法小结

《判断PyTorch是GPU版还是CPU版的方法小结》PyTorch作为当前最流行的深度学习框架之一,支持在CPU和GPU(NVIDIACUDA)上运行,所以对于深度学习开发者来说,正确识别PyTor... 目录前言为什么需要区分GPU和CPU版本?性能差异硬件要求如何检查PyTorch版本?方法1:使用命

Python如何精准判断某个进程是否在运行

《Python如何精准判断某个进程是否在运行》这篇文章主要为大家详细介绍了Python如何精准判断某个进程是否在运行,本文为大家整理了3种方法并进行了对比,有需要的小伙伴可以跟随小编一起学习一下... 目录一、为什么需要判断进程是否存在二、方法1:用psutil库(推荐)三、方法2:用os.system调用

Python实现特殊字符判断并去掉非字母和数字的特殊字符

《Python实现特殊字符判断并去掉非字母和数字的特殊字符》在Python中,可以通过多种方法来判断字符串中是否包含非字母、数字的特殊字符,并将这些特殊字符去掉,本文为大家整理了一些常用的,希望对大家... 目录1. 使用正则表达式判断字符串中是否包含特殊字符去掉字符串中的特殊字符2. 使用 str.isa