Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)

前言 最近长沙疫情不能出门,就只能在家里玩玩,刚好把项目组的leapmotion带回来了,就把互联网+省赛还未完全实现的代码,给实现下,一周前立下个flag要把手势识别系统做出来,结果几天都在玩游戏,想着不行啊,要动手做了,白天干了2天,熬了两天的夜,困难很多还是给肝出来了
leapmotion手势识别的思路及代码展示

间短介绍:leapmotion是我觉得是一款很不错的“玩具”,3D手模型,三维坐标,优秀的精度,200fps的刷新率,其实从项目组买leapmotion,到我真正上手它,到做完这个小项目,其实不到一个月,所以个人感觉上手不难。强烈建议要看文章末尾的BUG总结
开发语言:C,C++
开发者:杨富超
编译器工具:vs2019
leapmotion版本:4.1.0
opencv版本:4.1.0
CSDN源码下载:项目源码

动图展示

  1. 了解leapmotion的重要函数:hand.grab_angle,这个函数是项目的关键函数之一,以hand.grab_angle为主要判断依据,大于2.2的为拳头,小于0.65的为布,剩下的为剪刀。
    原理:hand.grabAngle()返回的是除却大拇指四根手指的平均弯曲程度,所以紧握拳头的时候数值为3.14(反复测试过了),出布的时候基本也为0,出剪刀的时候一般在1.8左右.
    2.为了减少误差,我们可以取多帧的均值,思路是:设置全局变量
int sum = 0; //计算平均值用 long long int num = 0; //ave_number帧一算 int ave_number = 5; //多少帧一算

