目录
前言
Leap Motion 已公布的官方 SDK 中,对于 Python 的兼容仅支持 Python2。官方团队对 Python 的兼容支持关注似乎不太够,其后更新的版本中,直接砍掉了官方对 Python 的兼容 SDK。
隐隐有不靠官方维护 Python 与 Leap Motion 间的兼容支持,而由开发者社区自行维护的趋势。由于某些原因(版本支持、机器学习等等),我们必须用 Python3 调用 Leap Motion,这个时候就需要我们按自己的需要(Python3.x、Python2.x、x86、x64)重新打包 SDK。
本文记录了我用 VS2019 基于 Leap Motion2.0 生成支持 Python 3.6 的 SDK 的全部过程及遇到的问题。
本文和我另一篇文章有很多类似的地方,因为我尝试了很多方法,鼓捣了很久。
较上一篇文章的进展为:
利用 VS2019 生成的 SDK 完成了 python3.6 调用 Leap Motion SDK 的功能,通过在 python 代码中加入异常捕获逻辑,可以正常持续获取 Leap Motion 的数据,但是由此生成的 LeapPython.pyd 中含有未解决的80多个异常,有可能对 python 代码产生影响。
本文内容中的资源链接: https://pan.baidu.com/s/17BezPQWFrs3aeDPSp3SQ5A 提取码: cr1r
2020.7.7:我突然发现有人盗我文章,这让我很不舒服,故上述链接已取消分享,有需要的留邮件地址
如有余力,烦请通过 优快云 download 下载资源:Leap Motion for vs2019,我也攒点积分下载我需要的资源。
一、由 Leap Motion2.0 中的文件生成 LeapPython.cpp
swig 的安装
先下载 swigwin-2.0.9。我尝试了 swigwin-3.0.12(本文撰写时 swig 的最新版本)和 swigwin-2.0.9,前者报错了,所以换回了后者。资源链接见:
swigwin-2.0.9 是绿色版,不需要安装,解压至文件夹中即可,如:
生成 LeapPython.cpp
用 VS2019 创建一个 C++ 空项目
然后将 Leap Motion2.0 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 的时候就出错了,虽然也多了几个文件出来,但是这些文件是有问题的,后面代码根本跑不起来。
在 VS2019 中把 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;
切回主界面,把这里改改
还剩80多个错误(开启IntelliSense后才能看到这些错误),我看大部分都与Leap这个类有关
先赌一波,强行运行,我们发现它竟然顶着错误成功生成了LeapPython文件,
拿着这个生成的 LeapPython.dll 去进行测试(将 LeapPython.dll 重命名为 LeapPython.pyd),发现可以在 python3.6下与Leap Motion进行连接,但是有异常抛出,大意是delete_HandList这个函数里出了问题
,所以生成的这个 LeapPython.dll 文件里面是有问题的。即便如此,还是建议各位平时遇见错误时,先赌一波试试,没准真有效果呢。
有可能是 Leap.h 或 Leap.lib 的问题,因为 Leap.i 是给 swig 用的,Leap.py 是给 Python 用的,此处略去一大堆我探索的方式。因为我失败了,没解决掉这 80 多个错。
几经辗转,我又回到了原点,拿着这个运行有错误抛出的 LeapPython.pyd ,想着在 python 代码 上下下功夫。
三、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 设备建立正常连接,虽然报错了,但是它正确地获取到了数据。
只输出 frame 信息的话,运行也是正常的:
def on_frame(self, controller):
frame = controller.frame()
print(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:
pass
运行完全正常。
结论
在没有更好的替代方案前,可以勉强用“包含错误的 LeapPython.dll ”链接库。
对于 python 代码,可以在 try …except 中写代码逻辑。但应时刻记住,LeapPython.pyd 中含有80多个未解决的异常,有可能对 python 代码逻辑造成影响。