本文转自:

相似图片搜索的原理

相似图片搜索的原理(二)

http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html

http://www.ruanyifeng.com/blog/2011/07/principle_of_similar_image_search.html

http://blog.sina.com.cn/s/blog_b27f71160101gp9c.html

http://blog.csdn.net/luoweifu/article/details/8220992

http://blog.csdn.net/zmazon/article/details/8618775

http://blog.sina.com.cn/s/blog_b27f71160101gpep.html

计算机怎么知道两张图片相似呢?

根据Neal Krawetz博士的解释,原理非常简单易懂。我们可以用一个快速算法,就达到基本的效果。

这里的关键技术叫做"感知哈希算法"(Perceptual hash algorithm),它的作用是对每张图片生成一个"指纹"(fingerprint)字符串,然后比较不同图片的指纹。结果越接近,就说明图片越相似。

下面是一个最简单的实现:

一、平均哈希算法(aHash)


此算法是基于比较灰度图每个像素与平均值来实现的。

第一步,缩小尺寸。

将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。

 

第二步,简化色彩。

将8*8的小图片转换成灰度图像,将64个像素的颜色(red,green,blue)转换成一种颜色(黑白灰度)。

第三步,计算平均值。

计算所有64个像素的灰度平均值。

第四步,比较像素的灰度。

将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。

第五步,计算哈希值。

将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。

 =  = 8f373714acfcf4d0

