以图搜图的实现

nodejs python keras

前言

在过去的三个月中,做了一个比较有意思的项目:ICON 网站。

在这个过程中实现了简单的以图搜图,这里整理下实现流程

以图搜图的实现流程

以图搜图这个服务,简单来说就是用户截一张图,上传给后台,后台返回和图匹配度比较高的 icon 列表。核心功能点是用卷积神经网络实现的,也就是近几年特别火的 tensorflow。听起来很高大上,其实仅仅作为应用的话,我们可以使用它提供的高级 api keras,还是比较好实现的,因为官网有详细的教程,网上有不少的案例可以参考。

图片数据收集流程

什么是 vgg16

要解释 vgg16 有点困难,需要的前置知识有点多,所以在这里简单的描述下它,它其实就是一个深度学习模型,预先内置在 keras 包中,所以你 下载keras 后,用 python 就可以直接引入它了。

如果想了解更多关于 vgg16 的知识,我推荐你看这篇文章: https://www.sohu.com/a/241338315_787107

enter image description here

为什么要使用 vgg16 呢?因为机器学习是建立在海量数据的基础上的,如果我们从头学习的话,将耗费大量计算力和精力。因为有 vgg16 这种预学习模型的存在,我们可以将训练好的数据,运用在我们自定义的数据上。

先把 vgg16 放在一边,接下来要做的,是爬取到所有的图片

生成图片样本

我们内网图标库的接口是 graphql,所以爬取所有 svg 图标,不是一个很难的事情。

graphqlquery 这样写就行了,等个几分钟就可以拿到所有 icon json 数据了。然后我将 数据存在了本地文件 source.json 里面。

enter image description here

拿到 json 数据后,如何转换成图片呢,json 数据的值有一个 source_code 字段,这个字段就是 svg 代码。

enter image description here

之后,将 svg 转为 jpeg 图片,就可以作为样本给 vgg16 使用了。

这里我用了 sharp 库,它可以很方便的将 svg 转为其他格式的图片,并且我调整了图片的大小,固定为 32 px,方便后期的图片匹配。

enter image description here

提取特征值

代码核心来自于 keras 官网,主要的方法就是 model_vgg.predict,提取输入图片路径的特征值。
enter image description here

让我们看看提取的特征值是什么样子吧。

1
2
3
4
5
6
7
8
9
[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 4.25918460e-01 9.74334311e-03
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
4.47806902e-03 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 2.80634430e-03
3.21221575e-02 0.00000000e+00 0.00000000e+00 2.90707089e-02
6.12684526e-02 0.00000000e+00 0.00000000e+00 0.00000000e+00
6.64397283e-03 ...]

提取出来的特征值,其实就是一个1 X n的矩阵。

保存特征值

提取特征值后,需要保存在文件里。

这里用到了 python 的一个包 h5py,你可以把它想像成本地数据库,可以用来存大数组。

创建文件并写数组

enter image description here

遍历图片,提取特征值,写入到 .h5 文件中。(之后读文件,将 w -> r 即可。)

enter image description here

现在我们已经有了所有图片的特征值,接下来要做的就是写以图搜图服务了,先启动一个服务吧。

图片搜索服务流程

起一个 python http 服务

这里使用了 Flask 框架,可以看到它非常快速且简单,当用户 post upload 接口,并带上搜索的图片时,将图片保存在本地文件,并执行搜索逻辑。

enter image description here

搜索方法

当拿到用户的搜索图片时,第一步当然是获取该图片的特征值,和之前一样,使用封装好的提取方法。

queryVec = model.vgg_extract_feat(query)

拿到特征值之后怎么办呢?我们该如何从 h5 文件中,找到与其相似度较高的图片对象呢?
先读取 h5 文件吧。

h5f = h5py.File('models/vgg_featureCNN.h5', 'r')

还记得之前我们说提取的特征值是一个矩阵吗,特征值相似就演变成了矩阵相似,假设我们矩阵

A:[.9,0,.9,0]

试着分别对其他两个不同的矩阵做乘积
[.9,0,.9,0] x [.9,0,.9,.9] = 1.62
[.9,0,.9,0] x [0,.9,0,.9] = 0

事实上,乘积的结果大小,就是匹配度大小。所以前一个矩阵就比后一个矩阵更相似 A(很拗口)

通过 python 的 np 包,可以计算两个矩阵的乘积。

np.dot(mix1, mix2),之后将乘积从大到小排序就可以拿到 特征值匹配度较高的图片了。
enter image description here

以上就是整个以图搜图的实现流程。

通俗的讲一遍整个流程吧

enter image description here

vgg16 想象成一只怪物,它的特异功能就是识别每张图片的特征值,比如这张图片里边有猫,那张图片里面有狗,然后我给它看了 4000+ 多张图片,它把每张图片的特征值保存了下来,当我再给他一张时,它告诉我特征值,然后我用特征值和保存下来的列表做对比,匹配度高的就是我要找的图片。

是不是很简单呢~

参考