【问题标题】:JS - How to check if 2 images (their hash) are similarJS - 如何检查 2 个图像(它们的哈希)是否相似
【发布时间】:2017-12-31 01:06:58
【问题描述】:

目标
通过比较它们的 hash 配置文件,找到一种检查 2 张图片是否相似的好方法。哈希是一个简单的数组,包含0 和1 值

简介
我有 2 张图片。它们是相同的图像,但有一些微小不同:一个具有不同的亮度、旋转和拍摄。
我想要做的是创建一个 Javascript 方法来比较 2 个图像并计算一个 百分比值,它告诉 它们有多少相似度

我做了什么
在将 2 张图片上传到 html5 画布以获取它们的图像数据后,我使用 pHash 算法 (www.phash.org) 来获取它们的 hash 展示。
哈希是一个包含 0 和 1 值的数组,它以“简化”形式重新创建图像。
我还创建了一个 JS 脚本,它生成一个带有黑色单元格的 html 表格,其中数组包含 1。
结果是以下屏幕截图(图像是梵高图片):

Screenshot

现在,我应该做的是比较两个数组以获得百分比值,以了解它们的“相似程度”。
我发现谷歌搜索的大部分哈希 Javascript 算法已经有一个比较算法:汉明距离算法。它非常简单和快速,但不是很精确。事实上,汉明距离算法表明我的截图中的 2 张图像具有 67% 的相似度

问题
从 2 个长度相同的简单数组开始,填充 0 和 1 值:有什么好的算法可以更精确地确定相似度?

注意事项
- 纯 Javascript 开发,无第三方插件或框架。
- 当 2 张图像相同但它们非常不同(强烈旋转、完全不同的颜色等)时,无需复杂的算法来找到正确的相似度。

谢谢

PHASH 代码

  // Size is the image size (for example 128px)
  var pixels = [];

  for (var i=0;i<imgData.data.length;i+=4){
			
      var j = (i==0) ? 0 : i/4;
			var y = Math.floor(j/size);
			var x = j-(y*size);			
			
			var pixelPos = x + (y*size);
			var r = imgData.data[i];
			var g = imgData.data[i+1];
			var b = imgData.data[i+2];

			var gs = Math.floor((r*0.299)+(g*0.587)+(b*0.114));
			pixels[pixelPos] = gs;
      
  }

  var avg = Math.floor( array_sum(pixels) / pixels.length );
  var hash = [];
  array.forEach(pixels, function(px,i){
    if(px > avg){
      hash[i] = 1;
    } else{
      hash[i] = 0;
    }
  });

  return hash;

汉明距离码

  // hash1 and hash2 are the arrays of the "coded" images.
  
  var similarity = hash1.length;
  
  array.forEach(hash1, function(val,key){
    if(hash1[key] != hash2[key]){
      similarity--;
    }
  });

  var percentage = (similarity/hash1.length*100).toFixed(2);

注意:array.forEach 不是纯 JavaScript。将其视为: for (var i = 0; i

【问题讨论】:

  • 请添加您拥有的代码。
  • 您认为汉明距离的“不精确”是什么?这似乎是适合这项工作的工具。您是否有汉明距离不适用于您的示例?
  • 如果你的汉明距离看起来不精确,那更有可能是你的哈希不够精确……汉明距离不能不精确,它完全是二元的。
  • pHash.org 是一个感知哈希算法库,您使用的是哪一个?以及如何?
  • 我们需要查看您的哈希算法

标签: javascript phash


【解决方案1】:

我正在使用blockhash,到目前为止看起来还不错,我得到的唯一误报是当一半的图片具有相同的背景颜色时,这是意料之中的=/

http://blockhash.io/

BlockHash 可能比你的慢,但它应该更准确。

您所做的只是计算每个像素的灰度,并将其与平均值进行比较以创建您的哈希。

BlockHash 所做的是将图片分割成大小相等的小矩形,然后对其中像素的 RGB 值的总和进行平均,并将它们与 4 个水平中值进行比较。

所以需要更长的时间是正常的,但它仍然非常有效和准确。

我正在使用分辨率良好的图片,至少 1000x800,并使用 16 位。这给出了一个 64 字符长的十六进制散列。当使用同一个库提供的汉明距离时,使用 10 相似度阈值时我看到了很好的结果。

您使用灰度的想法一点也不差。但是您应该平均图像的各个部分,而不是比较每个像素。这样您就可以将缩略图版本与其原始版本进行比较,并获得几乎相同的 phash!

【讨论】:

  • 出于好奇,我实现了 BlockHash 算法。结果与我的脚本的差异很小,只有 3% 的差异。值得注意的是,我的算法比 BlockHash 快很多。
  • 在这里,添加了一些信息来帮助您...很遗憾,不能做更多。
【解决方案2】:

我不知道这是否可以解决问题,但您可以比较数组之间的 0 和 1 相似性:

const arr1 = [1,1,1,1,1,1,1,1,1,1],
      arr2 = [0,0,0,0,0,0,0,0,0,0],
      arr3 = [0,1,0,1,0,1,0,1,0,1],
      arr4 = [1,1,1,0,1,1,1,0,1,1]

const howSimilar = (a1,a2) => {
    let similarity = 0
    a1.forEach( (elem,index) => {
        if(a2[index]==elem) similarity++
    })
    let percentage = parseInt(similarity/arr1.length*100) + "%"
    console.log(percentage)
}

howSimilar(arr1,arr2) // 0%
howSimilar(arr1,arr3) // 50%
howSimilar(arr1,arr4) // 80%

【讨论】:

  • 这基本上是汉明距离(倒数)。
  • 这是汉明距离。不幸的是,OP 说他想要别的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-22
  • 2011-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多