How to obtain N darkest colors, N brightest colors, and N most used colors from an image

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
abduct
Posts: 20
Joined: 2016-03-22T17:07:45-07:00
Authentication code: 1151

How to obtain N darkest colors, N brightest colors, and N most used colors from an image

Post by abduct »

Hi, I am trying to pull colors from an image (desktop backgrounds) to create an automated project for theming an application. Here is a testing image which has easy colors to pull from (lots of dark, medium and bright colors): http://i.imgur.com/5Wvr0xU.jpg

I would like to be able to fetch 1-N dark colors, 1-N bright colors, and 1-N most used colors from an image. I can use these as lowlights, highlights, and generic other colors in my theming process.

What I've tried already is:

Code: Select all

convert 5Wvr0xU.jpg +dither -colors 5 -define histogram:unique-colors=true -format "%c" histogram:info:
    875250: ( 27, 21, 44) #1B152C srgb(27,21,44)
    320626: ( 75, 46, 77) #4B2E4D srgb(75,46,77)
    427105: ( 93,  7, 47) #5D072F srgb(93,7,47)
    379734: (187, 35, 68) #BB2344 srgb(187,35,68)
     70885: (237,159,144) #ED9F90 srgb(237,159,144)
Which gives me the 5 most used colors along with the number of times they were used, but it gives no distinction between dark and bright colors (for instance, browns, blacks, and dark greys would be dark colors while pinks, reds, and the like may be bright colors).

Another solution I've tried was:

Code: Select all

convert 5Wvr0xU.jpg -scale 1x1\! -format '%[pixel:u]' info:-
srgb(86,29,57)
Which gives me the average color of the whole image if I understand it right. Which is good, but I need multiple colors of dark/light as explained above.

So is it possible for imagemagick to distinguish between dark colors and light colors from an image and return them in hex format for usage using separate function calls? I would like to only get the dark colors, then only get the light colors, then only get the generic colors per call to imagemagick.

Thanks.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: How to obtain N darkest colors, N brightest colors, and N most used colors from an image

Post by fmw42 »

to get the darkest and lightest colors, convert your image to HSL or HSI, get the histogram, then extract only the color values from the parenthesis and sort on the 3rd value (L or I). Then get the number of values you want and convert back to rgb.

Perhaps my script, spectrumhist, at the link below will help.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to obtain N darkest colors, N brightest colors, and N most used colors from an image

Post by snibgo »

As Fred says, although you might prefer the L channel of either CIELab or HCL.

Your test image has 2m pixels and 219,053 colours, so the "most common" colours may not be a meaningful statistic. You might first reduce the number of colours. "-colors X" would do the job, but you probably don't want colours that are close to each other, and "-posterize X" may be more suitable.
snibgo's IM pages: im.snibgo.com
abduct
Posts: 20
Joined: 2016-03-22T17:07:45-07:00
Authentication code: 1151

Re: How to obtain N darkest colors, N brightest colors, and N most used colors from an image

Post by abduct »

fmw42 wrote:to get the darkest and lightest colors, convert your image to HSL or HSI, get the histogram, then extract only the color values from the parenthesis and sort on the 3rd value (L or I). Then get the number of values you want and convert back to rgb.

Perhaps my script, spectrumhist, at the link below will help.
Thank's I took a look at your script (or rather the examples, since I couldn't make heads or tails of your bashfu) and it looks like what I may be after is the output of your "-t spectrum -s lum" option. I could sort and parse the output myself in my application. If you could provide the command line flags needed to get this output I'd be grateful.

I think if I use the -color option and set it to say, 10 as well as using your sorted "-t spectrum -s lum" command line, that would give me 1-3 being the dark colors, 4-7 being the medium colors, and 8-10 being the highlights of the image.

Could someone expand more on converting the image to CIELab, HSL or HSI? As well as the difference between -color and -posterize? I am not familiar with the terms or the advanced features of convert.

Edit:: Playing with your spectrumhist script the output of something like

Code: Select all

./spectrumhist -c 6 -t spectrum -s lum 
Is exactly what I would be looking for, but I need the hex color codes from this data rather than outputting the spectrum as an image. The output allows me to have 2 low lights, 2 mediums, and 2 highlights all the while easily scaling if I need more colors.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to obtain N darkest colors, N brightest colors, and N most used colors from an image

Post by snibgo »

For command options, see http://www.imagemagick.org/script/comma ... #posterize etc.

"-colors" quantizes to an optimum set of colors. "-posterize" quantizes to a pre-determined set of colours that are evenly spread throughout the colour cube. In my view, it gives better answers to the question "What are the most frequent colours in this photograph?"

To convert to a colorspace such as CIELab, use "-colorspace CIELab".

CIELab and HCL use a more human definition of Lightness than HSL or HSI.
snibgo's IM pages: im.snibgo.com
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: How to obtain N darkest colors, N brightest colors, and N most used colors from an image

Post by fmw42 »

try

Code: Select all

spectrumhist -c 6 -t spectrum -s lum yourimage miff:- | \
convert - txt: | tail -n +2 | sed 's/^[ ]*//' | sed 's/[ ][ ]*/ /g' | cut -d\  -f3
abduct
Posts: 20
Joined: 2016-03-22T17:07:45-07:00
Authentication code: 1151

