由于使用php来写图片主色调识别功能太麻烦了,所以我给大家介绍利用利用k-means聚类算法识别图片主色调方法.
识别图片主色调这个,网上貌似有几种方法,不过最准确,最优雅的解决方案还是利用聚类算法来做.
直接上代码,不过,我测试结果表示,用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)
-
- &nb
- sp; {
-
- 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)
-
- {
-
- &n
- bsp; 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;
-
- }
-
- ?>
|