OpenCV简单实现AR需用到的算法函数介绍
目前的AR需求(想要达到的目标)
公司目前的需求是要能够指定一个物体开始追踪,将一张预先准备好的图像覆盖在被追踪的物体上,
然后镜头偏转缩放各类操作,再转回来仍然可以识别到,并且同样依旧覆盖图片到先前的位置上来。
有点类似Google Camera 里内置的AR Stickers功能:
但是我们的需求不是在移动终端上实现,而是在PC上后置视频,所以不能像手机那样获取到各类陀螺仪、加速度仪和指北针等Sensors进行惯性定位式的追踪。
所以这个需求只能考虑只能依靠图像识别来实现之。
目标追踪算法
OpenCV内置提供的追踪算法有很多种,我大概把它分为三大类:
目标追踪算法、稠密(密集)光流算法、稀疏光流算法
每一类里面又有很多种算法。
1. Kalman(很古老的算法,卡尔曼滤波)
http://en.wikipedia.org/wiki/Kalman_filter
2. Meanshift(均值偏移算法)
https://en.wikipedia.org/wiki/Mean_shift
3. Camshift(是MeanShift算法的改进,称为连续自适应的MeanShift算法)
https://docs.opencv.org/4.6.0/d7/d00/tutorial_meanshift.html
4. Boosting(HAAR级联,相当于AdaBoost的在线版本,抖动很厉害,不建议使用)
5. MIL(比Boosting好,但是有遮挡不佳)
http://vision.ucsd.edu/~bbabenko/project_miltrack.shtml
6. KCF(比Boosting和MIL都要快,但是有遮挡时不佳)
http://www.robots.ox.ac.uk/~joao/publications/henriques_tpami2015.pdf
http://www.cvl.isy.liu.se/research/objrec/visualtracking/colvistrack/index.html
7. CSRT(速度比KCF慢一些,但是比KCF精确)
Lukezic_IJCV2018 Discriminative Correlation Filter
8. MedicamFlow(提供跟踪评分机制,跳动太快速可能会失效
http://www.aonsquared.co.uk/node/5
9. TLD(误报多,需跟踪、学习、检测,可解决遮挡问题,但不适合坐多行人下的跟踪)
TLD (Tracking, learning and detection)
10. MOSSE(速度块,准确性较高,遮挡下效果也还能接受)
MOSSE (Minimum Output Sum of Squared)
11. GOTURN(基于深度学习,处理遮挡效果不佳,需要提前训练好caffe模型文件)
http://davheld.github.io/GOTURN/GOTURN.pdf
https://github.com/davheld/GOTURN#train-the-tracker
https://github.com/Auron-X/GOTURN_Training_Toolkit
12. DaSiamRPN(基于深度学习,需要提前训练好onnx模型文件)
跟GOTURN类似,就是模型文件格式支持的不同。
稠密(密集)光流算法
1. Farneback(Gunnar Farneback's algorithm)
2. Variational optical flow refinement
3. DIS(Dense Inverse Search (DIS) optical flow algorithm)
稀疏光流算法
1. SparsePyrLK(Lucas-Kanade optical flow algorithm)
小试牛刀
上一章节既然说是AR,那我就用OpenCV里面提供的AR模块,来试试看能做到哪一步。
AR模块叫ArUco模块,它提供导出一些固定用于识别标定(标记)的函数。
cv::aruco::getPredefinedDictionary()
再使用cv::aruco::drawMarker()加入不同ID参数和想要生成图片的特定宽高的形态各不相同的二维码图片。
如下图所示:
我们将它用打印机打印出来,以便于在现实中镜头中识别。
将视频载入到识别程序中来,然后调用cv::aruco::drawDetectedMarkers()函数,它的作用就是内置了一个将所有识别出来的aruco生成的标定图自动画个框,一般用于调试。
将会得到类似下图这样:
编号左上角为1,右上角为2,右下角为3,左下角为4。
既然准确的将识别到的aruco标定图框出来了,那剩下来的当然好办了。
取一张要覆盖的照片:
将识别到的上下左右四个标定图的四个角找到(图1的左上角和图2的右上角和图3的右下角和图4的左下角)
然后使用透视变换将图片扭曲拉伸缩放透视变换到上一步四个角位置,
主要用到的函数有:cv::findHomography() cv::warpPerspective() cv::fillConvexPoly()
第一个函数cv::findHomography()是根据两组离散的点计算出透视变换矩阵。
第二个函数cv::warpPerspective()是使用上一步计算出来的透视变换矩阵去将图片矩阵变换成需要的样子。
第三个函数cv::fillConvexPoly()用指定颜色(白色)颜色填充多边形区域,是为了覆盖透视变换后的图片到原视频帧上需要的掩码图所做的准备的。
如下图所示:
将上一步透视变换的图片覆盖到视频帧上:
视频效果:(未加入任何追踪的版本)
改进纯aruco标定识别
上面的演示效果视频,如果您看了肯定会觉得在被遮挡的时候,效果会很差,因为四张标定图如果缺了某一张就可能会乱飞。
所以我考虑了并实作了用稀疏光流法追踪法去辅助上面的单纯的标定识别法,
在四张标定图有任意一个没有识别到的情况下,就用稀疏光流追踪法去预测当前帧应该的位置,
参考关键点就从视频帧中的整张图上去选。
要使用 稀疏光流追踪主要就几个步骤:
第一步:针对要追踪的物体或者背景识别角点(关键点),关于这部分,我上一篇博客有介绍过角点检测的11种算法。
第二步:将前后两帧的统计出来的角点进行对比(cv::calcOpticalFlowPyrLK()),得到两帧的图像中物体的变换矩阵。
第三步:用这个变换矩阵去影响aruco标定法中未被识别到的矩阵点。
可以看下有加入稀疏光流追踪的改良版本视频效果:
结合物件追踪算法
本来想法是既然物件追踪算法OpenCV提供了12种,各有优劣,觉得一定有一种是最适合自己场景的。
我就逐一尝试了下各类内置的物件追踪算法,每一帧都来追踪,比较一下各类追踪算法追踪效果:
实际上发现追踪效果并不尽人意(视频只显示了4种算法,实际上我尝试了8种追踪算法,当时的视频没保存)。
基本上都不会完全达到需求中所说的移出镜头视角范围再移回来能持续被追踪,甚至未移出镜头视角范围内有些追踪算法都会跟丢。。。
这样的话不但起不到辅助的作用,甚至还会带偏原本稀疏光流法追踪和aruco的结果。
稀疏光流法的骚操作
尝试了很多追踪算法,都觉得不尽人意,为什么不死磕在稀疏光流法上呢?
既然它这么好用,如果被追踪的物体移出了镜头,想想为什么不在脱离镜头视角范围之外的瞬间改成环境的光流追踪,类似上一篇文章视频防抖那样,
然后一直将变换矩阵应用到脱离视角前最后一帧时的位置开始持续应用变换矩阵,使其在视角范围之外也能持续追踪,即使是在可见坐标范围外也一样能work。
既然想到了就这么实现了:
下图为追踪键盘上的品牌logo,调焦距放大镜头,使其键盘logo脱离视角范围外,再焦距回来,仍然可以接着原来的位置。
下图为追踪键盘上的Page Down按键
总结这种方法的缺点:
1. 被追踪的物体是允许移动的,并且移动在一定条件下也是可以持续被追踪到的,
但是要注意到的是移动的时必须在镜头视角范围内移动,如果是在背后视角外私底下动就没办法了。
2. 如果被追踪的物体移出镜头视角范围太长时间,视频移动太远距离,抖动太剧烈,也会不准确的。