Re: How to obtain N darkest colors, N brightest colors, and N most used colors from an image

Post by abduct »

fmw42 wrote:try

Code: Select all

spectrumhist -c 6 -t spectrum -s lum yourimage miff:- | \
convert - txt: | tail -n +2 | sed 's/^[ ]*//' | sed 's/[ ][ ]*/ /g' | cut -d\  -f3
I am not familiar with the 6 byte colors that it is out puting. Is there a way to convert it to 3 byte (#000000) hex codes? Also the list was no deduped.

I can parse the list manually after the convert command, but I am not sure how to work with those longer hex color codes. I'd also like to not have to include your script with the project, just for users convince.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: How to obtain N darkest colors, N brightest colors, and N most used colors from an image

Post by fmw42 »

Does this work:

Code: Select all

spectrumhist -c 6 -t spectrum -s lum yourimage miff:- | \
convert - -depth 8 txt: | tail -n +2 | sed 's/^[ ]*//' | sed 's/[ ][ ]*/ /g' | cut -d\  -f3 | sort -d -u
or better

Code: Select all

spectrumhist -c 6 -t spectrum -s lum yourimage miff:- | \
convert - -depth 8 -crop x1+0+0 +repage txt: | tail -n +2 | sed 's/^[ ]*//' | sed 's/[ ][ ]*/ /g' | cut -d\  -f3

But your color reduction -c 6 is going to give you only 6 colors and not the 6 darkest colors. All this is doing is sorting your 6 colors by luminosity.

So perhaps you really want

Code: Select all

spectrumhist -c 256 -t spectrum -s lum yourimage miff:- | \
convert - -depth 8 -crop x1+0+0 +repage txt: | tail -n +2 | sed 's/^[ ]*//' | sed 's/[ ][ ]*/ /g' | cut -d\  -f3 | head -n 6

which are the 6 darkest values out of 256.
abduct
Posts: 20
Joined: 2016-03-22T17:07:45-07:00
Authentication code: 1151

Re: How to obtain N darkest colors, N brightest colors, and N most used colors from an image

Post by abduct »

fmw42 wrote:Does this work:

Code: Select all

spectrumhist -c 6 -t spectrum -s lum yourimage miff:- | \
convert - -depth 8 txt: | tail -n +2 | sed 's/^[ ]*//' | sed 's/[ ][ ]*/ /g' | cut -d\  -f3 | sort -d -u
Yes that works fine now thanks!

After a bit of digging and peeking into your script, I hacked together a one liner that I can run from inside my project:

Code: Select all

convert $(convert 5Wvr0xU.jpg +dither -colors 6 -depth 8 +repage -format %c histogram:info:- | sed -n 's/^.*: \(.*\) #.*$/\1/p' | tr -cs "0-9\n" " " | sed -n 's/^ *//p' | sed -n 's/ *$//p' | awk '{ i=NR; red[i]=$1; grn[i]=$2; blu[i]=$3; } END { for (i=1; i<=NR; i++) { lum[i]=int(0.29900*red[i]+0.58700*grn[i]+0.11400*blu[i]); print red[i], grn[i], blu[i], lum[i]; } } ' 2>/dev/null | sort -n -k 4,4 | awk '{ list=""; i=NR; red[i]=$1; grn[i]=$2; blu[i]=$3; } END { for (i=1; i<=NR; i++) { list=(list "\ " "xc:rgb("red[i]","grn[i]","blu[i]")"); }{ print list; } } ' 2>/dev/null) +append "miff:-" | convert - -depth 8 txt: | tail -n +2 | sed 's/^[ ]*//' | sed 's/[ ][ ]*/ /g' | cut -d\  -f3 | sort -d -u
output:

Code: Select all

#121427
#291833
#4B2E4D
#5D072F
#BB2344
#ED9F90
I modified it a little to fix a few things, such as the removal of the -size parameter as it is no longer needed, and appending all warnings/errors from awk to /dev/null as to not confuse my application.

If you see anything wrong with my butchered version of your script then be free to correct it. Although as of right now it seems to be working exactly as I've envisioned.

Thanks for the help and example scripts fmw42. I will remember to link back to your website when I release it to give you credit.
Last edited by abduct on 2016-03-26T18:38:03-07:00, edited 3 times in total.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: How to obtain N darkest colors, N brightest colors, and N most used colors from an image

Post by fmw42 »

You are only getting 6 colors, because you set -colors 6. That was why I suggested above to use -colors 256 and then head -n 6 to keep the 6 darkest pixels out of 256
abduct
Posts: 20
Joined: 2016-03-22T17:07:45-07:00
Authentication code: 1151

Re: How to obtain N darkest colors, N brightest colors, and N most used colors from an image

Post by abduct »

fmw42 wrote:You are only getting 6 colors, because you set -colors 6. That was why I suggested above to use -colors 256 and then head -n 6 to keep the 6 darkest pixels out of 256
Yea I realized that right after I made the edit. I can do that or simply divide the returned result into 3 groups no matter which color sample I used within my application.

Thanks again for the help.
Post Reply