说起脚本语言调用opencv,我们通常会想到python。如果说要在更小的系统中使用脚本语言,我们会想到lua。如果说用lua进行图像处理,我们肯定会想到大名鼎鼎的torch。torch中的image模块重写了opencv,封装了lua接口,但是如果我们不想修改opencv如此庞大的源码,又想像python调用opencv那样简单直接,那应该怎么做呢?
在正式开始介绍之前,想展示一段简答的代码,来告诉大家即将要做的事情是什么。(也是假人以渔了^_^)
cv = require("cv") local img = cv.Mat.zeros(500, 500, cv.CV_8UC3) cv.putText(img, 'Hello OpenCV', {50, 50}, cv.FONT_HERSHEY_SIMPLEX, 2, cv.Scalar(0, 0, 200), 2, cv.LINE_AA) cv.imshow('test', img); cv.waitKey(0);
上面不是python,可是一段lua代码哦(⊙o⊙)
一、编译lua
参见我上一篇博客,编译出的lua5.3.5.lib需要在这篇博客的程序中进行链接
二、编译LuaOpenCV
博主参考过LuaCV、torch-opencv等各种lua调用opencv的方式,它们都大张旗鼓的修改了OpenCV源码,也就是说我们必须有无限的精力来跟上OpenCV的迭代,博主认为对于一个不断迭代的系统颇为不妥,于是博主在github上找到了一位专门折腾lua的大神satoren(应该是个日本人) 主页 https://github.com/satoren
我们使用他给的一套工具kaguya来编译OpenCV
satoren / kaguya
C++ binding to Lua
0. 编译OpenCV
如果我们已经有OpenCV了我们就可以跳过这一步。
这里我们要注意OpenCV版本的问题,3.1 -3.4.13都可以,OpenCV4在编译LuaOpenCV的时候会有许多问题,用OpenCV3.1 几乎不需要怎么修改,因为原作者就是指定了OpenCV3.1,用高版本的OpenCV就需要在后面多解几个bug。确认版本后,我们就可以编译OpenCV了。
1. 下载LuaOpenCV源码
这个的来源也是satoren大神,这里博主用的opencv3.4.3,需要做些修改,这里就fork了下,引用了博主自己的仓库(你完全可以链接到原始仓库)
P-Chao / luaOpenCV
OpenCV wrapper for Lua
2. 下载3rdparty库
这里有四个3rdparty库:
opencv >>> 如果你已经有opencv的话,就不用了
googletest>>> 如果你编译测试程序,需要在github上clone googletest放到源码3rdparty目录下(使用git submodule命令同步也可以,参见readme)
kaguya>>> 这个库非常重要,也是放到3rdparty目录下(也可使用submodule命令同步)
lua>>> 这种直接下载官网的源码包,解压到3rdparty目录下就可以了
3. 修改CMakeLists
首先,修改OpenCV版本要求大于3就可以了
然后,修改Lua库查找(博主发现findLua.cmake有问题,可能找不到lua库)。需要指定Lua包含目录、库目录、链接库名称,这三项就可以了。
博主fork之后,已经修改了cmakelist,你可能需要按照你自己的lua路径对照修改
4. 解决编译错误
博主在用VS2013工具集编译过程中,遇到了一个 “!”运算符重载出错的问题,在!后面加一个bool强制类型转换就可以了 if(!(bool)tabel[“name”]){} 类似这种
5. 解决绑定错误
由于OpenCV版本的更迭,raw_bind_generated.inc 这个包含函数绑定信息的文件也需要更新。由于博主还没有弄清楚 kaguya 是如何生成该文件的,所以博主没有选择重新生成该文件,而是直接在原文件基础上进行修改(主要是注释掉一些类构造函数的绑定)。
下图中.constructors就是构造函数,在编译过程中,一个模板生成的构造函数检查会疯狂报raw_bind_generated.inc的问题,每报一次错,就注释掉对应的类的构造函数(有时需要注释掉整个类),发现有问题就注释,然后重新编译。(这一步博主重复了大概二三十次,所以要有耐心)
如果你生成了cv.dll那么恭喜,我们来测试以下吧
三、测试Demo
我们使用 sample/hello_opencv.lua 的opencv来测试。我们保证opencv_world.dll\lua5.3.5.dll\lua.exe都在环境变量中。我们把刚编译好的cv.dll拷贝到sample目录下。
然后命令行进入sample目录,说出咒语 > lua hello_opencv.lua
如果弹出hello_opencv 窗口,那么恭喜,欢迎来到opencv的lua世界。
四、使用kaguya封装自己的函数
如果自己的函数也需要封装kaguya应该怎么办呢?这就需要我们简单了解下kaguya了。
kaguya是一个纯模板文件,没有任何实现,所有实例都是在编译期完成的
我们使用kaguya封装自己的函数完全可以参考luaOpenCV中的manual_bind.cc 和 manual_bind.inc
1. 书写自己的注册函数
将自己的封装按照kaguya_manual_bind(); 函数一样进行书写
这里注意,function可能会报错,我们一定要使用kaguya::function来注册我们的函数,因为std里面也有function,可能会串扰。
用constant来注册我们常量,用class_<>来注册我们自己的类,参考kaguya_manual_bind();这个的写法就可以
2. 将自己的注册函数加入绑定
自己的注册函数需要在manual_bind.cc中进行声明
然后再manual_bind.inc中再声明一次(这次是为了加入raw_bind_generated.inc)
3. 将工程修改成自己的dll(so)名
再raw_bin_generated.inc中KAGUYA_BINDINGS(cv) 这个宏,就定义了lua调用dll的入口,因此我们编译出的只能是cv.dll才能被调用。如果我们需要用其它的dll名,修改这个宏的参数就可以了
这里注意4786行这里,就将我们自己的注册项进行注册了,因为KAGUYA_BINDINGS所包围的块都会被注册。大致过程清晰明了吗。
4. 使用kaguya提供的python自动封装工具
这个博主还没有弄清楚,只是告诉大家,kaguya和opencvlua中各自都有一些自动生成注册 .inc 文件的工具,opencv如此庞大的代码量,不可能一个个类去手工分析注册,可以研究下,看下官方的github\文档\issus等。
五、OpenCV4.0的lua移植
大体过程是一样的,只是中间的.inc绑定文件需要用kaguya工具和luaopencv里面的.py重新生成,博主一时还没机会折腾,如果有少侠折腾了并且愿意分享出来,请一定告知博主(下方留言即可),比万分感谢。如果再折腾过程中有问题,也欢迎与博主交流。
不知道为啥,这样调用会报错,看起来像是参数错误
local srcImage=cv.imread(“test.PNG”);
local fast=cv.FastFeatureDetector.create();
local detectKeyPoint=cv.KeyPoint.new()
fast:detect(srcGrayImage,detectKeyPoint);
错误信息:
maybe…Argument mismatch:userdata,nil,userdata candidate is:
cv::Feature2D,cv::_InputArray,std::__1::vector<cv::KeyPoint, std::__1::allocator >,[OPT]cv::_InputArray,
Argument mismatch 就是入参类型不正确了,可能需要打印出类型来看看,看是不是要转化写写法,输入需要是:cv::Feature2D,cv::_InputArray,std::__1::vector, 但是你输入的参数类型是 userdata,nil,userdata
我看了下源码需要转换。就是我没学过c++。对kaguya 那个自定义类型转换看的一知半解的。您可以帮我看看么?。付费。谢谢了
感觉问题在 std::vector cv::KeyPoin 这个上
opencv的dll,和自己编译出来的dll,出问题的lua脚本,打包发到我的邮箱deeplearning@vip.qq.com 吧,我看一下
…..我编译的iOS 上的。没有编译电脑上的。用的opencv 3.2。 获取能微信或者 QQ联系到你么?
lua code:
local img=cv.imread(“test.PNG”);
local keypoints=cv.KeyPoint.new()
local detector=cv.ORB.create(50);
detector:detect(img,keypoints)
根据网上c++的教程 转的。 opencv 的detect 定义是这样的 detect(InputArrayOfArrays images,std::vector< std::vector > & keypoints,InputArrayOfArrays masks = noArray() ) 他第二个参数在经过kaguya 的绑定后变成了 2个 报错如下:
maybe…Argument mismatch:userdata,userdata,userdata candidate is:
cv::Feature2D,cv::_InputArray,std::__1::vector<cv::KeyPoint, std::__1::allocator >,[OPT]cv::_InputArray,
cv::Feature2D,cv::_InputArray,std::__1::vector<std::__1::vector<cv::KeyPoint, std::__1::allocator >, std::__1::allocator<std::__1::vector<cv::KeyPoint, std::__1::allocator > > >,[OPT]cv::_InputArray,
改lua就可以了,应该不用改c++,回头我配下环境看下
您有 ios 的越狱设备吗?或者我吧 编译好的iOS 库发您?另外 我可以可以联系到您么?不能让你白白忙活啊。配置这个挺麻烦的。 我也可以远程给您测试
我也要, 付费