得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算"汉明距离"(Hamming distance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。

步骤说明:

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

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

附上灰度图相关算法(R = red, G = green, B = blue)

1.浮点算法:Gray=R*0.3+G*0.59+B*0.11
2.整数方法:Gray=(R*30+G*59+B*11)/100
3.移位方法:Gray =(R*76+G*151+B*28)>>8;
4.平均值法:Gray=(R+G+B)/3;
5.仅取绿色:Gray=G;

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

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

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

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

算法实现

关于均值哈希算法的实现,请参考:Google 以图搜图 - 相似图片搜索原理 - Java实现http://blog.csdn.net/luoweifu/article/details/7733030

下面给出matlab实现平均哈希算法(aHash)

%http://blog.sina.com.cn/s/blog_b27f71160101gp9c.html
%输入两幅图片,返回值为它们的为汉明距离。
%相似图片搜索原理:平均哈希算法
%对两幅图分别作如下处理:
%1:将两副256等级的灰度图像转化成8x8大小的64等级的灰度图像
%2:求全局灰度平均值
%3:逐次将灰度值与平均灰度值比较,大于等于的置为1,否则置为0
%4:将0、1序列看做8个字节(统一顺序)
%5:比较两幅图的数据位,如果不同的数据为不超过5位,则非常相似,若超过10为则认为两幅图无关
function v=tineyesearch_ahash(picture1,picture2)
t1=imresize(picture1,[8 8],'bicubic'); %图片放缩到固定大小
t2=imresize(picture2,[8 8],'bicubic'); %图片放缩到固定大小
t1=round(t1/4);
t2=round(t2/4);
mem1=round(sum(sum(t1))/64);
mem2=round(sum(sum(t2))/64);
for i=1:8for j=1:8if t1(i,j)>=mem1t1(i,j)=1;elset1(i,j)=0;endif t2(i,j)>=mem2t2(i,j)=1;elset2(i,j)=0;endend
end
h=abs(t1-t2);
v=sum(sum(h));
%http://blog.sina.com.cn/s/blog_b27f71160101gp9c.html
clear;
close all;
clc;
srcDir=uigetdir('Choose source directory.');
cd(srcDir);
allnames=struct2cell(dir('*.jpg'));
[k,len]=size(allnames);
FinalResult = {};for i=1:lenname=allnames{1,i};
picture1 = imread(name);
picture2 = imread('006.jpg');
v=tineyesearch_ahash(picture1,picture2);
FinalResult{i,1} = char('006.jgp');
FinalResult{i,2} = name;
FinalResult{i,3} = v;
endfigure('NumberTitle', 'off', 'Name', '统计表');
columnname =   {'ReferenceImage','TestImage', 'SimilarScore'};     %各列的名称
% columnformat = {'numeric', 'bank', 'numeric'};  %各列的数据类型
columneditable =  [false true true];                %各列是否是可编辑的,true是可以编辑,false是不可编辑
t = uitable('Units','normalized','Position',...[0.1 0.1 0.9 0.9], 'Data', FinalResult,...'ColumnName', columnname,...'ColumnEditable', columneditable);

具体的代码实现,可以参见Wote用python语言写的imgHash.py。代码很短,只有53行。使用的时候,第一个参数是基准图片,第二个参数是用来比较的其他图片所在的目录,返回结果是两张图片之间不相同的数据位数量(汉明距离)。

这种算法的优点是简单快速,不受图片大小缩放的影响,缺点是图片的内容不能变更。如果在图片上加几个文字,它就认不出来了。所以,它的最佳用途是根据缩略图,找出原图。

实际应用中,往往采用更强大的pHash算法和SIFT算法,它们能够识别图片的变形。只要变形程度不超过25%,它们就能匹配原图。这些算法虽然更复杂,但是原理与上面的简便算法是一样的,就是先将图片转化成Hash字符串,然后再进行比较。

如果图片放大或缩小,或改变纵横比,结果值也不会改变。增加或减少亮度或对比度,或改变颜色,对hash值都不会太大的影响。最大的优点:计算速度快!

如果你想比较两张图片,为每张图片构造hash值并且计算不同位的个数。(汉明距离)如果这个值为0,则表示这两张图片非常相似,如果汉明距离小于5,则表示有些不同,但比较相近,如果汉明距离大于10则表明完全不同的图片。


二、效果更佳的感知哈希算法pHash

虽然均值哈希更简单且更快速,但是在比较上更死板、僵硬。它可能产生错误的漏洞,如果有一个伽马校正或颜色直方图被用于到图像。这是因为颜色沿着一个非线性标尺 - 改变其中“平均值”的位置,并因此改变哪些高于/低于平均值的比特数。

一个更健壮的算法叫pHash, pHash的做法是将均值的方法发挥到极致。使用离散余弦变换(DCT)降低频率。

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

1.缩小尺寸

pHash以小图片开始,但图片大于8*8,32*32是最好的。这样做的目的是简化了DCT的计算,而不是减小频率。

2.简化色彩

将图片转化成灰度图像,进一步简化计算量。

3.计算DCT

DCT是把图片分解频率聚集和梯状形,虽然JPEG使用8*8的DCT变换,在这里使用32*32的DCT变换。

4.缩小DCT

虽然DCT的结果是32*32大小的矩阵,但我们只要保留左上角的8*8的矩阵,这部分呈现了图片中的最低频率。

5.计算平均值

如同均值哈希一样,计算DCT的均值,

6.进一步减小DCT

这是最主要的一步,根据8*8的DCT矩阵,设置0或1的64位的hash值,大于等于DCT均值的设为”1”,小于DCT均值的设为“0”。结果并不能告诉我们真实性的低频率,只能粗略地告诉我们相对于平均值频率的相对比例。只要图片的整体结构保持不变,hash结果值就不变。能够避免伽马校正或颜色直方图被调整带来的影响。

7.构造hash值

将64bit设置成64位的长整型,组合的次序并不重要,只要保证所有图片都采用同样次序就行了。将32*32的DCT转换成32*32的图像。

与均值哈希一样,pHash同样可以用汉明距离来进行比较。(只需要比较每一位对应的位置并算计不同的位的个数)

步骤说明:

步骤:

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 就是两张完全不同的图片)

使用matlab实现 PHash 算法

