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项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)_第1张图片

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

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

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

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

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

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

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

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

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

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

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

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

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

解决方案: 1.项目属性的包含目录大概率路径不正确
LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)_第11张图片
2.直接把官方文档的LeapC.h复制到项目头文件中
LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)_第12张图片

问题:XXXXXXXXX.exe打不开

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

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

解决方案,1,检查目录,标红地方是否正确
LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)_第13张图片
2.检查附加依赖项,注意是LeapC.lib,之前很多博主都是Leapd.lib,或是Leap.lib,都是错的
LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)_第14张图片

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

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

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

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

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

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

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

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

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

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

你可能感兴趣的:(Leapmotion,可视化,C语言,Leapmotion,手势识别,3D识别)