天哪这次也踩了好多坑。
上一篇【Matlab】表情合成尝试(4)——Dlib库混合编译中成功让应用了Dlib库的C++函数编译为了matlab的可用的Mex文件,又说到了Dlib库可以用来自动标定人脸的68个特征点(landmarks)。本篇便是要来具体编写接口来将Dlib的标记特征点函数应用到matlab过来。
具体内容类似上一篇也是重复了同一作者的另一篇文章的步骤
https://blog.csdn.net/ephemeroptera/article/details/83788759但是解决了一些遇到的问题并记录了下来。
一.指令集判断(可选)
首先来看看Dlib提供的特征点样例的说明,即dlib-19.1\examples\face_landmark_detection_ex.cpp,可以看到25行开始的地方写着:
可以看到如果CPU支持SSE2,SSE4或AVX指令集的话可以在cmake时附加编译选项来加速特征探测的速度。而查看支持的指令集可以使用例如CPU-Z的探测软件,例如下图为我的电脑的CPU信息,可以看到是支持这几个指令集的。
确认了支持的指令集后便可以在下面使用对应的Cmake来编译了。
二.C++编译测试(可选)
做好了前期准备后便可以来试试看这个特征点标定的实际效果了,这里先直接使用C++在windows下进行编译测试试试,先不深入代码实现。
首先由于example文件夹里有很多我们不需要尝试的项目,所以打开CMakeList.txt文件注释掉不需要编译的文件。
接着与之前类似,进入到exampe文件夹中,然后新键build文件夹,然后尝试使用和之前一样的做法来编译。
cmake -G "Visual Studio 14 Win64" ..
看看编译得到的文件列表:
然后打开face_landmark_detection_ex.vcxproj项目文件,右击此项目然后设置为启动项目,调整好编译选项后直接启动生成,就可以在build中得到生成出的exe文件。
可是程序框一闪而过,这是为什么呢?查看代码57行的介绍可以看到解释。运行此程序需要在命令行参数中附加上训练好的图像识别模型和我们需要用的图像。
在提供的链接中下载好模型后将我们的图像拷入Release文件夹中,然后在命令行中尝试运行下:
很可惜还是报错了。冷静下来看看异常提示,可以发现错误的原因是我们没有正确在项目编译选项中定义图片支持。按照上面的提示将其定义到项目中即可。
重新生成然后再运行一下,这就是样例代码在C++里的效果了,左边的图是找到的脸部区域,右边是得到的68个特征点连线。
三.样例函数分析
成功尝试了官方的代码后就该进入正题了。我们的目的是利用官方的这个代码改为需要的代码,然后利用上一篇文章的方法将其编译为mex文件。重新看看之前的example,可以发现代码主要分为三个部分:初始化,实际检测,输出。
首先是初始化阶段,这部分是用于判断输入参数格式和初始化变量,这部分需要精简。
接下来是实际检测部分,这部分是下面要编写的代码的重点。首先代码用循环遍历输入的命令行参数中的每个有效图片,读取图片然后进行扩大化,接下来检测图片中的人脸,利用循环对图片里每个人脸各自进行特征点检测,最后依次压入链表中。
显示阶段中将前面得到的人脸和特征点显示,这部分需要舍弃。
四.Matlab接口模板
从上一点中example的注释和实际代码我们可以了解到各个部分的代码的作用,但在具体编写用于混合编译的c++代码之前,我们需要先理解matlab混合编译用的代码的规范。dlib已经帮我们写好了简单易懂的模板,打开dlib-19.1\dlib\matlab\example_mex_function.cpp
首先在20行的注释中可以看到编写函数时C++变量类型与matlab变量类型的Dlib转换规范,我们希望编写的函数可以输入图片和训练模型路径然后返回人脸正方形和68个特征点。于是需要使用到的类型是array2d<rgb_pixel>,string,matrix三种。
了解了需要的变量类型后,来看看示例中主要代码部分:
可以看到这是一个很短的函数示例,也就是上篇文章的那个函数。在这里要理解的编写要点是以下几个:
理解了以上几点下一点来实际编写接口。
五.Matlab函数实际编写
思路清晰后来实际进行编写便不再困难了。
首先是函数的参数部分,与前面的预计相同,比较特别的是在Dlib中matrix需要预分配,下面的写法即是函数会返回一个1*4的矩阵和一个68*2的矩阵。
然后是函数的主要部分,在这里有个还没解决的问题是如何扩大图片方便探测?不过不扩大也有好处。读取好图片和训练模型后,内容与样例代码类似,区别在于利用matrix重载的括号运算符进行了矩阵的赋值,然后利用循环将68个点都打入了矩阵中用于返回。
然后编译前先来修改下CMakeLists的内容,将不需要编译的函数都注释掉,然后加入刚写好的函数。例如我这里是加入了add_mex_function(landmarksDetection dlib)
搞定这部分后就使用上一篇文章一样的方法:修复项目设置,编译生成...具体参照上篇文章即可:【Matlab】表情合成尝试(4)——Dlib库混合编译
完成后再简单写个Matlab用的函数来调用这个混合编译的函数。
然后和在C++下运行的操作步骤一样,把图片和训练模型放到文件夹内,接下来就可以设置文件夹目录然后在Matlab调用了。
六.后记
最后试着在Matlab运行下,效果如下,可以看到已经达到我们的要求了。至此便完成了自动标定人脸特征点的任务,只差串在一起。
时间过得好快啊,这次踩到的坑还是蛮多的,本想着这篇春节前可以发结果摸到现在233。下篇应该是写个小结简单总结一下这个表情合成的过程,然后这个小系列就算结束了吧XD