Detect “overall average” color of the picture

前端 未结 7 905
走了就别回头了
走了就别回头了 2020-12-04 05:53

I have a jpg image.

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

At wor

相关标签:
7条回答
  • 2020-12-04 05:55

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

    <?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.

    EDIT A 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 Javascript Lokesh's Color-Theif library does exactly what you're looking for.

    0 讨论(0)
  • 2020-12-04 06:01

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

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

    Something like this.

    Image color detection using python

    0 讨论(0)
  • 2020-12-04 06:03

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

    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.

    0 讨论(0)
  • 2020-12-04 06:06

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

    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.

    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).

    #!/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.

    0 讨论(0)
  • 2020-12-04 06:09
    $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 !

    0 讨论(0)
  • 2020-12-04 06:14

    Combining JKirchartz and Alexander Hugestrand answer:

     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.

    0 讨论(0)
提交回复
热议问题