用一张图像,从图像数据库中快速找到相似或者相同的图像,这就是以图搜图。

1. VP-Tree结构

1.1 概念

VP-Tree(Vantage Point Tree)在1991年被Uhlmann作者提出,它是一种基于距离的度量空间上的索引结构,是一颗度量二叉树。其基本思想是将 二分查找 用于只有距离信息的多维度量空间中。也就是采用特征空间的目标点集的点与 制高点(Vantage Point) 之间的距离信息对特征空间进行划分。

  • VP-Tree构造时间复杂度:O(nlogn)
  • VP-Tree搜索在理想情况下的复杂度:O(logn)

1.2 数据结构

假设有一个数据集S={S1,S2,… ,Sn-1,Sn},度量空间距离函数D(Si,Sj):

  • 若|S|=0,构造空树,返回;
  • 若|S|不为0,从S中随机选取一个对象Sc,把这个Sc看作制高点(Vantage Point),设m是S中所有对象与Sc的距离中值,小于m的数据点分给左子树,大于m的数据点分给右子树:
    Sleft={Si|D(Si, Sc) ≤ m, Si∈S,Si ≠ Sc }
    Sright={Sj|D(Sj, Sc) ≥ m, Sj∈S}
  • 递归构造VP-Tree(即递归地建立左子树和右子树)

1.3搜索算法

对于一个查询数据对象Q和距离范围r(近邻查询),Ac为当前制高点,距离中值m,搜索算法为:

  1. 当D(Q, Ac) ≤ r, 则返回Ac
  2. 当D(Q, Ac) + r ≥ m,递归地搜索右子树 Sright(球外区域)
  3. 当D(Q, Ac) - r ≤ m,递归地搜索左子树 Sleft(球内区域)

2.图像哈希算法

在判断图片是不是同一张图片,最简单的方法是用加密哈希来进行判断是否相同,如:MD5, SHA-1等算法。但这存在很大的缺点,如果同一张图像被缩放或者颜色变了一点,产生MD5值是完全不同的,这就无法判断相似图片。比较好的解决方案是采用感知哈希算法,它包括:aHash、pHash、dHash。
他们的区别:

  1. 平均哈希aHash:速度比较快,但不精确
  2. 感知哈希pHash:精确度比较高,但速度较差。
  3. 差异哈希dHash:精确度较高,且速度也快
差异值哈希dHash算法步骤:
  1. 缩小图像:将图像调整为固定尺寸N + 1 xN。通常N = 8,即9X8大小,9作为行数,方便计算图像中相邻像素之间的差异(“差异哈希”)
  2. 转化为灰度图:把缩放后的图片转化为256阶的灰度图。因为彩色的图片是由 RGB 三原色构成,每个像素点是一个由这三个颜色组成的一个 list 。而 RGB 三个颜色中每个颜色值都是用 8 个比特来表示,大小范围是 0 ~ 255(28 - 1),就一共有 256 * 256 * 256 种颜色。并且作为一个像素类似于这样的数值:[253 255 255] 是不利于简单比较的,肉眼看着类似的颜色,但是它的三个颜色分布可能相差很多。所以将它灰度化,用 256 个不同的灰色表示现有的图片。由于现在用一种灰色表示三种颜色,原来每个像素是一个 list 现在就降维成一个数值,这样数值的大小还是比较容易比较的。
  3. 计算差异值:每行有9个像素,每列有8个像素。然后,我们可以计算相邻列像素之间的差异,得出8个差异。每行9个像素之间产生了8个不同的差异,得到64个值。
  4. 生成哈希值:对差异值进行处理,若为正数或0,则记得为1;若为负数,记为0。将64个结果结合在一起就得到一个哈希值(每张图像的64个值组合顺序要一致),这就是图像的“指纹”。

3.汉明距离(Hamming Distance)

汉明距离表示两个(相同长度)字对应位不同的数量,我们以d(x,y)表示两个字x,y之间的汉明距离。对两个字符串进行异或运算,并统计结果为1的个数,那么这个数就是汉明距离。
例如:
A为 10101001
B为 10110001
可以看出A和B有两位的不同,那么汉明距离就是2

4.图像搜索引擎

假设有3,000,000张图像的图像库。这3,000,000张图像中的每张图像都计算了图像哈希值。假设每次汉明距离比较花费0.00001秒,总共有3,000,000张图像,它也将用30秒来完成搜索。这对于任何搜索引擎都是太慢了。图像引擎需要查询速度很快的,这就用到了上面提到的VP-Tree数据结构。

图像搜索引擎主要有两部分组成:索引和查询。

  • 索引:
  • 查询:

这里图像库有3万9千多张图。
构建VP-Tree代码

