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.