Detect overall average color of the picture
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;'> </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;'> </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.
Get average color of image without sacrificing lazy loading
You can create a load event listener for each image, so once each image loads you get the color. Your code can be written thus:
var imgg = document.getElementsByClassName("cimg");
var blocks = document.getElementsByClassName("block");
for (var i = 0; i < imgg.length; i++) {
setColor(i);
}
function setColor(i) {
var $img = imgg[i];
// once the lazy-loaded image loads:
$img.addEventListener("load", e => {
// get average color and set
var rgb = averageColor($img);
blocks[i].style.backgroundColor =
'rgb(' + rgb.r + ','
+ rgb.g + ','
+ rgb.b + ')';
});
}
Get average color of image via Javascript
AFAIK, the only way to do this is with <canvas/>
...
DEMO V2: http://jsfiddle.net/xLF38/818/
Note, this will only work with images on the same domain and in browsers that support HTML5 canvas:
function getAverageRGB(imgEl) {
var blockSize = 5, // only visit every 5 pixels
defaultRGB = {r:0,g:0,b:0}, // for non-supporting envs
canvas = document.createElement('canvas'),
context = canvas.getContext && canvas.getContext('2d'),
data, width, height,
i = -4,
length,
rgb = {r:0,g:0,b:0},
count = 0;
if (!context) {
return defaultRGB;
}
height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
context.drawImage(imgEl, 0, 0);
try {
data = context.getImageData(0, 0, width, height);
} catch(e) {
/* security error, img on diff domain */
return defaultRGB;
}
length = data.data.length;
while ( (i += blockSize * 4) < length ) {
++count;
rgb.r += data.data[i];
rgb.g += data.data[i+1];
rgb.b += data.data[i+2];
}
// ~~ used to floor values
rgb.r = ~~(rgb.r/count);
rgb.g = ~~(rgb.g/count);
rgb.b = ~~(rgb.b/count);
return rgb;
}
For IE, check out excanvas.
How to find average color of an image with ImageMagick?
You can do the following to parse out just the comma-separated RGB values. It also will not return text color names.
convert cat.png -resize 1x1\! \
-format "%[fx:int(255*r+.5)],%[fx:int(255*g+.5)],%[fx:int(255*b+.5)]" info:-
Output format should look like:
155,51,127
This should work in ImageMagick 6.3.9.1+
How can I get the average color of an image?
Bitmap bitmap = someFunctionReturningABitmap();
long redBucket = 0;
long greenBucket = 0;
long blueBucket = 0;
long pixelCount = 0;
for (int y = 0; y < bitmap.getHeight(); y++)
{
for (int x = 0; x < bitmap.getWidth(); x++)
{
Color c = bitmap.getPixel(x, y);
pixelCount++;
redBucket += Color.red(c);
greenBucket += Color.green(c);
blueBucket += Color.blue(c);
// does alpha matter?
}
}
Color averageColor = Color.rgb(redBucket / pixelCount,
greenBucket / pixelCount,
blueBucket / pixelCount);
How to calculate the average color of a UIImage?
You'll need to use the Accelerate Library, Apple has a manual with some sample code, it'll work in Swift or ObjC
Here is a sample to get you going, I use this to calculate a person's heart rate and heart rate variability using the change in colors of a finger over the camera lens.
Full code here:
https://github.com/timestocome/SwiftHeartRate/blob/master/Swift%20Pulse%20Reader/ViewController.swift
It's in an older version of Swift but I think you'll get the idea. I was doing this at 240 fps, but with a cropped smaller section of the image.
Relevant code here:
// compute the brightness for reg, green, blue and total
// pull out color values from pixels --- image is BGRA
var greenVector:[Float] = Array(count: numberOfPixels, repeatedValue: 0.0)
var blueVector:[Float] = Array(count: numberOfPixels, repeatedValue: 0.0)
var redVector:[Float] = Array(count: numberOfPixels, repeatedValue: 0.0)
vDSP_vfltu8(dataBuffer, 4, &blueVector, 1, vDSP_Length(numberOfPixels))
vDSP_vfltu8(dataBuffer+1, 4, &greenVector, 1, vDSP_Length(numberOfPixels))
vDSP_vfltu8(dataBuffer+2, 4, &redVector, 1, vDSP_Length(numberOfPixels))
// compute average per color
var redAverage:Float = 0.0
var blueAverage:Float = 0.0
var greenAverage:Float = 0.0
vDSP_meamgv(&redVector, 1, &redAverage, vDSP_Length(numberOfPixels))
vDSP_meamgv(&greenVector, 1, &greenAverage, vDSP_Length(numberOfPixels))
vDSP_meamgv(&blueVector, 1, &blueAverage, vDSP_Length(numberOfPixels))
// convert to HSV ( hue, saturation, value )
// this gives faster, more accurate answer
var hue: CGFloat = 0.0
var saturation: CGFloat = 0.0
var brightness: CGFloat = 0.0
var alpha: CGFloat = 1.0
var color: UIColor = UIColor(red: CGFloat(redAverage/255.0), green: CGFloat(greenAverage/255.0), blue: CGFloat(blueAverage/255.0), alpha: alpha)
color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
// 5 count rolling average
let currentHueAverage = hue/movingAverageCount
movingAverageArray.removeAtIndex(0)
movingAverageArray.append(currentHueAverage)
let movingAverage = movingAverageArray[0] + movingAverageArray[1] + movingAverageArray[2] + movingAverageArray[3] + movingAverageArray[4]
Python - average color of part of an image
As your region of interest (ROI) is only a simple rectangle, I think you just want to use Numpy slicing to identify it.
So, I have made a test image that is green where you want to measure:
Then the code would go like this:
import cv2
import numpy as np
# Load the image
im = cv2.imread('start.png')
# Calculate mean of green area
A = np.mean(im[600:640, 20:620], axis=(0,1))
That gets green, unsurprisingly:
array([ 0., 255., 0.])
Now include some of the black area above the green to reduce the mean "greenness"
B = np.mean(im[500:640, 20:620], axis=(0,1))
That gives... "a bit less green":
aarray([ 0. , 72.85714286, 0. ])
The full sampling of every pixel in the green area takes 214 microsecs on my Mac, as follows:
IIn [5]: %timeit A = np.mean(im[600:640, 20:620], axis=(0,1))
214 µs ± 150 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Note that you could almost certainly sample every 4th pixel down and every 4th pixel across as follows in 50.6 microseconds and still get a very indicative result:
In [11]: %timeit A = np.mean(im[500:640:4, 20:620:4], axis=(0,1))
50.6 µs ± 29.3 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
You can make every pixel you are sampling into a red dot like this - look carefully:
im[600:640:4, 20:620:4] = [255,0,0]
As suggested by Fred (@fmw42), it is even faster if you replace np.mean()
with cv2.mean()
:
So, 11.4 microseconds with cv2.mean()
versus 214 microseconds with np.mean()
:
In [22]: %timeit cv2.mean(im[600:640, 20:620])
11.4 µs ± 11.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
And 7.85 microseconds with cv2.mean()
versus 50.6 microseconds with np.mean()
if sampling every 4th pixel:
In [23]: %timeit cv2.mean(im[600:640:4, 20:620:4])
7.85 µs ± 6.42 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Related Topics
Check If Current User Is Administrator in Wordpress
Passing JavaScript Variables to PHP
Tracking Email with PHP and Image
Phpunit Best Practices to Organize Tests
How to Work with Many-To-Many Relations in Yii2
Ajax/PHP - How to Get Posted Data to Load into a Modal on the Same Page
How to Check If an Entered Value Is Currency
Preserve and Display Text Exactly How It Is Typed and Submitted
PHP Method="Post" Stopped Working After I Added This .Htaccess... Why
PHP Adds Keys to Decoded and Then Encoded JSON Data
Check If a "Run-Time" Multidimensional Array Key Exists
Orm/Dao/Datamapper/Activerecord/Tablegateway Differences
How to Design a Hierarchical Role Based Access Control System
How to Load a PHP File into a Variable
Minimum Cart Amount for Specific Product Categories in Woocommerce