图片相似度计算及检索调研

简介: 图片相似度计算和相似图片搜索,是图片识别领域两个常见的应用场景。例如搜索相似商品,和相似的图片,在百度、淘宝中都有应用。在某些业务中,也存在对图片相似度的计算和判断。因此,在这里简单介绍一下相关算法。

背景

   图片相似度计算和相似图片搜索,是图片识别领域两个常见的应用场景。例如搜索相似商品,和相似的图片,在百度、淘宝中都有应用。在某些业务中,也存在对图片相似度的计算和判断。因此,在这里简单介绍一下相关算法。

一 Hash 算法

Hash算法作为大多图片搜索引擎的核心算法,其准确率和效率均很高,本板块将介绍Hash的三种核心算法:aHash、pHash、dHash。

1.1 图像均值哈希算法-aHash

基于均值哈希的算法称为均值哈希算法(Average Hash Algorithm,AHA),此算法是基于比较灰度图每个像素与所有像素点的平均值来实现的,最适用于缩略图,放大图搜索。

步骤:

1.缩放图片:为了保留结构去掉细节,去除大小、横纵比的差异,把图片统一缩放到8*8,共64个像素的图片。

2.转化为灰度图:把缩放后的图片转化为256阶的灰度图。

3.计算平均值: 计算进行灰度处理后图片的所有像素点的平均值。

4.比较像素灰度值:遍历灰度图片每一个像素,如果大于平均值记录为1,否则为0.

5.得到信息指纹:组合64个bit位,顺序随意保持一致性即可。

6.对比指纹:计算两幅图片的指纹,计算汉明距离(从一个指纹到另一个指纹需要变几次),汉明距离越大则说明图片越不一致,反之,汉明距离越小则说明图片越相似,当距离为0时,说明完全相同。(通常认为距离>10 就是两张完全不同的图片)

1.2 图像感知哈希算法-pHash

平均哈希算法过于严格,不够精确,更适合搜索缩略图,为了获得更精确的结果可以选择感知哈希算法,它采用的是DCT(离散余弦变换)来降低频率的方法

感知哈希,全称是Perceptual Hash,是基于像素点级别的一种散列映射方式,基于认知心理学的信息加工理论为基础,提取图像中的各种特征用于生成独特但不是唯一的指纹,即一串简短且可以表示图像可被人类感知的特征内容的感知数字序列,且这些指纹具有可比性。

步骤:

1.缩小图片:32 * 32是一个较好的大小,这样方便DCT计算

2.转化为灰度图:把缩放后的图片转化为256阶的灰度图。(具体算法见平均哈希算法步骤)

3.计算DCT:DCT把图片分离成分率的集合

4.缩小DCT:DCT是32*32,保留左上角的8*8,这些代表的图片的最低频率

5.计算平均值:计算缩小DCT后的所有像素点的平均值。

6.进一步减小DCT:大于平均值记录为1,反之记录为0.

7.得到信息指纹:组合64个信息位,顺序随意保持一致性即可。

8.对比指纹:计算两幅图片的指纹,计算汉明距离(从一个指纹到另一个指纹需要变几次),汉明距离越大则说明图片越不一致,反之,汉明距离越小则说明图片越相似,当距离为0时,说明完全相同。(通常认为距离>10 就是两张完全不同的图片)

1.3 图像差异哈希算法-dHash

图像差异哈希,全称是Difference Hash,是基于像素点级别的一种散列映射方式。图像差异哈希是通过逐像素比对相邻像素像素值的差异,即逐像素得到当前像素与右邻像素的差值,得到一个图像差异矩阵,通过该矩阵映射生成哈希值。这个逐像素得到的图像差异矩阵的比原像素矩阵少了一列,即宽度比原像素矩阵少了1,高度不变。

相比pHash,dHash的速度要快的多,相比aHash,dHash在效率几乎相同的情况下的效果要更好,它是基于渐变实现的。

步骤:

1.缩小图片:收缩到9*8的大小,一遍它有72的像素点

2.转化为灰度图:把缩放后的图片转化为256阶的灰度图。(具体算法见平均哈希算法步骤)

3.计算差异值,获得最后哈希值(与aHash主要区别处)。dHash算法工作在相邻像素之间。比较每行左右两个像素,如果左边的像素比右边的更亮(左边像素值大于右边像素值),则记录为1,否则为0。因为每行有9个像素,左右两个依次比较可得出8个值,所以8行像素共可以得出64个值,因此此时哈希值为长度是64的0-1序列。

4.图片配对,计算汉明距离。

汉明距离

汉明距离是以理查德·卫斯里·汉明的名字命名的。在信息论中,两个等长字符串之间的汉明距离是两个字符串对应位置的不同字符的个数。换句话说,它就是将一个字符串变换成另外一个字符串所需要替换的字符个数。例如:

1011101 与 1001001 之间的汉明距离是 2。

2143896 与 2233796 之间的汉明距离是 3。

"toned" 与 "roses" 之间的汉明距离是 3。

二 算法比较

