相似图片搜索的算法有很多种,如aHash、pHash、bHash等。
颜色分布法指的是根据图片的颜色分布决定他们是否相似。
实现步骤
- 分别获取两张图片的颜色分布
- 用余弦相似度计算出相似值
颜色分布
即图片中每个颜色出现次数的统计:
任意一种颜色都是由 rgb
三原色构成的,每个原色的取值在 0-255
之间,所有颜色的总数达到 256^3=16777215
个,精准统计每一个颜色的计算成本非常高,因此需要简化颜色的取值。
可以将每个原色的取值变成四个部分:0-63
、64-127
、128-191
、192-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;
该更新了,铁子