相似图片搜索(颜色分布法)

相似图片搜索的算法有很多种,如aHash、pHash、bHash等。
颜色分布法指的是根据图片的颜色分布决定他们是否相似。

实现步骤

  1. 分别获取两张图片的颜色分布
  2. 用余弦相似度计算出相似值

颜色分布

即图片中每个颜色出现次数的统计:

See the source image
颜色分布

任意一种颜色都是由 rgb 三原色构成的,每个原色的取值在 0-255 之间,所有颜色的总数达到 256^3=16777215 个,精准统计每一个颜色的计算成本非常高,因此需要简化颜色的取值。
可以将每个原色的取值变成四个部分:0-6364-127128-191192-255,这样需要统计的总数从 256^3=16777215 变成了 4^3=64 个,大大减少了计算的成本。

/**
 * 获取图片的颜色分布
 * @param $img 图片资源
 * @return array 该图片64种颜色的数量统计
 */
function get_color_distribution ($img) {
  $y_len = imagesy($img);
  $x_len = imagesx($img);
  $res = [];
  for ($i = 0; $i < 64; $i++) {
    $res[$i] = 0;
  }
  for ($y = 0; $y < $y_len; $y++) {
    for ($x = 0; $x < $x_len; $x++) {
      $rgb = imagecolorat($img, $x, $y);
      $color = get_quaternary_rgb($rgb >> 16 & 0xff) * 4 ** 2 +
      get_quaternary_rgb($rgb >> 8 & 0xff) * 4 ** 1 +
      get_quaternary_rgb($rgb >> 0 & 0xff);
      $res[$color]++;
    }
  }
  return $res;
}

/**
 * 获取原色的取值部分
 * @param $num 原色值,0-255
 * @return int 对应的部分,0-3
 */
function get_quaternary_rgb ($num) {
  if ($num < 64) return 0;
  else if ($num < 128) return 1;
  else if ($num < 192) return 2;
  else return 3;
}

余弦相似度

得到两组颜色分布后,通过以下公式计算出相似度。

余弦相似度计算公式
/**
 * 获取两组数列相似值
 * @param $nums1 数列一
 * @param $nums2 数列二
 * @return float|int 相似值
 */
function get_cosine_similarity ($nums1, $nums2) {
  $sum = 0;
  $avg1 = 0;
  $avg2 = 0;
  for ($i = 0; $i < 64; $i++) {
    $n1 = $nums1[$i];
    $n2 = $nums2[$i];
    $sum += $n1 * $n2;
    $avg1 += $n1 ** 2;
    $avg2 += $n2 ** 2;
  }
  return $sum / sqrt($avg1) / sqrt($avg2);
}

实例

// 读取图片资源
$img1 = imagecreatefrompng('image-1.png');
$img2 = imagecreatefrompng('image-2.png');

// 分别获取颜色分布
$distribution1 = get_color_distribution($img1);
$distribution2 = get_color_distribution($img2);

// 计算出相似值
$similarity = get_cosine_similarity($distribution1, $distribution2);

// 输出
echo $similarity;
计算结果

加入对话

1条评论

留下评论

邮箱地址不会被公开。 必填项已用*标注

给博主打赏

2元 5元 10元