许多查找引擎能够用一张图片,查找互联网上一切与它类似的图片。你输入网片的网址,或许直接上传图片,Google就会找出与其类似的图片。下面这张图片是美国女演员Alyson Hannigan。
上传后,Google回来如下成果:
类似的”类似图片查找引擎”还有不少,TInEye乃至能够找出相片的拍照布景。
===================================================
这种技能的原理是什么?核算机怎样知道两张图片类似呢?
依据Neal Krawetz博士的解说,原理十分简略易懂。咱们能够用一个快速算法,就到达根本的作用。
这儿的关键技能叫做”感知哈希算法”(Perceptual hash algorithm),它的作用是对每张图片生成一个”指纹”(fingerprint)字符串,然后比较不同图片的指纹。成果越挨近,就阐明图片越类似。
下面是一个最简略的完成:
第一步,缩小尺度。
将图片缩小到8&TImes;8的尺度,一共64个像素。这一步的作用是去除图片的细节,只保存结构、明暗等根本信息,摒弃不同尺度、份额带来的图片差异。
第二步,简化色彩。
将缩小后的图片,转为64级灰度。也便是说,一切像素点一共只需64种色彩。
第三步,核算平均值。
核算一切64个像素的灰度平均值。
第四步,比较像素的灰度。
将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。
第五步,核算哈希值。
将上一步的比较成果,组合在一起,就构成了一个64位的整数,这便是这张图片的指纹。组合的次第并不重要,只需确保一切图片都选用相同次第就行了。
得到指纹今后,就能够比照不同的图片,看看64位中有多少位是不相同的。在理论上,这等同于核算“汉明间隔”(Hamming distance)。假如不相同的数据位不超越5,就阐明两张图片很类似;假如大于10,就阐明这是两张不同的图片。
详细的代码完成,能够拜见Wote用python言语写的imgHash.py。代码很短,只需53行。运用的时分,第一个参数是基准图片,第二个参数是用来比较的其他图片地点的目录,回来成果是两张图片之间不相同的数据位数量(汉明间隔)。
这种算法的长处是简略快速,不受图片大小缩放的影响,缺陷是图片的内容不能变更。假如在图片上加几个文字,它就认不出来了。所以,它的最佳用处是依据缩略图,找出原图。
实践使用中,往往选用更强壮的pHash算法和SIFT算法,它们能够辨认图片的变形。只需变形程度不超越25%,它们就能匹配原图。这些算法尽管更杂乱,可是原理与上面的简洁算法是相同的,便是先将图片转化成Hash字符串,然后再进行比较。
昨日,我在isnowfy的网站看到,还有其他两种办法也很简略,这儿做一些笔记。
一、色彩散布法
每张图片都能够生成色彩散布的直方图(color histogram)。假如两张图片的直方图很挨近,就能够以为它们很类似。
任何一种色彩都是由红绿蓝三原色(RGB)构成的,所以上图共有4张直方图(三原色直方图 + 终究组成的直方图)。
假如每种原色都能够取256个值,那么整个色彩空间共有1600万种色彩(256的三次方)。针对这1600万种色彩比较直方图,核算量真实太大了,因而需求选用简化办法。能够将0~255分红四个区:0~63为第0区,64~127为第1区,128~191为第2区,192~255为第3区。这意味着红绿蓝别离有4个区,一共能够构成64种组合(4的3次方)。
任何一种色彩必定归于这64种组合中的一种,这样就能够核算每一种组合包括的像素数量。
上图是某张图片的色彩散布表,将表中终究一栏提取出来,组成一个64维向量(7414, 230, 0, 0, 8, …, 109, 0, 0, 3415, 53929)。这个向量便是这张图片的特征值或许叫”指纹”。
所以,寻觅类似图片就变成了找出与其最类似的向量。这能够用皮尔逊相关系数或许余弦类似度算出。
二、内容特征法
除了色彩构成,还能够从比较图片内容的类似性下手。
首要,将原图转成一张较小的灰度图片,假定为50&TImes;50像素。然后,确认一个阈值,将灰度图片转成是非图片。
假如两张图片很类似,它们的是非概括应该是附近的。所以,问题就变成了,第一步怎么确认一个合理的阈值,正确出现相片中的概括?
显着,前景色与布景色反差越大,概括就越显着。这意味着,假如咱们找到一个值,能够使得前景色和布景色各自的”类内差异最小”(minimizing the intra-class variance),或许”类间差异最大”(maximizing the inter-class variance),那么这个值便是抱负的阈值。
1979年,日本学者大津展之证明晰,”类内差异最小”与”类间差异最大”是同一件事,即对应同一个阈值。他提出一种简略的算法,能够求出这个阈值,这被称为“大津法”(Otsu’s method)。下面便是他的核算办法。
假定一张图片共有n个像素,其间灰度值小于阈值的像素为 n1 个,大于等于阈值的像素为 n2 个( n1 + n2 = n )。w1 和 w2 表明这两种像素各自的比重。
w1 = n1 / n
w2 = n2 / n
再假定,一切灰度值小于阈值的像素的平均值和方差别离为 μ1 和 σ1,一切灰度值大于等于阈值的像素的平均值和方差别离为 μ2 和 σ2。所以,能够得到
类内差异 = w1(σ1的平方) + w2(σ2的平方)
类间差异 = w1w2(μ1-μ2)^2
能够证明,这两个式子是等价的:得到”类内差异”的最小值,等同于得到”类间差异”的最大值。不过,从核算难度看,后者的核算要简单一些。
下一步用”穷举法”,将阈值从灰度的最低值到最高值,顺次取一遍,别离代入上面的算式。使得”类内差异最小”或”类间差异最大”的那个值,便是终究的阈值。详细的实例和Java算法,请看这儿。
?
有了50&TImes;50像素的是非缩略图,就等于有了一个50×50的0-1矩阵。矩阵的每个值对应原图的一个像素,0表明黑色,1表明白色。这个矩阵便是一张图片的特征矩阵。
两个特征矩阵的不同之处越少,就代表两张图片越类似。这能够用”异或运算”完成(即两个值之中只需一个为1,则运算成果为1,不然运算成果为0)。对不同图片的特征矩阵进行”异或运算”,成果中的1越少,便是越类似的图片。