from imutils import paths
import pickle
import vptree
import numpy as np
import cv2# 差异哈希函数
def dhash(image, hashSize=8):# 转为灰度图gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 缩放resizeImg = cv2.resize(gray, (hashSize + 1, hashSize))# 计算差异值diff_value = resizeImg[:, 1:] > resizeImg[:, :-1]return sum([2 ** i for (i, v) in enumerate(diff_value.flatten()) if v])def convert_hash(hash_value):# 对差异值处理,返回64位浮点数值return int(np.array(hash_value, dtype="float64"))def hamming(a_dist, b_dist):# 计算汉明距离return bin(int(a_dist) ^ int(b_dist)).count("1")hashes = {}# 换成自己的图像库文件路径
path = "E:\\yu\\work\\python_work\\input\\image_data"
imagePaths = list(paths.list_images(path))
for (i, imagePath) in enumerate(imagePaths):print("加载处理图像: {}/{}".format(i + 1,len(imagePaths)))image = cv2.imread(imagePath)# 计算hash_value = dhash(image)hash_value = convert_hash(hash_value)# 添加进hashes字典h = hashes.get(hash_value, [])h.append(imagePath)hashes[hash_value] = h# 建vp树
print("构建 VP-Tree...")
points = list(hashes.keys())
tree = vptree.VPTree(points, hamming)# 保存
print("保存 VP-Tree...")
f = open("E:\\yu\\work\\python_work\\output\\vptree.pickle", "wb")
f.write(pickle.dumps(tree))
f.close()# 保存哈希值
print("保存 hashes...")
f = open("E:\\yu\\work\\python_work\\output\\hashes.pickle", "wb")
f.write(pickle.dumps(hashes))
f.close()

图有点多,需要等待两分钟

搜索代码

import pickle
import time
import numpy as np
import cv2# 差异哈希函数
def dhash(image, hashSize=8):# 转为灰度图gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 缩放resizeImg = cv2.resize(gray, (hashSize + 1, hashSize))# 计算差异值diff_value = resizeImg[:, 1:] > resizeImg[:, :-1]return sum([2 ** i for (i, v) in enumerate(diff_value.flatten()) if v])def convert_hash(hash_value):# 对差异值处理,返回64位浮点数值return int(np.array(hash_value, dtype="float64"))def hamming(a, b):# compute and return the Hamming distance between the integersreturn bin(int(a) ^ int(b)).count("1")# 加载VP和哈希文件
tree = pickle.loads(open("E:\\yu\\work\\python_work\\output\\vptree.pickle", "rb").read())
hashes = pickle.loads(open("E:\\yu\\work\\python_work\\output\\hashes.pickle", "rb").read())
print("加载 VP-Tree and hashes...")# 待搜索图片路径
image = cv2.imread("E:\\yu\\work\\python_work\\input\\image_data\\6.jpg")if(len(image)==None):print("加载图片失败 ...")cv2.namedWindow("test_search",cv2.WINDOW_NORMAL)
cv2.resizeWindow("test_search",512,384)
cv2.imshow("test_search", image)# 计算哈希值
search_Hash = dhash(image)
search_Hash = convert_hash(search_Hash)# 获取结果
distance = 10
print("搜索中...")
start = time.time()
results = tree.get_all_in_range(search_Hash, distance)
results = sorted(results)
# print("results:",results)
end = time.time()
print("消耗时间 {} s".format(end - start))# 结果处理
for (d, h) in results:# 用哈希值获取数据集中的所有相似图像resultPaths = hashes.get(h, [])print("检索到 {} 张, 汉明距离: {}, 哈希值: {}".format(len(resultPaths), d, h))# 显示结果for resultPath in resultPaths:result = cv2.imread(resultPath)cv2.namedWindow("Result", cv2.WINDOW_NORMAL)cv2.resizeWindow("Result", 512, 384)cv2.imshow("Result", result)cv2.waitKey(0)

拿张图举个例子:

测试1:

拿原图比较,运行一下搜索代码:


搜索时间在0.12s,汉明距离为零表示是两张相同的图像。

测试2:

把图亮度,饱和度调整一下:


那修改后的图再次搜索一下,结果:


可以看到,距离变为了1。

测试3:

把图再修改一下:

运行结果:


完~

Reference:
https://blog.csdn.net/mandycool/article/details/8492819
https://blog.csdn.net/Leo_whj/article/details/80923166