图像均值哈希本质上是对颜色的比较,图像感知哈希由于做了 DCT 操作,本质上是对频率的比较,图像差异哈希本质上是基于渐变的感知哈希算法。

下面是对比的素材:

下面是对比的结果:

三 环境搭建与算法实现

3.1 三种hash算法的实现与环境搭建

语言:python, 版本:python2.7 / python3

module依赖:scikit-image , opencv-python

依赖安装:

sudo pip3 install --upgrade setuptoolssudo pip3 install scikit-image -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com//后面为镜像源加速
pip install --default-timeout=1000 opencv-python
//使用清华源安装
pip3 install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple

3.2 aHash、dHash、pHash的实现示例

3.2.1 aHash

# -*- coding: utf-8 -*-
from skimage import transform
import cv2
#aHash方法计算图片的指纹数据
img=cv2.imread('/Users/develop/imageanalysis/RPC框架.png')#读入图片
length = 8
height = 8
sum = 0.0
k = 0
grey = []
# 修改图像大小
dst=transform.resize(img, (length, height))
for i in range(length):
    for j in range(height):
        (b,g,r) = dst[i,j]
        # 计算灰度值
        grey.append(r*0.3+g*0.59+b*0.11)#浮点灰度值计算
        sum+=grey[k]
        k=k+1
average = sum/(length*height)#算出平均的灰度数据
fingerprint = []
for i in range(length*height):
    if grey[i] > average:
        fingerprint.append(1)#如果灰度数据大于平均值,填入元素1,否则填入元素0
    else:
        fingerprint.append(0)
print(fingerprint)

3.2.2 dHash

# -*- coding: utf-8 -*-
from skimage import transform,data
import matplotlib.pyplot as plt
from skimage import io
import cv2
img=cv2.imread('/Users/develop/imageanalysis/RPC框架.png')#读入图片
length = 9
height = 8
sum = 0.0
k = 0
grey = []
dst=transform.resize(img, (length, height))
#灰度图转化
for i in range(length):
    for j in range(height):
        (b,g,r) = dst[i,j]
        grey.append(r*0.3+g*0.59+b*0.11)#浮点灰度值计算
        sum+=grey[k]
        k=k+1
# 获取每行的差值,为64位
differ = []
for i in range(length-1):#i 8
    for j in range(height):#j 8
        differ.append(grey[j*8+i+1]-grey[j*8+i])
#获取01值
fingerprint = []
for i in range((length-1)*height):#8*8
    if differ[i] > 0:
        fingerprint.append(1)
    else:
        fingerprint.append(0)
print(fingerprint)

3.2.3 pHash

# -*- coding: utf-8 -*-
import cv2
from skimage import transform
import numpy as np
#利用phash计算图像指纹
img=cv2.imread('/Users/develop/imageanalysis/RPC框架.png')#读入图片
length = 32
s_length = 8
dst=transform.resize(img, (length, length))
#print(type(dst))
#all 代表全图,建议32*32
matrix_all_grey = [[0 for i in range(length)] for i in range(length)]
#small 代表最低频率,8*8大小
matrix_small_grey = [[0 for i in range(s_length)] for i in range(s_length)]
# 灰度图转化
k = 0
for i in range(length):
    for j in range(length):
        (b,g,r) = dst[i,j]
        matrix_all_grey[i][j] = ( b + g + r )/3
# 缩小
fft_matrix_grey = np.fft.fft(matrix_all_grey)
for i in range(s_length):
    for j in range(s_length):
        matrix_small_grey[i][j] = fft_matrix_grey[i][j]
# 计算平均
sum_pixel = 0
for i in range(s_length):
    for j in range(s_length):
        sum_pixel += matrix_small_grey[i][j]
average = sum_pixel / (s_length*s_length)
bite = []
#赋予01值
for i in range(s_length):
    for j in range(s_length):
        if matrix_small_grey[i][j] > average :
            bite.append(1)
        else:
            bite.append(0)
print(bite)

3.3 高效对比检索

   通过上面的几种hash算法,我们可以得到一系列图片的hash值。接下来,如果需要对比去除重复图片,或者要检索,怎样才能加快查询速度呢?

   暴力的遍历显然是不太靠谱的,少量图片还好,当达到百万、千万、甚至亿级十亿级的图片数量时,O(n)的复杂度显然无法保障查询速度。

   可以考虑的是一种内存换速度的方式,64位的的hash值,分为八组,每组八位。建立八个dict,每个dict代表一组,以每组的值作为key,value是一个list,存放key相同的hash值。查找的时候,把hash值分成八个,分别在八个map里边查找,如果有key相同的,取出key相同的所有hash值进行遍历。

示例代码:

split_count = 8  # 每个64位的phash值分为八段,每段8位
def split(key, split_count):
    pre_length = 64 / split_count
    return [key[i * pre_length: (i + 1) * pre_length] for i in range(split_count)]
