相似图片搜索的算法有很多种,如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;

该更新了,铁子