Python 检测图片的“整体平均”颜色

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3468500/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 11:13:21  来源:igfitidea点击:

Detect "overall average" color of the picture

phpjavascriptpythonimage-processing

提问by Kalinin

I have a jpg image.

我有一个 jpg 图像。

I need to know "overall average" the color of the image. At first glance there can use the histogram of the image (channel RGB).

我需要知道图像的“整体平均”颜色。乍一看,可以使用图像的直方图(通道 RGB)。

At work I use mostly JavaScript and PHP (a little Python) therefore welcomed the decision in these languages. Maybe ther are library for working with images that address similar problems.

在工作中,我主要使用 JavaScript 和 PHP(一点 Python),因此欢迎使用这些语言的决定。也许有用于处理类似问题的图像的库。

I do not need to dynamically determine the color of the picture. I need just once go through the entire array of images and determine the color of each separately (this information I will remember for future use).

我不需要动态确定图片的颜色。我只需要遍历整个图像数组并分别确定每个图像的颜色(我会记住这些信息以备将来使用)。

采纳答案by JKirchartz

You can use PHPto get an array of the color palette like so:

您可以使用PHP来获取调色板数组,如下所示:

<?php 
function colorPalette($imageFile, $numColors, $granularity = 5) 
{ 
   $granularity = max(1, abs((int)$granularity)); 
   $colors = array(); 
   $size = @getimagesize($imageFile); 
   if($size === false) 
   { 
      user_error("Unable to get image size data"); 
      return false; 
   } 
   $img = @imagecreatefromjpeg($imageFile);
   // Andres mentioned in the comments the above line only loads jpegs, 
   // and suggests that to load any file type you can use this:
   // $img = @imagecreatefromstring(file_get_contents($imageFile)); 

   if(!$img) 
   { 
      user_error("Unable to open image file"); 
      return false; 
   } 
   for($x = 0; $x < $size[0]; $x += $granularity) 
   { 
      for($y = 0; $y < $size[1]; $y += $granularity) 
      { 
         $thisColor = imagecolorat($img, $x, $y); 
         $rgb = imagecolorsforindex($img, $thisColor); 
         $red = round(round(($rgb['red'] / 0x33)) * 0x33); 
         $green = round(round(($rgb['green'] / 0x33)) * 0x33); 
         $blue = round(round(($rgb['blue'] / 0x33)) * 0x33); 
         $thisRGB = sprintf('%02X%02X%02X', $red, $green, $blue); 
         if(array_key_exists($thisRGB, $colors)) 
         { 
            $colors[$thisRGB]++; 
         } 
         else 
         { 
            $colors[$thisRGB] = 1; 
         } 
      } 
   } 
   arsort($colors); 
   return array_slice(array_keys($colors), 0, $numColors); 
} 
// sample usage: 
$palette = colorPalette('rmnp8.jpg', 10, 4); 
echo "<table>\n"; 
foreach($palette as $color) 
{ 
   echo "<tr><td style='background-color:#$color;width:2em;'>&nbsp;</td><td>#$color</td></tr>\n"; 
} 
echo "</table>\n";

Which gives you an array whose values are higher for how often that color has been used.

这为您提供了一个数组,该数组的值与该颜色的使用频率有关。

EDITA commenter asked how to use this on all files in a directory, here it is:

编辑评论者询问如何在目录中的所有文件上使用它,这里是:

    if ($handle = opendir('./path/to/images')) {

        while (false !== ($file = readdir($handle))) {
           $palette = colorPalette($file, 10, 4);
           echo "<table>\n"; 
           foreach($palette as $color) { 
               echo "<tr><td style='background-color:#$color;width:2em;'>&nbsp;</td><td>#$color</td></tr>\n"; 
           } 
           echo "</table>\n";
        }
        closedir($handle);
    }

might not want to do this on too many files, but it's your server.

可能不想对太多文件执行此操作,但这是您的服务器。

Alternatively if you'd rather use JavascriptLokesh's Color-Theiflibrary does exactly what you're looking for.

或者,如果您更愿意使用Javascript Lokesh 的 Color-Theif库,那么它完全符合您的要求。

回答by S.Lott

Start with PIL. http://www.pythonware.com/products/pil/

从 PIL 开始。 http://www.pythonware.com/products/pil/

Open the Image object. Use the getdatamethod to get all pixels. Average the values you get back.

打开图像对象。使用该getdata方法获取所有像素。平均你得到的价值。

Something like this.

像这样的东西。

Image color detection using python

使用python进行图像颜色检测

回答by Alexander Hugestrand

A shorter solution for true color image would be to scale it down to 1x1 pixel size and sample the color at that pixel:

真彩色图像的一个更短的解决方案是将其缩小到 1x1 像素大小并在该像素处采样颜色:

$scaled = imagescale($img, 1, 1, IMG_BICUBIC); $meanColor = imagecolorat($img, 0, 0);

$scaled = imagescale($img, 1, 1, IMG_BICUBIC); $meanColor = imagecolorat($img, 0, 0);

...but I haven't tested this myself.

......但我自己没有测试过。

回答by Johnny Rockex

Combining JKirchartz and Alexander Hugestrand answer:

结合 JKirchartz 和 Alexander Hugestrand 的回答:

 function getAverage($sourceURL){

    $image = imagecreatefromjpeg($sourceURL);
    $scaled = imagescale($image, 1, 1, IMG_BICUBIC); 
    $index = imagecolorat($scaled, 0, 0);
    $rgb = imagecolorsforindex($scaled, $index); 
    $red = round(round(($rgb['red'] / 0x33)) * 0x33); 
    $green = round(round(($rgb['green'] / 0x33)) * 0x33); 
    $blue = round(round(($rgb['blue'] / 0x33)) * 0x33); 
    return sprintf('#%02X%02X%02X', $red, $green, $blue); 
 }

