利用k-means聚类算法识别图片主色调
由于使用php来写图片主色调识别功能太麻烦了,所以我给大家介绍利用利用k-means聚类算法识别图片主色调方法,比php要己100倍哦。
识别图片主色调这个,网上貌似有几种方法,不过,最准确,最优雅的解决方案还是利用聚类算法来做。。。
直接上代码。。。。不过,我测试结果表示,用PHP来做,效率不佳,PHP不适合做这种大规模运算~~~,用nodejs做 效率可以高出100倍左右。。。
<?php
$start = microtime(TRUE);
main();
function main($img = 'colors_files/T1OX3eXldXXXcqfYM._111424.jpg') {
list($width, $height, $mime_code) = getimagesize($img);
$im = null;
$point = array();
switch ($mime_code) {
// jpg
case 2:
$im = imagecreatefromjpeg($img);
break;
// png
case 3:
default:
exit('擦 ,什么图像?解析不了啊');
}
$new_width = 100;
$new_height = 100;
$pixel = imagecreatetruecolor($new_width, $new_height);
imagecopyresampled($pixel, $im, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
run_time();
$i = $new_width;
while ($i--) {
// reset高度
$k = $new_height;
while ($k--) {
$rgb = ImageColorAt($im, $i, $k);
array_push($point, array(
'r' => ($rgb >> 16) & 0xFF,
'g' => ($rgb >> 8) & 0xFF,
'b' => $rgb & 0xFF
));
}
}
imagedestroy($im);
imagedestroy($pixel);
run_time();
$color = kmeans($point);
run_time();
foreach ($color as $key => $value) {
echo '<br><span style="background-color:' . RGBToHex($value[0]) . '" >' . RGBToHex($value[0]) . '</span>';
}
}
function run_time() {
global $start;
echo '<br/>消耗:', microtime(TRUE) - $start;
}
function kmeans($point = array() , $k = 3, $min_diff = 1) {
global $ii;
$point_len = count($point);
$clusters = array();
$cache = array();
for ($i = 0; $i < 256; $i++) {
$cache[$i] = $i * $i;
}
// 随机生成k值
$i = $k;
$index = 0;
while ($i -) {
$index = mt_rand(1, $point_len - 100);
array_push($clusters, array(
$point[$index],
array(
$point[$index]
)
));
}
run_time();
$point_list = array();
$run_num = 0;
while (TRUE) {
foreach ($point as $value) {
$smallest_distance = 10000000;
// 求出距离最小的点
// index用于保存point最靠近的k值
$index = 0;
$i = $k;
while ($i -) {
$distance = 0;
foreach ($value as $key => $p1) {
if ($p1 > $clusters[$i][0][$key]) {
$distance+= $cache[$p1 - $clusters[$i][0][$key]];
} else {
$distance+= $cache[$clusters[$i][0][$key] - $p1];
}
}
$ii++;
if ($distance < $smallest_distance) {
$smallest_distance = $distance;
$index = $i;
}
}
$point_list[$index][] = $value;
}
$diff = 0;
// 1个1个迭代k值
$i = $k;
while ($i -) {
$old = $clusters[$i];
// 移到到队列中心
$center = calculateCenter($point_list[$i], 3);
// 形成新的k值集合队列
$new_cluster = array(
$center,
$point_list[$i]
);
$clusters[$i] = $new_cluster;
// 计算新的k值与队列所在点的位置
$diff = euclidean($old[0], $center);
}
// 判断是否已足够聚合
if ($diff < $min_diff) {
break; >
}
}
echo '->' . $ii;
return $clusters;
}
// 计算2点距离
$ii = 0;
function euclidean($p1, $p2) {
$s = 0;
foreach ($p1 as $key => $value) {
$temp = ($value - $p2[$key]);
$s+= $temp * $temp;
}
return sqrt($s);
}
// 移动k值到所有点的中心
function calculateCenter($point_list, $attr_num) {
$vals = array();
$point_num = 0;
$keys = array_keys($point_list[0]);
foreach ($keys as $value) {
$vals[$value] = 0;
}
foreach ($point_list as $arr) {
$point_num++;
foreach ($arr as $key => $value) {
$vals[$key]+= $value;
}
}
foreach ($keys as $index) {
$vals[$index] = $vals[$index] / $point_num;
}
return $vals;
}
function RGBToHex($r, $g = ", $b=") {
if (is_array($r)) {
$b = $r[b];
$g = $r[g];
$r = $r[r];
}
$hex = "#";
$hex.= str_pad(dechex($r) , 2, '0', STR_PAD_LEFT);
$hex.= str_pad(dechex($g), 2, '0 '
, STR_PAD_LEFT);
$hex.= str_pad(dechex($b) , 2, '0 '
, STR_PAD_LEFT);
return $hex;
}
?>本文链接:http://www.phprm.com/frame/php1005385.html
收藏随意^^请保留教程地址.