Last active
February 15, 2023 16:14
-
-
Save jcupitt/ee3afcbb931b41b4d7f4 to your computer and use it in GitHub Desktop.
find dominant colour in an 8-bit RGB Image with libvips python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import sys | |
from gi.repository import Vips | |
N_BINS = 10 | |
BIN_SIZE = 256 / N_BINS | |
im = Vips.Image.new_from_file(sys.argv[1], access = Vips.Access.SEQUENTIAL) | |
# turn to lab | |
im = im.colourspace("lab") | |
# turn to 8-bit unsigned so we can make a histogram | |
# use 0 - 255 to be -128 - +127 for a/b | |
# and 0 - 255 for 0 - 100 L | |
im += [0, 128, 128] | |
im *= [255.0 / 100, 1, 1] | |
im = im.cast("uchar") | |
# make a 3D histogram of the 8-bit LAB image | |
hist = im.hist_find_ndim(bins = N_BINS) | |
# find the position of the maximum | |
v, x, y = hist.maxpos() | |
# get the pixel at (x, y) | |
pixel = hist(x, y) | |
# find the index of the max value in the pixel | |
band = pixel.index(v) | |
# scale up for the number of bins | |
x = x * BIN_SIZE + BIN_SIZE / 2 | |
y = y * BIN_SIZE + BIN_SIZE / 2 | |
band = band * BIN_SIZE + BIN_SIZE / 2 | |
# turn the index back into the LAB colour | |
L = x * (100.0 / 255) | |
a = y - 128 | |
b = band - 128 | |
print "dominant colour:" | |
print " L = ", L | |
print " a = ", a | |
print " b = ", b |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import sys | |
from gi.repository import Vips | |
im = Vips.Image.new_from_file(sys.argv[1], access = Vips.Access.SEQUENTIAL) | |
N_BINS = 10 | |
BIN_SIZE = 256 / N_BINS | |
# make a 3D histogram of the RGB image ... 10 bins in each axis | |
hist = im.hist_find_ndim(bins = N_BINS) | |
# find the position of the maximum | |
v, x, y = hist.maxpos() | |
# get the pixel at (x, y) | |
pixel = hist(x, y) | |
# find the index of the max value in the pixel | |
band = pixel.index(v) | |
print "dominant colour:" | |
print " R = ", x * BIN_SIZE + BIN_SIZE / 2 | |
print " G = ", y * BIN_SIZE + BIN_SIZE / 2 | |
print " B = ", band * BIN_SIZE + BIN_SIZE / 2 |
From https://github.com/jcupitt/libvips/issues/259#issuecomment-214658553
import gi
gi.require_version('Vips', '8.0')
from gi.repository import Vips
value = [50, 2, 2]
from_space = "lab"
to_space = "srgb"
# make a 1x1 pixel image, tag as being in the source colourspace
pixel = Vips.Image.black(1, 1) + value
pixel = pixel.copy(interpretation = from_space)
# transform to dest space
pixel = pixel.colourspace(to_space)
# pull out the pixel from coordinate (0, 0) as an array
new_value = pixel(0, 0)
print(from_space, " ", value)
print(to_space, " ", new_value)`
Hi, @jcupitt, I’m messed up a little here, could you please help with getting not the most used color, but N most used colors?
Hi, you can use the size
flag to max
to get it to find the N largest values.
@jcupitt, I use max()
, but it returns a single result... Where could I be wrong?
const BINS = 20;
const BIN_SIZE = 256 / BINS;
const PALETTE_MAX_COLORS = 10;
// load an image, get fields, process, save
$image = Vips\Image::newFromFile($argv[1] ?? '2.jpg');
echo "width×height = {$image->width}×{$image->height}\n";
// Lab?
//$image = $image->colourspace('lab');
//$image = $image->cast('uchar');
$histogram = $image->hist_find_ndim(['bins' => BINS]);
$max = $histogram->max(['x' => true, 'y' => true, 'size' => PALETTE_MAX_COLORS]);
var_dump($max);
yields
width×height = 600×450
array(3) {
["out"]=>
float(11888)
["x"]=>
int(3)
["y"]=>
int(2)
}
You need to ask for the output array, eg.:
john@banana ~/pics $ python3
Python 3.10.7 (main, Nov 24 2022, 19:45:47) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyvips
>>> x = pyvips.Image.new_from_file("k2.jpg")
>>> x.max(size=12)
255.0
>>> x.max(size=12, out_array=True)
[255.0, {'out_array': [255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0]}]
You can get the positions of the maxima like this:
>>> x.max(size=12, out_array=True, x_array=True, y_array=True)
[255.0, {'out_array': [255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0], 'x_array': [376, 377, 378, 378, 379, 385, 386, 387, 390, 391, 391, 392], 'y_array': [2032, 2032, 2032, 2032, 2032, 2032, 2032, 2032, 2032, 2032, 2032, 2032]}]
@jcupitt, you helped a lot, I really appreciate it! Maybe we’ll continue in the discussion?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi John,
I was wondering, is there any utility function in libvips python, for converting the resulting (L,a,b) value to corresponding (R, G, B) value?