Tried and tested, returns hex string.

尝试和测试,返回十六进制字符串。

回答by tooleks

I've created the composer package that provides the library for picking an average color from the given image by its path.

我创建了 composer 包,该包提供了通过路径从给定图像中选择平均颜色的库。

You can install it by running the following command within your project directory:

您可以通过在项目目录中运行以下命令来安装它:

composer require tooleks/php-avg-color-picker

Usage example:

用法示例:

<?php

use Tooleks\Php\AvgColorPicker\Gd\AvgColorPicker;

$imageAvgHexColor = (new AvgColorPicker)->getImageAvgHexByPath('/absolute/path/to/the/image.(jpg|jpeg|png|gif)');

// The `$imageAvgHexColor` variable contains the average color of the given image in HEX format (#fffff).

See the documentation.

请参阅文档

回答by antoine demacon

$img = glob('img/*');
foreach ($img as $key => $value) {
    $info = getimagesize($value);
    $mime = $info['mime'];
    switch ($mime) {
        case 'image/jpeg':
            $image_create_func = 'imagecreatefromjpeg';
            break;
        case 'image/png':
            $image_create_func = 'imagecreatefrompng';
            break;
        case 'image/gif':
            $image_create_func = 'imagecreatefromgif';
            break;
    }
    $avg = $image_create_func($value);
    list($width, $height) = getimagesize($value);
    $tmp = imagecreatetruecolor(1, 1);
    imagecopyresampled($tmp, $avg, 0, 0, 0, 0, 1, 1, $width, $height);
    $rgb = imagecolorat($tmp, 0, 0);
    $r = ($rgb >> 16) & 0xFF;
    $g = ($rgb >> 8) & 0xFF;
    $b = $rgb & 0xFF;
    echo '<div style="text-align:center; vertical-align: top; display:inline-block; width:100px; height:150px; margin:5px; padding:5px; background-color:rgb('.$r.','.$g.','.$b.');">';
    echo '<img style="width:auto; max-height:100%; max-width: 100%; vertical-align:middle; height:auto; margin-bottom:5px;" src="'.$value.'">';
    echo '</div>';

you can get the value of the average color with $r, $g, & $b resample the image is much more better than only scale it !

您可以使用 $r、$g 和 $b 来获得平均颜色的值,重新采样图像比仅缩放图像要好得多!

回答by jcupitt

Here's a solution using php-vips. It's very fast, and will find the most commoncolour, rather than the average colour.

这是使用php-vips的解决方案。它非常快,并且会找到最常见的颜色,而不是平均颜色。

Most photos will have grey as the average, since that's what auto white balance does. What you really want is the colour which appears most often.

大多数照片的平均值都是灰色的,因为这就是自动白平衡的作用。你真正想要的是最常出现的颜色。

This program uses a 3D histogram. It makes a 10 x 10 x 10 cube (you can change this, see $n_bins) to represent the whole of RGB colourspace, then loops through the image counting the number of pixels which fall into each bin. It sets the count in bin (0, 0, 0) to zero (black is usually uninteresting background), then searches for the bin with the highest count. The index of that bin is the most common RGB colour.

该程序使用 3D 直方图。它制作了一个 10 x 10 x 10 的立方体(您可以更改它,请参阅$n_bins参考资料)来表示整个 RGB 色彩空间,然后循环遍历图像,计算落入每个 bin 的像素数。它将 bin (0, 0, 0) 中的计数设置为零(黑色通常是无趣的背景),然后搜索计数最高的 bin。该 bin 的索引是最常见的 RGB 颜色。

This won't work for most PNGs (you'll need to flatten out the alpha) or CMYKs (you'll need to convert to RGB first).

这不适用于大多数 PNG(您需要拉平 alpha)或 CMYK(您需要先转换为 RGB)。

#!/usr/bin/env php
<?php

require __DIR__ . '/vendor/autoload.php';
use Jcupitt\Vips;

$im = Vips\Image::newFromFile($argv[1], ['access' => 'sequential']);

# 3D histogram ... make 10 x 10 x 10 bins, so 1000 possible colours
$n_bins = 10;
$hist = $im->hist_find_ndim(['bins' => $n_bins]);

# black is usually background or boring, so set that cell to 0 counts
# fetch (0, 0, set the 0th element of that to 0, paste back
$pixel = $hist->getpoint(0, 0);
$pixel[0] = 0;
$pixel = Vips\Image::black(1, 1)->add($pixel);
$hist = $hist->insert($pixel, 0, 0);

# (x, y) pixel with the most counts
[$v, $x, $y] = $hist->maxpos();
$pixel = $hist->getpoint($x, $y);
$z = array_search($v, $pixel);

# convert indexes to rgb ... +0.5 to get the centre of each bin
$r = ($x + 0.5) * 256 / $n_bins;
$g = ($y + 0.5) * 256 / $n_bins;
$b = ($z + 0.5) * 256 / $n_bins;

echo("r = " . $r . "\n");
echo("g = " . $g . "\n");
echo("b = " . $b . "\n");

I can run it like this:

我可以像这样运行它:

$ time ./try302.php ~/pics/shark.jpg 
r = 38.4
g = 38.4
b = 12.8
real    0m0.077s
user    0m0.068s
sys 0m0.016s

So 70ms on this modest laptop for a 700 x 700 pixel jpg.

所以在这台适中的笔记本电脑上 70 毫秒才能获得 700 x 700 像素的 jpg。