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

5 篇文章 2 订阅
1 篇文章 0 订阅
本文档记录了一位开发者使用LeapMotion进行手势识别,实现石头剪刀布游戏及数字识别的过程。通过关键函数hand.grab_angle判断手势,并结合opencv显示结果。在开发过程中遇到并解决了一系列配置和编程问题,包括LeapC.lib的寻找、C与C++文件的互相调用等。项目最终完成,开发者计划将其应用于手语交流模型。
摘要由CSDN通过智能技术生成

前言

最近长沙疫情不能出门,就只能在家里玩玩,刚好把项目组的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);
        }
     }
}

心路历程:开始–咋弄了?–有思路了!–人麻了。。–彻底麻了。。–好起来了–完成!

看到一篇博客,很有启发

在这里插入图片描述

晚上和hxd开黑,遇到了玩的菜的喷子,我当时就想,长了张嘴可惜了,喷子不如日常用手语交流。突然想到leapmotion可以做一个手语交流模型,就有了下面这个备忘录,嗯哼,大二的大创课题有了。

在这里插入图片描述
在这里插入图片描述

开干,发现问题了,因为下载的官方的SDK,直接打开的文件夹,没有配置,也就是根本不算一个真正的项目,后期配置不了opencv与数据库,所以决定配置完整的项目。

在这里插入图片描述
在这里插入图片描述

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

凌晨到早上八点一直调bug,熬到了天亮早上8点,去睡觉了,困。

下午两点接着干,在LeapC.lib以几乎碰运气得方式解决后,四点成功配置完成leapmotion

在这里插入图片描述

后来继续睡了会儿,起来配置完所有的opencv与.c与.cpp之间函数的互相调用,所有项目配置完成。然后写算法,找图片,写代码框架,以后再添手势,就是参数问题了,简便很多。毕竟项目组今年获得了互联网+的省金,暑假继续出力,希望明年进国赛

在这里插入图片描述

各种离谱!离谱!搞心态的BUG合集

问题:无法找到LeapC.h文件

解决方案: 1.项目属性的包含目录大概率路径不正确
在这里插入图片描述
2.直接把官方文档的LeapC.h复制到项目头文件中
在这里插入图片描述

问题:XXXXXXXXX.exe打不开

解决方案,1.重启VS,2.重启电脑,是因为.exe已经打开过了,不能再次打开,但是它在哪个端口你并不知道,所以重启关闭端口,解决问题。

问题:无法找到LeapC.lib文件

解决方案,1,检查目录,标红地方是否正确
在这里插入图片描述
2.检查附加依赖项,注意是LeapC.lib,之前很多博主都是Leapd.lib,或是Leap.lib,都是错的
在这里插入图片描述

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

#pragma comment(lib,"LeapC.lib")

在这里插入图片描述

.c文件与.cpp文件互相调用

解决方案:
C与C++互相调用

vs怎么同时运行多个main函数

解决方案:解决方案——属性–多个启动项目–选择项目启动

在这里插入图片描述

opencv不能直接用在官方文档的.c中

解决方案:新建.cpp文件写入opencv的函数,上面用.c与.cpp互相调用的方法
原理:.c与.cpp(C++)的接口不相容

void cedl_XXXXXXXXXXX main函数找不到

解决方法:1 .c与.cpp不兼容,更改后缀名
2. lib配置不正确,看上面的lib配置方法

leapmotion的学习途径分享

码文不易,期待一间三联!!!

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超超不写代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值