clear;
close all;
clc;
% read image
I = imread('cameraman.tif');% cosine transform and reduction
d = dct2(I);
d = d(1:8,1:8);% compute average
a = mean(mean(d));% set bits, here unclear whether > or >= shall be used
b = d > a;
% maybe convert to string:
string = num2str(b(:)');

同类中的最佳算法?

自从我做了大量关于数码照片取证和巨幅图片的收集工作之后,我需要一种方法来搜索图片,所以,我用了一些不同的感知哈希算法做一个图片搜索工具,根据我并不很科学但长期使用的经验来看,我发现均值哈希比pHash显著地要快。如果你找一些明确的东西,均值Hash是一个极好的算法,例如,我有一张图片的小缩略图,并且我知道它的大图存在于一个容器的某个地方,均值哈希能算法快速地找到它。然而,如果图片有些修改,如过都添加了一些内容或头部叠加在一起,均值哈希就无法处理,虽然pHash比较慢,但它能很好地容忍一些小的变型(变型度小于25%的图片)。

其次,如果,你运行的服务器像TinEye这样,你就可以不用每次都计算pHash值,我确信它们肯定之前就把pHash值保存在数据库中,核心的比较系统非常快,所以只需花费一次计算的时间,并且几秒之内能进行成千上百次的比较,非常有实用价值。

改进

有许多感知哈希算法的变形能改进它的识别率,例如,在减小尺寸之前可以被剪裁,通过这种方法,主体部分周围额外的空白区域不会产生不同。也可以对图片进行分割,例如,你有一个人脸识别算法,然后你需要计算每张脸的hash值,可以跟踪一般性的着色(例如,她的头发比蓝色或绿色更红,而背景比黑色更接近白色)或线的相对位置。

如果你能比较图片,那么你就可以做一些很酷的事情。例如, 你可以在GazoPa搜索引擎拖动图片,和TinEye一样,我并不知道GazoPa工作的细节,然而它似乎用的是感知哈希算法的变形,由于哈希把所有东西降低到最低频率,我三个人物线条画的素描可以和其它的图片进行比较——如匹配含有三个人的照片。

差异哈希算法dHash

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

步骤:

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

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

3.计算差异值:dHash算法工作在相邻像素之间,这样每行9个像素之间产生了8个不同的差异,一共8行,则产生了64个差异值

4.获得指纹:如果左边的像素比右边的更亮,则记录为1,否则为0.

四、直方图相似度


每张图片都可以生成其灰度图像直方图(histogram)。如果两张图片的直方图很接近,就可以认为它们很相似。

     因此,此处我们利用两幅图像的直方图来进行相似度的比较。原理较为简单,具体算法如下:
1、获得输入灰度图像的直方图分布;
2、将直方图划分为64个区,每个区为连续的4个灰度等级;
3、对每个区的4个值进行求和运算,得到1个数据,如此,会得到64个数据,即为该幅图像的一个向量(指纹);
4、根据步骤【1、2、3】,我们将输入的两幅图像转化为了2个向量,记为A、B;
5、计算两个向量的相似度,可以用皮尔逊相关系数或者余弦相似度计算,这里我们采用【余弦相似度】;
下面就顺便介绍一下余弦相似度的概念及用法:
      对于两个向量,我们可以把它们想象成空间中的两条线段,都是从原点([0, 0, ...])出发,指向不同的方向。两条线段之间形成一个夹角,如果夹角为0度,意味着方向相同、线段重合;如果夹角为90度,意味着形成直角,方向完全不相似;如果夹角为180度,意味着方向正好相反。因此,我们可以通过夹角的大小,来判断向量的相似程度。夹角越小,就代表越相似。

以二维空间为例,上图的a和b是两个向量,我们要计算它们的夹角θ。余弦定理告诉我们,可以用下面的公式求得:

假定a向量是[x1, y1],b向量是[x2, y2],那么可以将余弦定理改写成下面的形式:

数学家已经证明,余弦的这种计算方法对n维向量也成立。假定A和B是两个n维向量,A是 [A1, A2, ..., An] ,B是 [B1, B2, ..., Bn] ,则A与B的夹角θ的余弦等于:

使用这个公式,我们就可以得到,句子A与句子B的夹角的余弦。

余弦值越接近1,就表明夹角越接近0度,也就是两个向量越相似,这就叫"余弦相似性"。

6、得到两个向量的夹角之后,我们就可以通过角度的大小来判别它们的相似程度。

7、至此,我们就完成了两幅图像的相似度计算,因此,可以通过此算法来寻找相似的图像。

下面给出matlab实现直方图分布相似度

%相似图像搜索:利用直方图分布相似度
%1:获得输入两幅图片的直方图分布
%2:将直方图依次划分为64个区,即每个区有4个灰度等级
%3:分别将各自的64个区生成64个元素,即一个向量(图像指纹)
%4:计算两个向量的余弦相似度
%5:判断,若相似度
function v=tineyesearch_hist(picture1,picture2)
t1=picture1;
[a1,b1]=size(t1);
t2=picture2;
t2=imresize(t2,[a1 b1],'bicubic');%缩放为一致大小
t1=round(t1);
t2=round(t2);
e1=zeros(1,256);
e2=zeros(1,256);
%获取直方图分布
for i=1:a1for j=1:b1n1=t1(i,j)+1;n2=t2(i,j)+1;e1(n1)=e1(n1)+1;e2(n2)=e2(n2)+1;end
end
figure;
imhist(uint8(t1));
figure;
imhist(uint8(t2));
%将直方图分为64个区
m1=zeros(1,64);
m2=zeros(1,64);
for i=0:63m1(1,i+1)=e1(4*i+1)+e1(4*i+2)+e1(4*i+3)+e1(4*i+4);m2(1,i+1)=e2(4*i+1)+e2(4*i+2)+e2(4*i+3)+e2(4*i+4);
end
%计算余弦相似度
A=sqrt(sum(sum(m1.^2)));
B=sqrt(sum(sum(m2.^2)));
C=sum(sum(m1.*m2));
cos1=C/(A*B);%计算余弦值
cos2=acos(cos1);%弧度
v=cos2*180/pi;%换算成角度
figure;
imshow(uint8([t1,t2]));
title(['余弦值为:',num2str(cos1),'       ','余弦夹角为:',num2str(v),'°']);
%http://blog.sina.com.cn/s/blog_b27f71160101gpep.html
clear;
close all;
clc;
srcDir=uigetdir('Choose source directory.');
cd(srcDir);
allnames=struct2cell(dir('*.jpg'));
[k,len]=size(allnames);
FinalResult = {};for i=1:lenname=allnames{1,i};
picture1 = imread(name);
picture2 = imread('006.jpg');
v=tineyesearch_hist(picture1,picture2);
FinalResult{i,1} = char('006.jgp');
FinalResult{i,2} = name;
FinalResult{i,3} = v;
endfigure('NumberTitle', 'off', 'Name', '统计表');
columnname =   {'ReferenceImage','TestImage', 'SimilarScore'};     %各列的名称
% columnformat = {'numeric', 'bank', 'numeric'};  %各列的数据类型
columneditable =  [false true true];                %各列是否是可编辑的,true是可以编辑,false是不可编辑
t = uitable('Units','normalized','Position',...[0.1 0.1 0.9 0.9], 'Data', FinalResult,...'ColumnName', columnname,...'ColumnEditable', columneditable);

图像相似性搜索的原理相关推荐

  1. matlab 文本相似度,图像相似性搜索的MATLAB实现

    图像相似性搜索的MATLAB实现(论文11000字) 摘要:随着计算机的普及率增加,用户越来越注重网络体验,同时对图像检索的要求越来越高,快速.准确是从业者和用户永恒的目标和期望.这就对图像相似性检索 ...

  2. 探究Facebook相似性搜索工具 faiss的原理

    探究Facebook相似性搜索工具的原理 它是一个能使开发者快速搜索相似多媒体文件的算法库.而该领域一直是传统的搜索引擎的短板.借助Faiss,Facebook 在十亿级数据集上创建的最邻近搜索(ne ...

  3. 用go来做图像相似性比较

    原文 目录 背景介绍 背景知识 原理过程介绍 1. 减小图像的尺寸 2. 编程灰度图像 3. 计算颜色的平均值 4. 计算64位中的每一位 5. 计算hash值 Go语言实践 参考文档 背景介绍 20 ...

  4. 海量数据相似度搜索,如相似的网页、图像、文章、query 等相似性搜索

    参考资料: https://blog.csdn.net/icvpr/article/details/12342159 局部敏感哈希(Locality-Sensitive Hashing, LSH)方法 ...

  5. 救救小王吧:如何快速解决图像相似性检测问题?

    相似性图像检测,是模型训练过程中常出现的问题,本文介绍了 4 个常用的哈希算法,并通过 Colab 代码,展示了完整的训练过程. 新晋炼丹师小王最近遇到了一个难题,愁的头发掉了好几根儿. 一问才知道, ...

  6. 图像相似性匹配 快速算法

    需求是库内存有部分版权图片,现在搜索网上是否有侵权图片.因此从网上跑去大量图片和库内的版权图片比较,由于比较数量大,对效率有一定的要求. 方法1: 关键点匹配(Keypoint Matching) 一 ...

  7. 一致代价搜索_谷歌工程师发布最新技术ScaNN:可实现高效的向量相似性搜索

    假设一个人想要使用要求标题,作者或其他易于机器索引的精确匹配的查询条件来搜索庞大的文学作品数据集,而这样的任务恰恰非常适合使用SQL之类的关系数据库.但是,如果要支持更多的抽象查询,例如"南 ...

  8. Google 图片搜索的原理是什么?

    Google 图片搜索的原理是什么? 1 条评论 分享 按投票排序按时间排序 18 个回答 389赞同 反对,不会显示你的姓名 知乎用户,安全行业 XsXs.知乎用户.知乎用户 等人赞同 针对这个问题 ...

  9. 简单的相似图片搜索的原理

    FROM:1) http://www.ruanyifeng.com/blog/2011/07/principle_of_similar_image_search.html 2) http://www. ...

最新文章

  1. 在vue项目中引入高德地图及其UI组件的方法
  2. 缓冲区溢出漏洞攻击演示实验(CProxy 6.2缓冲区溢出漏洞)
  3. python切换ip群发邮件_通过 python 把家里路由的 IP 发邮件给自己
  4. vba控制matlab,Matlab加VBA在实验室内质量控制中的应用(南京)
  5. linkin大话设计模式--单例模式
  6. 专题三——枚举、模拟、排序
  7. 【实验】实验五 MATLAB高等数学运算20211125
  8. 矢量网络分析仪测量相位是靠什么实现的
  9. 学习笔记——利用串口通信控制LED指示灯开关
  10. 别克汽车常见疑难故障1000实例
  11. InnoDB——锁、事务和复制
  12. 中国超级计算机神威 上市公司,中国拟研发百亿亿级超级计算机 秒杀目前最快神威...
  13. Linux/Centos nethogs 按进程监控网络带宽
  14. JavaWeb-狂神系列
  15. Android 9.0 Wifi连接AP过程
  16. C++ 如何保留两位小数
  17. EasyCVR国标GB28181协议接入时TCP和UDP模式的差异
  18. Jython-在JAVA调用Python脚本使用方法详解+示例代码
  19. 【GaussDB数据库----连接】
  20. 复旦大学桂韬:当NLP邂逅Social Media--构建计算机与网络语言的桥梁

热门文章

  1. php调用百度天气接口,php使用百度天气接口示例
  2. [蓝桥杯][2016年第七届真题]密码脱落(记忆化搜索)
  3. 【计算机组成原理】计算机软硬件组成
  4. 【计算机组成原理】各种码表示的数
  5. oracle 分组排序后取第一条_关于oracle中位图索引的探讨:概念、原理、优缺点...
  6. python理论知识选择题_python基础知识练习题(一)
  7. 【IT笔试面试题整理】给定一个数组a[N]构造数组b [N]
  8. 深度学习模型建立过程_所有深度学习都是统计模型的建立
  9. 全志A33-串口的使用
  10. 第一次申请信用卡额度太低,怎么办?