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
然后再运行就可以了。