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

相关文章

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

阿里开源语音识别SenseVoiceWindows环境部署

SenseVoice介绍 SenseVoice 专注于高精度多语言语音识别、情感辨识和音频事件检测多语言识别: 采用超过 40 万小时数据训练,支持超过 50 种语言,识别效果上优于 Whisper 模型。富文本识别:具备优秀的情感识别,能够在测试数据上达到和超过目前最佳情感识别模型的效果。支持声音事件检测能力,支持音乐、掌声、笑声、哭声、咳嗽、喷嚏等多种常见人机交互事件进行检测。高效推

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

zoj 1721 判断2条线段(完全)相交

给出起点,终点,与一些障碍线段。 求起点到终点的最短路。 枚举2点的距离,然后最短路。 2点可达条件:没有线段与这2点所构成的线段(完全)相交。 const double eps = 1e-8 ;double add(double x , double y){if(fabs(x+y) < eps*(fabs(x) + fabs(y))) return 0 ;return x + y ;

POJ1269 判断2条直线的位置关系

题目大意:给两个点能够确定一条直线,题目给出两条直线(由4个点确定),要求判断出这两条直线的关系:平行,同线,相交。如果相交还要求出交点坐标。 解题思路: 先判断两条直线p1p2, q1q2是否共线, 如果不是,再判断 直线 是否平行, 如果还不是, 则两直线相交。  判断共线:  p1p2q1 共线 且 p1p2q2 共线 ,共线用叉乘为 0  来判断,  判断 平行:  p1p

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

MiniGPT-3D, 首个高效的3D点云大语言模型,仅需一张RTX3090显卡,训练一天时间,已开源

项目主页:https://tangyuan96.github.io/minigpt_3d_project_page/ 代码:https://github.com/TangYuan96/MiniGPT-3D 论文:https://arxiv.org/pdf/2405.01413 MiniGPT-3D在多个任务上取得了SoTA,被ACM MM2024接收,只拥有47.8M的可训练参数,在一张RTX

【408DS算法题】039进阶-判断图中路径是否存在

Index 题目分析实现总结 题目 对于给定的图G,设计函数实现判断G中是否含有从start结点到stop结点的路径。 分析实现 对于图的路径的存在性判断,有两种做法:(本文的实现均基于邻接矩阵存储方式的图) 1.图的BFS BFS的思路相对比较直观——从起始结点出发进行层次遍历,遍历过程中遇到结点i就表示存在路径start->i,故只需判断每个结点i是否就是stop

linux 判断某个命令是否安装

linux 判断某个命令是否安装 if ! [ -x "$(command -v git)" ]; thenecho 'Error: git is not installed.' >&2exit 1fi

SAM2POINT:以zero-shot且快速的方式将任何 3D 视频分割为视频

摘要 我们介绍 SAM2POINT,这是一种采用 Segment Anything Model 2 (SAM 2) 进行零样本和快速 3D 分割的初步探索。 SAM2POINT 将任何 3D 数据解释为一系列多向视频,并利用 SAM 2 进行 3D 空间分割,无需进一步训练或 2D-3D 投影。 我们的框架支持各种提示类型,包括 3D 点、框和掩模,并且可以泛化到不同的场景,例如 3D 对象、室