Leap Motion 已公布的官方 SDK 中,对于 Python 的兼容仅支持 Python2。官方团队对 Python 的兼容支持关注似乎不太够,其后更新的版本中,直接砍掉了官方对 Python 的兼容 SDK。

隐隐有不靠官方维护 Python 与 Leap Motion 间的兼容支持,而由开发者社区自行维护的趋势。由于某些原因(版本支持、机器学习等等),我们必须用 Python3 调用 Leap Motion,这个时候就需要我们按自己的需要(Python3.x、Python2.x、x86、x64)重新打包 SDK。

强烈提示:

以我实测来看,利用 VS2010 生成的 SDK 完成了 python3.6 调用 Leap Motion SDK 的功能,但是Leap Motion 的 on_frame功能似乎没有正常工作,仅仅运行了一次。理论上来讲,每监测到一帧图像都会触发一下这个函数。

但是实际并没有。对于用 Python 获取 Leap Motion 设备的信息,本文所做的工作只完成了一小部分功能。

仅作为工作记录。

后续进阶文章:基于 Leap Motion 2.0 利用 VS2019 生成支持 Python3.6 的 SDK

本文内容中的资源链接: https://pan.baidu.com/s/1wmF71Cj8aYUgSitiEXJmkA 提取码: qhvu

*****2020.7.7:我突然发现有人盗我文章,这让我很不舒服,故上述链接已取消分享,有需要的留邮件地址*****

如有余力,烦请通过CSDN download下载资源:Leap Motion for vs2010,我也攒点积分下载我需要的资源。

一、由 Leap Motion2.3 中的文件生成 LeapPython.cpp

先下载 swigwin-2.0.9。我尝试了 swigwin-3.0.12(本文撰写时 swig 的最新版本)和 swigwin-2.0.9,前者报错了,所以换回了后者。资源链接见:

swigwin-2.0.9 是绿色版,不需要安装,解压至文件夹中即可,如:

然后用 VS2010 创建一个 C++ 空项目。

然后将 Leap Motion2.3 SDK中的 Leap.h,LeapMath.h,,Leap.i,和 Leap.lib (x64) 拷贝到这个项目文件夹内:

在这个文件夹下运行命令行:"D:\SWIG\swigwin-2.0.9\swig.exe" -c++ -python -o LeapPython.cpp -interface LeapPython Leap.i

"D:\SWIG\swigwin-2.0.9\swig.exe"这个是我SWIG的位置,如果配置了环境变量的话直接输入 swig 就行。

正常情况下,刚刚那个文件夹里会多几个文件(Leap.py、LeapPython.cpp、LeapPython.h),并且命令行无报错

我用 swigwin-3.0.12 的时候就出错了,虽然也多了几个文件出来,但是这些文件是有问题的,后面代码根本跑不起来。

在 VS2010 中把 LeapPython.cpp 加载进来。LeapPython.h 由于和 LeapPython.cpp 在同一文件夹下,内部用的是#include “LeapPython.h” 而不是#include<LeapPython.h>,所以项目自己会检测到,Leap.py 在 python 代码中会用到。

二、由 LeapPython.cpp 生成 LeapPython.pyd

在项目上右键选择“属性”

顶部“配置”选 Release 和 x64 (我需要 x64 的),没有的话自己建一个

修改常规配置:目标文件名、扩展名、类型。文件名一般都是用 LeapPython ,自己使用或他人维护时都好理解,改成其他的也行。默认$(ProjectName)会用项目名作输出的文件名。

修改C/C++ 常规配置,把自己的python版本的 Python.h 的路径包含进来,我的是

D:\Miniconda3\Miniconda3\envs\python36\include

修改链接器输入配置,把Leap.lib 和自己版本 python 对应的 python lib加入附加依赖项中(由于是在原配置基础上加,别忘了逗号分隔),我的是D:\Miniconda3\Miniconda3\envs\python36\libs\python36.lib;

合一起就是:Leap.lib;D:\Miniconda3\Miniconda3\envs\python36\libs\python36.lib;

配置完成,运行会生成 LeapPython.dll 文件(如果有报错,后面会解释部分情况):

它启不启动无所谓,反正dll文件也不是直接启动运行的。

然后把 LeapPython.dll 重命名为 LeapPython.pyd 就可以了,对 pyd 文件不了解或者感兴趣的去了解一下就可以了。

三、LeapPython.pyd 使用示例

将生成的 Leap.py、LeapPython.pyd 和 SDK 中对应位数的 Leap.dll 拷贝至同一个文件夹。

我在 python 项目文件里建了 lib 子文件夹。

新建一个 python 脚本文件“test.py”,代码如下:

import os, sys, inspect
src_dir = os.path.dirname(inspect.getfile(inspect.currentframe()))
lib_dir = os.path.abspath(os.path.join(src_dir, 'lib'))
sys.path.insert(0, lib_dir)

import Leap

class SampleListener(Leap.Listener):
    
    def on_init(self, controller):
        print("Initialized")

    def on_connect(self, controller):
        print("Connected")

    def on_disconnect(self, controller):
        print("Disconnected")

    def on_exit(self, controller):
        print("Exited")

    def on_frame(self, controller):
       
        frame = controller.frame()
        for hand in frame.hands:
            print("hand.palm_position %s" % (
                hand.palm_position))
                
def main():

    listener = SampleListener()
    controller = Leap.Controller()
    controller.add_listener(listener)
    
    print("Press Enter to quit...")
    try:
        sys.stdin.readline()
    except KeyboardInterrupt:
        pass
    finally:
        controller.remove_listener(listener)
        
if __name__ == "__main__":
    main()


运行 python 文件,发现可以与 Leap motion 设备建立正常连接,并获取数据。但是 on_frame() 函数似乎只执行了一次,讲道理它应该会一直执行。

 

加个 try———except 看看:

def on_frame(self, controller):
       
        frame = controller.frame()
        try:
            for hand in frame.hands:                
                print("hand.palm_position %s" % (
                    hand.palm_position))
                    
        except Exception as e:
            print(e)

 仍然只执行了一次,但是没看到有什么异常。

只打印 frame 信息呢:

def on_frame(self, controller):
       
        frame = controller.frame()
        print(frame)
        '''try:
            for hand in frame.hands:                
                print("hand.palm_position %s" % (
                    hand.palm_position))
                    
        except Exception as e:
            print(e)'''

我们发现 Frame 获取是正常的,这也说明 on_frame() 函数执行是正常的,它在不停的被触发。但是对于 frame 里的数据解析可能出了问题,导致一执行类似 frame.hands 这种代码时,内部函数(LeapPython.pyd里的)就出错了,所以代码终止了。

 

这部分内容就先写到这儿。

 

四、可能遇到的错误及解决办法

使用 VS2010 时在 Python3.6 版本中会报这个错,

无论多少个错,源头都是 error C1083 : 无法打开包括文件:“inttypes.h”: No such file or directory那个。

这是因为 Python 自 3.x (x是多少我不清楚,反正3.6是不行的)开始,将 C++ 的库文件<stdint.h> 替换为了<inttypes.h>,而 inttypes.h 是 C99 标准新定义的,VS2010 此时还不支持 inttypes.h,我们直接将 Python的这个 pyport.h (原代码如下面第一张图所示)按照下面第二张图的方式进行修改即可。pyport.h 在我这儿的路径是 “D:\Miniconda3\Miniconda3\envs\python36\include\pyport.h” (我用的conda)

#if defined(_MSC_VER) && _MSC_VER < 1800
#include <stdint.h>
#else
#include <inttypes.h>
#endif

然后再运行就可以了。