图像搜索引擎搭建:利用VP-Tree实现以图搜图相关推荐

  1. 7 招教你轻松搭建以图搜图系统!

    作者 | 小龙 责编 | 胡巍巍 当您听到"以图搜图"时,是否首先想到了百度.Google 等搜索引擎的以图搜图功能呢?事实上,您完全可以搭建一个属于自己的以图搜图系统:自己建立图 ...

  2. python+milvus实现一个以图搜图系统

    目录 引言 说明 准备数据 训练数据 安装minlvus(docker-compose方式) python集成milvus+towhee python后端启动方式 启动前端 查询数据 引言 当您听到& ...

  3. 搭建自己的以图搜图系统(二):深入优化搭建生产级别的图搜系统

    概述 本文是"搭建自己的以图搜图系统"系列的第二篇,在第一篇内容中我们了解了如何利用"机器学习框架 Towhee ¹"和"向量数据库 Milvus ² ...

  4. Torch、Java、Milvus快速搭建以图搜图系统

    Torch.Java.Milvus快速搭建以图搜图系统 1 原理概述 以图搜图大致原理(口水话版) 以图搜图,即通过一张图片去匹配数据库中的图片,找到最相似的N张图.在我们普通的搜索系统中,文字匹配的 ...

  5. 推荐系统工程篇之搭建以图搜图服务

    基于内容的召回在推荐系统中是比较常见的召回策略,常见有基于用户或物品的标签召回或者基于用户的年龄,地域等召回,一般该策略的实现是基于开源软件 Elasticseach 实现的.虽然召回的结果都比较合理 ...

  6. 11款相似图片搜索引擎推荐,以图搜图将不再是难事

    你想凭着一张现有图片找出它的原始图片,或者是凭着一张小的缩略图找出原始大图吗? 下面的十一款搜索引擎可以帮你实现,以图找图,以图搜图,以图片搜索相似的图片. 1.http://tineye.com/ ...

  7. 使用elasticSearch搭建本地以图搜图服务

    使用elasticSearch的向量检索实现以图搜图 文章目录 使用elasticSearch的向量检索实现以图搜图 前言 快速开始 安装elasticsearch和kibana 创建索引 下载项目 ...

  8. 工程篇之搭建以图搜图服务

    基于内容的召回在推荐系统中是比较常见的召回策略,常见有基于用户或物品的标签召回或者基于用户的年龄,地域等召回,一般该策略的实现是基于开源软件 Elasticseach 实现的.虽然召回的结果都比较合理 ...

  9. 拍立淘-以图搜图中的图像搜索算法

    摘要:移动端的以图搜图是一代又一代的图像人,搜索人的梦想.从90年代开始,学术界,工业界做了很多的努力和尝 试.拍立淘-以图搜图,从14年正式立项开始,通过算法/工程/产品的不断打磨,以及兄弟部门的紧 ...

最新文章

  1. 网站错误记录:A transport-level error has occurred when sending the request to the server.
  2. linux系统安全加固脚本
  3. 如何向学妹解释在地址栏中输入网址后发生了什么?
  4. c 语言输入n个数求和,c++---天梯赛---N个数求和
  5. PHP 服务器变量 $_SERVER(转)
  6. 微信小程序访问豆瓣电影api400错误解决方法
  7. 怪物猎人物语稀有9星_怪物猎人崛起武器怎么锻造 武器锻造机制介绍
  8. Oracle服务的作用
  9. 聊一聊字节跳动的面试
  10. Selenium(二)——webdriver 开始
  11. 垃圾处理设备远程调试远程运维方案
  12. R语言meta包的预后meta分析复现
  13. dx逆向建模步骤_产品温度的逆向建模的系统和方法与流程
  14. 戴尔计算机无法安装Win10,dell电脑安装win10 识别不了硬盘
  15. on1 photo raw 2020中文版(RAW图像处理) v14.5.1.9231绿色便携版
  16. DeepMind黄士杰:深度学习有创造性,正参与星际2项目
  17. 蘑菇街2016校园招聘之编程题解析-技术类
  18. 槃星—第1天任务—植物大战僵尸游戏数据修改(Hex Editor Neo)
  19. subplots用法详解
  20. 【Qt】按键事件:Alt+F4

热门文章

  1. Reflex WMS入门系列十八:如何看年终盘点的Inventory report数据?
  2. Chrome Console 小技巧之 01 如何启动XHR监控网络请求
  3. 免费影像数据下载网站汇总——2010年7月28[转自ESRI中国]
  4. 计算机湖北高校排名,湖北高校排名,985、211、省属高校,各有千秋
  5. matlab产生时间数组以月为单位_MATLAB的时间与日期
  6. OpenGL画三角形 圆 五角星 菱形
  7. 第三方物流学习(六)
  8. cookie使用注意问题【cookie学习笔记】
  9. ubuntu14.04下设置静态IP
  10. 赵小楼《天道》《遥远的救世主》深度解析(10)肖亚文对丁元英有没有动过心思?