class ImageManager(object):
    def __init__(self):
        self.phash = pHash() # pHash类
        self.phash_cache = [defaultdict(list) for i in range(split_count)] #
        self.init_phash_map()
    def init_phash_map(self):
        #把所有的phash存在sqlite里边,这边取出所有的Image
        for image in Image.select():
            self.add_to_image_cache(image)
    def add_to_image_cache(self, image):
        # 将hash值分割为8段
        key_split = split(bin(int(image.phash))[2:].rjust(64, '0'), split_count)
        for index, k in enumerate(key_split):
            self.phash_cache[index][k].append(image)
    def has_same(self, ori_image):
        phash = ori_image.phash
        key_split = split(bin(int(phash))[2:].rjust(64, '0'), split_count)
        result = set()
        for index, k in enumerate(key_split):
            if k in self.phash_cache[index]:
                for image in self.phash_cache[index][k]:
                    distance = self.distance(int(phash), int(image.phash))
                    if distance < 5 and ori_image.key != image.key:
                        result.add(image)
        if result:
            return True,list(result)
        return False,[]

参考文章

相似图片搜索算法介绍

图像处理 图像相似算法aHash、dHash、pHash解析与对比

最近邻搜索

较大规模图片 使用phash去重

相关文章
|
存储 人工智能 测试技术
图像相似度比较之 CLIP or DINOv2
图像相似度比较之 CLIP or DINOv2
|
9月前
|
机器学习/深度学习 存储 算法
如何判断两张图片的相似度?原来图片对比也可以如此简单!
本文介绍了图片对比技术在多个场景中的应用,如图片去重、内容审核、版权维权及相似图片搜索,并详细解析了两种主流的图片对比方法。第一种是**MD5指纹对比**,适合精确匹配完全相同的图片,具有速度快、简单易用的特点,但对稍作修改的图片无能为力。第二种是**图像哈希对比**,包括平均哈希、感知哈希等算法,能够判断图片的相似程度,适用于处理缩放、旋转或亮度调整后的图片,但在语义相似性上仍有局限。最后提到,随着机器学习和深度神经网络的发展,图片相似度判断技术将有更多可能性,值得进一步探索。
3089 6
如何判断两张图片的相似度?原来图片对比也可以如此简单!
|
计算机视觉
微信开源二维码检测识别-实时检测识别-opencv-Python
微信开源二维码检测识别-实时检测识别-opencv-Python
|
4月前
|
搜索推荐 API 开发者
1688图片搜索API | 上传图片秒找同款 | 相似商品精准推荐
1688图片搜索API是阿里巴巴B2B平台提供的图像识别服务,支持通过上传商品图片在海量商品库中快速查找同款或相似商品。适用于电商比价、批量搜索及系统集成,提升采购效率。建议使用清晰图片并优化分类与分页设置,以提高搜索准确率和性能表现。
|
编解码 计算机视觉 索引
OpenCV使用单目标匹配从图像中选择最佳的匹配结果及查找重复图像实战(附Python源码)
OpenCV使用单目标匹配从图像中选择最佳的匹配结果及查找重复图像实战(附Python源码)
1295 0
|
8月前
|
人工智能 自然语言处理 Serverless
阿里云 Milvus 轻松实现文搜图&图搜图
阿里云Milvus是一款高性能、易扩展的云原生向量检索引擎,适用于推荐系统、图像检索、自然语言处理等AI场景。它支持海量向量数据实时召回,并提供直观API和多语言SDK。结合阿里云百炼模型服务与函数计算,可轻松实现文搜图、图搜图等多模态检索应用,助力企业高效开发智能搜索系统。
|
定位技术 API 数据安全/隐私保护
QWEN-VL Plus 使用小记
近期尝试使用Qwen VL Plus模型处理图像识别任务,以GIS专业背景选择了一张街景图片进行测试。体验上,API调用流畅,环境配置简单,且成本低廉,免费额度可支持约1,000张图片的处理。不过,模型在某些情况下会产生幻觉,如对仅含Google水印的街景图片错误地描述存在地名信息。此外,其文本描述风格多变,从轻松愉快到沉稳不一,有时甚至会拒绝回答。
925 5
|
机器学习/深度学习 并行计算 数据可视化
目标分类笔记(二): 利用PaddleClas的框架来完成多标签分类任务(从数据准备到训练测试部署的完整流程)
这篇文章介绍了如何使用PaddleClas框架完成多标签分类任务,包括数据准备、环境搭建、模型训练、预测、评估等完整流程。
1274 0
目标分类笔记(二): 利用PaddleClas的框架来完成多标签分类任务(从数据准备到训练测试部署的完整流程)
|
机器学习/深度学习 安全 网络协议
网络安全公开数据集Maple-IDS,恶意流量检测数据集开放使用!
【8月更文挑战第29天】Maple-IDS 是东北林业大学网络安全实验室发布的网络入侵检测评估数据集,旨在提升异常基础入侵检测和预防系统的性能与可靠性。该数据集包含多种最新攻击类型,如 DDoS 和 N-day 漏洞,覆盖多种服务和网络行为,兼容 CIC-IDS 格式,便于直接使用或生成 csv 文件,适用于多种现代协议。
1404 1

热门文章

最新文章