然后再调用的函数中用个小算法,num每一帧加一,sum加上每次的hand.grabAngle(),num是五的倍数时,再算平均值,最后把sum归零
leapmotion猜拳游戏代码展示
static void OnFrame(const LEAP_TRACKING_EVENT* frame) {printf("Frame %lli with %i hands.\n", (long long int)frame->info.frame_id, frame->nHands); //几只手 num++; for (uint32_t h = 0; h < frame->nHands; h++) {//几个手 LEAP_HAND* hand = &frame->pHands[h]; printf("Hand id %i is a %s hand with position (%f, %f, %f).\nthumb:(%f,%f,%f)\n", hand->id, (hand->type == eLeapHandType_Left ? "left" : "right"), hand->palm.position.x, hand->palm.position.y, hand->palm.position.z, hand->thumb.bones->next_joint.x, hand->thumb.bones->next_joint.y, hand->thumb.bones->next_joint.z ); sum += hand->grab_angle; //五次的总值 if (num % ave_number == 0) { int average = sum / ave_number; //五次的平均值 if (average >= 2.2) {printf("石头"); CAdd(3); } else if (average < 0.6) {printf("布"); CAdd(1); } else {printf("剪刀"); CAdd(2); }sum = 0; } } }

  1. 网上找几张石头剪刀布的图片,方便我们演示,至于演示什么图片,由上面代码中的CAdd函数传入的参数决定,当然这是配置了opencv的
//1:布 2:剪刀 3:拳头4:数字一5:数字二6:数字三 7:数字四 8:数字五 9:点赞 10:ok void CAdd(int num) { std::cout << "Hello OpenCV4.10!\n"; Mat img; if (num == 1) { img = imread("image/a1.png", IMREAD_ANYCOLOR); } else if (num==2) { img = imread("image/a2.png", IMREAD_ANYCOLOR); } else if (num == 3) { img = imread("image/a3.png", IMREAD_ANYCOLOR); } else if (num == 4) { img = imread("image/a4.png", IMREAD_ANYCOLOR); } else if (num == 5) { img = imread("image/a5.png", IMREAD_ANYCOLOR); } else if (num == 6) { img = imread("image/a6.png", IMREAD_ANYCOLOR); } else if (num == 7) { img = imread("image/a7.png", IMREAD_ANYCOLOR); } else if (num == 8) { img = imread("image/a8.png", IMREAD_ANYCOLOR); } else if (num == 9) { img = imread("image/good.png", IMREAD_ANYCOLOR); } else if (num == 10) { img = imread("image/ok.png", IMREAD_ANYCOLOR); } if (!img.data) { printf("error,no image!\n"); } imshow("图片显示", img); waitKey(1); }

4.对于数字识别,要先了解leapmotion的另外一个函数:hand->digits[0].is_extended,digits[5]是个包含五个手指的数组,digits[0]是大拇指,is_extended函数是bool类型的,如果这个手指伸直,那么就返回true,否则返回flase,有了这个函数,我们可以识别很多的手势,例如:数字一,食指伸直且其他手指均弯曲。介绍下leapmotion另外一个函数hand.pinch_distance,这个函数是返回大拇指与食指间的距离,多用于捏取手势识别,其实is_extended也能用上面介绍的函数hand.grab_angle来做,只是我还没摸清他们的大致判断范围,之后会把范围发表出来
leapmotion数字识别代码展示
/** Callback for when a frame of tracking data is available. */ static void OnFrame(const LEAP_TRACKING_EVENT* frame) {printf("Frame %lli with %i hands.\n", (long long int)frame->info.frame_id, frame->nHands); //几只手 num++; for (uint32_t h = 0; h < frame->nHands; h++) {//几个手 LEAP_HAND* hand = &frame->pHands[h]; printf("Hand id %i is a %s hand with position (%f, %f, %f).\nthumb:(%f,%f,%f)\n", hand->id, (hand->type == eLeapHandType_Left ? "left" : "right"), hand->palm.position.x, hand->palm.position.y, hand->palm.position.z, hand->thumb.bones->next_joint.x, hand->thumb.bones->next_joint.y, hand->thumb.bones->next_joint.z ); sum += hand->grab_angle; //五次的总值 //1:布 2:剪刀 3:拳头4:数字一5:数字二6:数字三 7:数字四 8:数字五 9:点赞 10:ok if (hand->digits[0].is_extended && !hand->digits[1].is_extended && !hand->digits[2].is_extended && !hand->digits[3].is_extended && !hand->digits[4].is_extended) { printf("点赞\n"); CAdd(9); } else if (hand->pinch_distance < 3.0 && hand->digits[2].is_extended && hand->digits[3].is_extended && hand->digits[4].is_extended) { printf("欧克"); CAdd(10); } else if (!hand->digits[0].is_extended && hand->digits[1].is_extended && !hand->digits[2].is_extended && !hand->digits[3].is_extended && !hand->digits[4].is_extended) { printf("数字一\n"); CAdd(4); } else if (!hand->digits[0].is_extended && hand->digits[1].is_extended && hand->digits[2].is_extended && !hand->digits[3].is_extended && !hand->digits[4].is_extended) { printf("数字二"); CAdd(5); } else if (!hand->digits[0].is_extended && !hand->digits[1].is_extended && hand->digits[2].is_extended && hand->digits[3].is_extended && hand->digits[4].is_extended) { printf("数字三"); CAdd(6); } else if (!hand->digits[0].is_extended && hand->digits[1].is_extended && hand->digits[2].is_extended && hand->digits[3].is_extended && hand->digits[4].is_extended) { printf("数字四"); CAdd(7); } else if (hand->digits[0].is_extended && hand->digits[1].is_extended && hand->digits[2].is_extended && hand->digits[3].is_extended && hand->digits[4].is_extended) { printf("数字五"); CAdd(8); } } }

心路历程:开始–咋弄了?–有思路了!–人麻了。。–彻底麻了。。–好起来了–完成!
看到一篇博客,很有启发
Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

晚上和hxd开黑,遇到了玩的菜的喷子,我当时就想,长了张嘴可惜了,喷子不如日常用手语交流。突然想到leapmotion可以做一个手语交流模型,就有了下面这个备忘录,嗯哼,大二的大创课题有了。
Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

开干,发现问题了,因为下载的官方的SDK,直接打开的文件夹,没有配置,也就是根本不算一个真正的项目,后期配置不了opencv与数据库,所以决定配置完整的项目。
Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

网上找博客,配置vs如何配置leapmotion,链接我放在后面的leapmotion的BUG模块了。过程当然是不出意外的话,要出意外了,一个LeapC.lib一直找不到,exe还打不开了,重新新建了项目,重新配置,删除官方文档多余的.c文件,.h文件,又遇到main函数重复,人麻了从凌晨弄到2点,心态崩了,去刷了会儿抖音,然后接着干,因为OpenCV只能配置到.cpp的文件,期间又遇到了.cpp与官方文档的sample里面的.c文件不兼容的问题,LeapC.lib还是没找到,exe在电脑重启后解决了。项目前后看了不下150篇各种网站的博客,帖子,leapmotion在国内的问题解决方案与案例真的还是太少了。最后的BUG介绍值得一看
Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

凌晨到早上八点一直调bug,熬到了天亮早上8点,去睡觉了,困。
Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

下午两点接着干,在LeapC.lib以几乎碰运气得方式解决后,四点成功配置完成leapmotion
Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

后来继续睡了会儿,起来配置完所有的opencv与.c与.cpp之间函数的互相调用,所有项目配置完成。然后写算法,找图片,写代码框架,以后再添手势,就是参数问题了,简便很多。毕竟项目组今年获得了互联网+的省金,暑假继续出力,希望明年进国赛
【Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)】Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

各种离谱!离谱!搞心态的BUG合集 问题:无法找到LeapC.h文件 解决方案: 1.项目属性的包含目录大概率路径不正确
Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

2.直接把官方文档的LeapC.h复制到项目头文件中
Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

问题:XXXXXXXXX.exe打不开
解决方案,1.重启VS,2.重启电脑,是因为.exe已经打开过了,不能再次打开,但是它在哪个端口你并不知道,所以重启关闭端口,解决问题。
问题:无法找到LeapC.lib文件
解决方案,1,检查目录,标红地方是否正确
Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

2.检查附加依赖项,注意是LeapC.lib,之前很多博主都是Leapd.lib,或是Leap.lib,都是错的
Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

3.用这个代码来找,加上还是错的话,把LeapC.lib直接复制进来,这个方法一样适合于opencv的lib找不到
#pragma comment(lib,"LeapC.lib")

Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

.c文件与.cpp文件互相调用
解决方案:
C与C++互相调用
vs怎么同时运行多个main函数
解决方案:解决方案——属性–多个启动项目–选择项目启动
Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
文章图片

opencv不能直接用在官方文档的.c中
解决方案:新建.cpp文件写入opencv的函数,上面用.c与.cpp互相调用的方法
原理:.c与.cpp(C++)的接口不相容
void cedl_XXXXXXXXXXX main函数找不到
解决方法:1 .c与.cpp不兼容,更改后缀名
2. lib配置不正确,看上面的lib配置方法
leapmotion的学习途径分享
  • Leapmotion官网
  • vs2019配置opencv
  • vs2019配置Leapmotion
  • Leapmotion中文文档百度网盘 提取码:0zx3
  • B站Leapmotion学习视频(Unity)
  • 项目所有代码-百度网盘 提取码:8888
  • 记得配置好环境
    遇到的问题可以看看本文BUG介绍,也许就有你的BUG
码文不易,期待一间三联!!!

    推荐阅读