利用k-means聚类算法识别图片主色调

由于使用php来写图片主色调识别功能太麻烦了,所以我给大家介绍利用利用k-means聚类算法识别图片主色调方法.

识别图片主色调这个,网上貌似有几种方法,不过最准确,最优雅的解决方案还是利用聚类算法来做.

直接上代码,不过,我测试结果表示,用PHP来做,效率不佳,PHP不适合做这种大规模运算,用nodejs做效率可以高出100倍左右,代码如下:

  1. <?php
  2. $start = microtime(TRUE);
  3. main();
  4. function main($img = ‘colors_files/T1OX3eXldXXXcqfYM._111424.jpg’)
  5. {
  6. list($width, $height, $mime_code) = getimagesize($img);
  7. //开源代码phpfensi.com
  8. $im = null;
  9. $point = array();
  10. switch ($mime_code)
  11. {
  12. # jpg
  13. case 2:
  14. $im =imagecreatefromjpeg($img);
  15. break;
  16. # png
  17. case 3:
  18. default:
  19. exit(‘擦 ,什么图像?解析不了啊’);
  20. }
  21. $new_width = 100;
  22. $new_height = 100;
  23. $pixel = imagecreatetruecolor($new_width, $new_height);
  24. imagecopyresampled($pixel, $im, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
  25. run_time();
  26. $i = $new_width;
  27. while ($i–)
  28. {
  29. # reset高度
  30. $k = $new_height;
  31. while ($k–)
  32. {
  33. $rgb = ImageColorAt($im, $i, $k);
  34. array_push($point, array(‘r’=>($rgb >> 16) & 0xFF, ‘g’=>($rgb >> 8) & 0xFF, ‘b’=>$rgb & 0xFF));
  35. }
  36. }
  37. imagedestroy($im);
  38. imagedestroy($pixel);
  39. run_time();
  40. $color = kmeans($point);
  41. run_time();
  42. foreach ($color as $key => $value)
  43. &nb
  44. sp; {
  45. echo ‘<br><span style=“background-color:’ . RGBToHex($value[0]) . ‘” >’ . RGBToHex($value[0]) . ‘</span>’;
  46. }
  47. }
  48. function run_time()
  49. {
  50. global $start;
  51. echo ‘<br/>消耗:’, microtime(TRUE) – $start;
  52. }
  53. function kmeans($point=array(), $k=3, $min_diff=1)
  54. {
  55. global $ii;
  56. $point_len = count($point);
  57. $clusters = array();
  58. $cache = array();
  59. for ($i=0; $i < 256; $i++)
  60. {
  61. $cache[$i] = $i*$i;
  62. }
  63. # 随机生成k值
  64. $i = $k;
  65. $index = 0;
  66. while ($i–)
  67. {
  68. $index = mt_rand(1,$point_len-100);
  69. array_push($clusters, array($point[$index], array($point[$index])));
  70. }
  71. run_time();
  72. $point_list = array();
  73. $run_num = 0;
  74. while (TRUE)
  75. {
  76. foreach ($point as $value)
  77. {
  78. $smallest_distance = 10000000;
  79. # 求出距离最小的点
  80. # index用于保存point最靠近的k值
  81. $index = 0;
  82. $i = $k;
  83. while ($i–)
  84. {
  85. $distance = 0;
  86. foreach ($value as $key => $p1)
  87. {
  88. &n
  89. bsp; if ($p1 > $clusters[$i][0][$key])
  90. {
  91. $distance += $cache[$p1 - $clusters[$i][0][$key]];
  92. }
  93. else
  94. {
  95. $distance += $cache[$clusters[$i][0][$key] – $p1];
  96. }
  97. }
  98. $ii++;
  99. if ($distance < $smallest_distance)
  100. {
  101. $smallest_distance = $distance;
  102. $index = $i;
  103. }
  104. }
  105. $point_list[$index][] = $value;
  106. }
  107. $diff = 0;
  108. # 1个1个迭代k值
  109. $i = $k;
  110. while ($i–)
  111. {
  112. $old = $clusters[$i];
  113. # 移到到队列中心
  114. $center = calculateCenter($point_list[$i], 3);
  115. # 形成新的k值集合队列
  116. $new_cluster = array($center, $point_list[$i]);
  117. $clusters[$i] = $new_cluster;
  118. # 计算新的k值与队列所在点的位置
  119. $diff = euclidean($old[0], $center);
  120. }
  121. # 判断是否已足够聚合
  122. if ($diff < $min_diff)
  123. {
  124. break;
  125. >
  126. }
  127. }
  128. echo ‘—>’.$ii;
  129. return $clusters;
  130. }
  131. # 计算2点距离
  132. $ii = 0;
  133. function euclidean($p1, $p2)
  134. {
  135. $s = 0;
  136. foreach ($p1 as $key => $value)
  137. {
  138. $temp = ($value – $p2[$key]);
  139. $s += $temp*$temp;
  140. }
  141. return sqrt($s);
  142. }
  143. # 移动k值到所有点的中心
  144. function calculateCenter($point_list, $attr_num) {
  145. $vals = array();
  146. $point_num = 0;
  147. $keys = array_keys($point_list[0]);
  148. foreach($keys as $value)
  149. {
  150. $vals[$value] = 0;
  151. }
  152. foreach ($point_list as $arr)
  153. {
  154. $point_num++;
  155. foreach ($arr as $key => $value)
  156. {
  157. $vals[$key] += $value;
  158. }
  159. }
  160. foreach ($keys as $index)
  161. {
  162. $vals[$index] = $vals[$index] / $point_num;
  163. }
  164. return $vals;
  165. }
  166. function RGBToHex($r, $g=”, $b=”)
  167. {
  168. if (is_array($r))
  169. {
  170. $b = $r['b'];
  171. $g = $r['g'];
  172. $r = $r['r'];
  173. }
  174. $hex = “#”;
  175. $hex.= str_pad(dechex($r), 2, ’0′, STR_PAD_LEFT);
  176. $hex.= str_pad(dechex($g), 2, ’0′, STR_PAD_LEFT);
  177. $hex.= str_pad(dechex($b), 2, ’0′, STR_PAD_LEFT);
  178. return $hex;
  179. }
  180. ?>