本文描述一个基于人工智能2D图像识别算法实现的绘本阅读方案,应用于绘本阅读机器人和绘本阅读手机App。主要内容包括:基础算法,方案架构及工程化,项目遇到的坑及解决方案。为了更容易理解,本文重点描述项目的工程化,对于算法也做一定程度的阐述、但不做深入,相关算法资料及论文在互联网可方便搜到。
本项目要解决的核心问题是:在低算力的硬件上通过普通摄像头(2D)采集图像快速(<1s)定位到是哪一本绘本的哪一页,即需要通过计算机视觉算法来评估当前摄像头图像帧是否存在一个预置的特有FLAG。项目技术方案评估过方法主要有:
1) 基于目标分类算法,可以看作是一种图像分类的问题。先对绘本封面图像进行分类定位,找到对应绘本后,再对绘本内页图像分类定位。这个方法理论是可行的,但分布封面的分类过多(可能有超过两万本绘本),而且算法复杂度高,实际并不可行。
2)另外还有目标检测的算法,但对于绘本图像来说,并没有相对固定的特征(例如人,动植物等),所以这个方法也不可行。
3)基于图像特征匹配的图像识别,即对两个图像的特征进行匹配来预测是否为相同图像,这个算法复杂度较低,算法鲁棒性强,且绘本图像天然有较多的图像特征,这个方法与项目需求是非常匹配的,其实在技术选型时,就很快确定了这个算法基础。、
图像特征匹配中算法基础是特征因子算法,如SIFT, SURF, FAST, ORB等,综合算法的鲁棒性和复杂度,项目主要采用的是SURF和SIFT算法因子。以下是基于SURF算法因子匹配对两个图像进行匹配的代码片段,可以大概感受下:
... img1 = cv2.imread(imgname1) img1 = cv2.resize(img1, (600, 400)) kp1, des1 = surf.detectAndCompute(img1,None) #des是特向量 img2 = cv2.imread(imgname2) img2 = cv2.resize(img2, (600, 400)) kp2, des2 = surf.detectAndCompute(img2,None) matches = flann.knnMatch(des1,des2,k=2) ...
算法层面上,实现了图像特征匹配还是不够,因为还有解决一个问题:在大数量的图像中(如10000+的绘本封面图像)快速定位到目标图像,如果程序是一张一张图像的比较匹配,时效是非常低,完全达不到秒识别的要求。这时需要引用图像检索的算法,项目实现两种图像检索算法,建立图像索引,大概如下:
1)KD-tree, 基于树型布局的索引分为向量空间和度量空间。向量空间使用欧式距离来比较特征相似度,度量空间不使用欧式距离来比较特征相似度,KD-Tree是典型的基于二叉树的索引结构。
2)K-means,其首先通过聚类方法构建聚类中心,将图像特征库分成许多簇(类)。检索时,查询图像的特征向量先和聚类中心向量比较,计算向量间的距离,然后只需在距离较近的簇中进行检索。
总的来说,绘本图像的识别与查字典类似:先通过图像检索定位到少量的目标图像,然后再通过特征匹配预测出目标图像。
确定了算法基础,接下来就是充满荆棘的项目开发和落地的过程。
首先是摄像头方案选定。摄像头是产品的“眼睛”,摄像头方案对于识别的效果是有关键作用的,主要目的是保证摄像头有效成像区域覆盖绝大部分尺寸绘本翻开后的尺寸,而有效成像区域是摄像头采集到的、可用于视觉分析的图像,边角图像畸变大、失真属于无效成像区域。摄像的方案主要考虑以下因素:
1)因为摄像头是固定安装的且与采集图像的距离是相对固定,因此摄像头需要时定焦的,避免对焦过程,图像不清晰影响到识别效果。
2)FOV(摄像头视场角度),FOV越大,成像区域越广,但也会带来畸变,FOV的选定要结合产品结构。本项目摄像头的FOV是110°
3)摄像头的高度(H)和倾斜角(α)直接影响到有效成像区域,在符合“有效成像区域覆盖绝大部分尺寸绘本翻开后的尺寸”的产品需求下,根据结构综合决定。本项目中,H是13cm,α是40°
整体软件架构是经过不断设计,验证和优化得出的。
1、绘本SDK,包括Android 和 linux SDK,核心算法部分是C++写的,在Android中通过NDK融合到SDK中。SDK包含本地识别和云识别模块。本地识别主要包括:检索和识别算法,不同系统的交互逻辑;云识别模块:云服务器交互的客户端部分功能(如各种HTTP Client)。
2、云识别服务,核心算法部分是C++写的单独程序,在云上部署方式非常灵活,结合集群、均衡负载、缓存等可提升云服务性能和稳定性。前后端通过HTTP POST 图像数据为主要接口。
3、绘本训练管理系统,是C++写的程序,实现绘本数据自动批量上线:包括绘本资源数据上传到CDN存储服务器,绘本封面图典文件(图典下面详述)上传,每一本绘本图典文件上传,数据更新上线。
云识别服务器是单独高计算服务,对于服务器的高并发、高可用的追求,可用从集群、均衡负载、算法轻量化、图像信息压缩传输、热点数据缓存等方面考虑。以下是一个部署方案的参考:
是实现是算法工程化的重要一步,解决的问题是将所有绘本的图像特征和图像索引按特定数据结构描述并存储,而且图典支持叠加更新。
1、indexedDescriptors 特征向量描述列表,保存所有图像特征向量的列表,相似的特征向量会唯一元素存储。
2、wordToObject特征向量ID和图像ID的map,存储obj(即预存图像)与向量特征列表的ID的对应关系
3、scene是摄像头采集当前帧的图像特征向量列表,vocabulary是图典索引,数据结构跟图像检索算法有关:KD-Tree是二叉树;K-means是n叉树,具体树的结构暂不展开。下图描述scene的特征向量从vocabulary索引中检索到最有可能匹配的特征向量以及在indexedDescriptors中的id,检索出来后,根据wordToObject算出最有可能匹配的图像。
1、本项目中,图典是保存成文件,所有绘本的封面图像保存成一个图典文件,每一本绘本的封面和所有内页图像保存为一个图典文件。对于此类部分结构化数据,可以保存数据库中(NoSQL)。存储为文件,主要考虑到开发和运维便利。
结合产品需求,实施方案有以下两种:
1、离在线结合方案:
1)封面在云服务识别,服务器性能和存储可根据性能要求伸缩,支持大数量图像准确检索(数万绘本封面);
2)识别到封面后,本地SDK下载并加载对应封面绘本的图典文件,本地实时识别当前翻到对应内页图像。
2、离线方案
1)封面和所有绘本图典文件预先下载到本地,本地进行绘本封面和绘本内页图像检索识别。这个方案在算力和存储较低的设备上,支持绘本的数量有限。
绘本训练上线是通过绘本训练管理系统完成的,工作原理和流程是:
1、制作绘本数据:包括绘本封面和内页图像 以及 封面和每一内页对应的音频
2、将绘本数据图片和音频按特定目录文件命名存放,如下图是my dad绘本的命名例子,图片和音频命名一一对应,如图片没有对应音频,则空缺。
3、绘本训练管理系统根据命名读取图像生成所有绘本封面图典和每一绘本的图典文件,同时将图典文件、绘本图片和音频上传到CDN静态存储服务器,将静态文件URL以及绘本信息(ID,书名,ISBN号等)上线到数据库。
以下以离在线结合方案描述绘本阅读程序一个正常基本的流程,通过云服务识别绘本封面,识别到封面定位到绘本后,加载对应绘本的图典,绘本SDK本地识别绘本内页图像,识别到一页播放对应页的音频,实现 放置哪一步绘本,读那一本绘本;翻哪一页,读那一页内容。
绘本训练的方案确定、开发、实施经历一些曲折,这里也分享下。
1、虽然SIFT等特征因子算法具备方向、尺度等不变性,考虑识别效果,最初绘本训练的方案是通过绘本机器人摄像头来采集绘本图像进行训练,保持训练图像和实际使用采集图像的角度一直性。但这个方案需要绘本书本,且需要人力一本一本地训练,不具备大批量操作的可行性。
2、绘本训练方案必须自动化、大批量进行,所以把出版社的绘本高清扫描图作为训练数据似乎是唯一的方案,但这个方案还需解决图像视角不一致的问题以提高识别率,如下图,一张是绘本机器人摄像头采集的图像(灰度化),另一张是出版社绘本扫描图,两者视角有差异。解决训练图像与采集图像的视角差异的方法是:将采集图像通过透视变换将视角转换与训练图像一致后,再做特征提取。
每一帧采集图像的处理(特征提取和检索)都需要一定算力,提高计算资源效率一个方法是图像采集后预测图像是否包含绘本图像,预测到有绘本图像才进行特征提取和检索。通过图像熵值可以比较有效预测当前图像是否有绘本图像(具体方法参考代码)。
前端摄像头采集的图像可以直接将图像信息完整发送到后端进行识别,比较好的方法是将图像灰度化,去除无效数据后、再压缩传输。
在绘本数量不大的情况下,服务器上的绘本数据可以都从redis缓存获取,提高性能。