由于近期微信小程序有上线以图识图功能的迫切需求,于是进行了一段时间的技术调研,分析下来大概有三种实现方式。方式一是找专业的图像识别的商业公司,省时但费钱,这些公司会针对客户特定的领域和个性化需求做定制化实现,可以达到怎样的效果不确定;方式二是调用各大搜索引擎和第三方应用的以图搜图API,但可能会受到API可用性、访问速度、访问频率、IP限制等因素的影响;方式三是利用开源的机器学习系统搭建自有的识图系统,实现难度较大,但实现以后会形成较高的技术壁垒。鉴于各方面成本的考虑,我们计划先以识别率较高的搜索引擎和第三方应用的以图搜图API为基础搭建服务,再逐步迁移到基于TensorFlow搭建的自有识图系统上。
以图识图的基本原理是,基于大量已知物种的图片训练模型并建立检索表,识图时通常先做高斯降噪处理,然后提取物种的形状、纹理、颜色等特征数据,最后在样本库搜索相似的图片并按相似度排序。其实图像识别技术已经有几十年的发展历史了,但仅仅在近两年由于深度学习等技术的发展使得识别率大幅提升,图像识别技术才被应用到越来广泛的场景中。此外,Google开源的TensorFlow深度学习系统也使得非专业的技术人员也可以搭建自己的曾经是遥不可及的AI系统。
言归正传,先搭建起我们的基础服务。微信小程序端将图片经gzip压缩后传至后台服务器,为了提升图片的识别速度,注意限制图片的大小,nginx和springboot默认最大上传文件大小均为1MB。对用户上传的图片需要做预处理,主要是基于安全性的考虑,根据文件头字节码验证图片类型,修改文件名称并保存到随机临时目录,防止被脚本攻击。如果有足够的存储可以将图片备份到COS或者独立的数据盘,由于我们前期使用第三方API识图,为了节省存储资源可以借助第三方识图存储图片,我们只需要记录下图片存放的url地址即可。接下来就是将用户上传的图片通过API提交给第三方识图系统获取结果,为了防止调用过于频繁被第三方封杀采取了两个对策。一是对接多个第三方识图,将用户的请求随机分配给不同的第三方识图,存在的问题是不同的第三方识图可能识别结果不一致。二是通过代理去访问第三方识图,存在的问题是开源的IP代理池不稳定,后期可能会考虑自己去实现一个可靠的IP代理池。从第三方识图获取的结果形式各异,需要从中解析有价值的信息,然后将结果封装成统一的格式。最后还需要进行清理现场的工作,将之前用户上传的临时文件删除。
上图为相应的UML设计类图,ImageRecognition定义了识图接口需要实现的方法,AbstractImageRecognition实现了图片预处理和清理现场的方法,recognize模版方法定义了完整的识图过程,针对AxxImageRecognition、BxxImageRecognition、CxxImageRecognition不同的第三方识图需要实现不同的上传图像和解析结果的方法,最后通过ImageRecognitionFactory工厂方法定义将会使用哪种第三方识图。
上述实现方案中种种纠结的折衷妥协都源于没有自有识图的困境,后期我们要不断完善物种基础数据,利用TensorFlow持续训练不断提升识别正确率,那么最终提升识别速度应该就是水到渠成的事了,期待以图识图2.0。AI的时代来了,你还在等什么?