Algorithm design: image quantization for brightest colors

So, I am working to extract the dominant colors perceived by people from the image.

As an example, here's a photo: https://500px.com/photo/63897015/looking-out-for-her-kittens-by-daniel-paulsson

Most people will think the "dominant" color is the penetrating blue of the eyes. However, using standard quantization, blue disappears completely when you drop below 16 colors or so. The eyes only take up 0.2% of the canvas, so switching to middle doesn't work at all.

Details of the project . I am building a Rails application that will take an uploaded photo or a specific color and return a bunch of other photos with similar dominant colors. The tool will be used by designers to find a photograph that matches their pre-existing color scheme. There are other interesting ideas I have, if I can get the technical bit sorted out.

Ongoing research . For the last 24 hours I have read all about it. Of all the services I've tried, TinEye is the only one doing it right, but they are closed. I cannot provide more than 1 link, but you can find "TinEye Color" on Google.

Tools used . I am using ImageMagick to transform images and generate histograms.

Desired result . In submitting this photo, I would like to create a palette of 5-6 colors, with this rich azure being one of them.

The current method . The way I do it now, I reduce it to 32 or 64 colors and looked for saturation / hues. If the standard deviation is low and the outlier is far away, I'll add it to the palette. Then I will reduce the photo to 4 colors and combine them for a 5-6 color palette.

My question . My problem is with ImageMagick's quantization algorithm. I don't want to take the average of the colors, I want to group them with the same colors and render the median using saturated colors. When I reduce the cat to 32 colors, the eyes turn to a desaturated gray.

So, I ask you guys if you know any algorithm or color principle that will allow me to find the colors that stand out from the image without blurring them together. I want a color that is actually in the image, not a blurry average of 4-5 colors.

More generally, TinEye did an excellent job and I would like to find out how they did it.

+3


source to share


2 answers


You say the "dominant" color is the "piercing blue of the eye".

You also say that as a result, you want rich azure to be one of the 5-6 colors in your extracted palette.

Finally, you want "the color that is actually in the image, not the blurry average of 4-5 colors together."

To start solving this problem, I first tried to find the exact definition of the color by "piercing the blue of the eye".

But here I am already stuck: this insightful azure is already a mixture of at least 20 different shades of blue! See here an image with a cropped cat's eye at a zoom level of 1000%:

"Piercing blue eye", at 1000% zoom

So which one do you want? So what if the best blue match that you imagine at the end is the "blurry average" of several colors being combined and doesn't even appear once in the original image ?!


Update

Here's my first shot ...



1. Use -posterize 8

to switch to fewer colors

convert 2048.jpg -posterize 8 posterized-8.png

      

Here is the cat's eye when posterized and enlarged by 1000%:

Posterized blue eye at 1000% zoom

2. Create a text "histogram" describing the 12 most commonly used colors after posterization

convert              \
   posterized-8.png  \
  -format %c         \
  -colorspace lab    \
  -colors 12         \
   histogram:info:-  | sort -n -r

  850708: (172,171,171) #ACABAB srgb(172,171,171)
  370610: (219,219,226) #DBDBE2 srgb(219,219,226)
  262870: (218,201,183) #DAC9B7 srgb(218,201,183)
  162588: (182,182,219) #B6B6DB srgb(182,182,219)
  161739: (182,219,219) #B6DBDB srgb(182,219,219)
  115671: ( 92, 87, 87) #5C5757 srgb(92,87,87)
  102337: (146,109,109) #926D6D srgb(146,109,109)
   86318: ( 67, 46, 46) #432E2E srgb(67,46,46)
   82882: ( 22, 20, 21) #161415 srgb(22,20,21)
   66221: (109,139,154) #6D8B9A srgb(109,139,154)
   58403: (146,146,109) #92926D srgb(146,146,109)
   38949: ( 97,109,146) #616D92 srgb(97,109,146)

      

3. Use the 12 most commonly used colors to create a palette patch strip:

convert      \
   -size 100x100 \
    xc:"srgb(172,171,171)" \
    xc:"srgb(219,219,226)" \
    xc:"srgb(134,119,120)" \
    xc:"srgb(182,182,219)" \
    xc:"srgb(182,219,219)" \
    xc:"srgb(92,87,87)" \
    xc:"srgb(146,109,109)" \
    xc:"srgb(67,46,46)" \
    xc:"srgb(22,20,21)" \
    xc:"srgb(109,139,154)" \
    xc:"srgb(146,146,109)" \
    xc:"srgb(97,109,146)" \
   +append \
    palette.png

      

This is what the palette looks like (it skips colors from a very bright spot in the eye):

Palette of 12 most frequently used colors from posterized image

+2


source


Here is the initial thought ... I, or someone else, can develop it further. Your statement was motivated by the fact that you want to maintain rich colors.

First, remove all black and white photos from the photo as they are desaturated. Then convert to HSL color space and extract the saturation channel. Contrast stretches the saturation to its full range and then uses it as a mask when applying ImageMagick's color quantization algorithms.



convert cat.png -fuzz 20% -fill black \
    -opaque white                     \
    -opaque black                     \
    -colorspace HSL -channel S -separate -contrast-stretch 0.1% out.png

      

enter image description here

+1


source







All Articles