NHacker Next
  • new
  • past
  • show
  • ask
  • show
  • jobs
  • submit
Okmain: How to pick an OK main colour of an image (dgroshev.com)
useftmly 6 minutes ago [-]
The performance concern is real but there's another footgun that surprises people in practice: images with large white or transparent backgrounds — product photos on e-commerce sites are the classic case — where the dominant color ends up being white or near-white, which is useless for any branding or UI purpose.

The fix that works best is to either filter out near-white and near-black pixels before the clustering step, or to look at the distribution tail rather than the mode. The most visually interesting color in an image is often not the most frequent one — it's the one that would be chosen as an accent color by a designer. That's a harder problem than it looks because 'visually interesting' is partly about contrast and saturation relative to the rest of the palette.

bee_rider 1 hours ago [-]
I’m surprised the baseline to compare against is shrinking the image to one pixel, that seems extremely hacky and very dependent on what your image editor happens to do (and also seems quite wasteful… the rescaling operation must be doing a lot of extra pointless work keeping track of the position of pixels that are all ultimately going to be collapsed to one point).

So, making a library that provides an alternative is a great service to the world, haha.

An additional feature that might be nice: the most prominent colors seem like they might be a bad pick in some cases, if you want the important part of the image to stand out. Maybe a color that is the close (in the color space) to the edges of your image, but far away (in the color space) from the center of your image could be interesting?

mungoman2 47 minutes ago [-]
Tbh shrinking the image is probably the cheapest operation you can do that still lets every pixel influence the result. It’s just the average of all pixels, after suitable color conversion.
bombcar 40 minutes ago [-]
It might work decently well, but I wonder if it makes it "visually" match - sometimes the perfect average is not what our eyes see as the color.
llimllib 2 hours ago [-]
OKPalette by David Aerne is my favorite tool for this, it chooses points sensibly but then also lets you drag around or change the number of colors you want: https://okpalette.color.pizza/
iamcalledrob 2 hours ago [-]
As a designer, I've built variants of this several times throughout my career.

The author's approach is really good, and he hits on pretty much all the problems that arise from more naive approaches. In particular, using a perceptual colorspace, and how the most representative colour may not be the one that appears the most.

However, image processing makes my neck tingle because there are a lot of footguns. PNG bombs, anyone? I feel like any library needs to either be defensively programmed or explicit in its documentation.

The README says "Finding main colors of a reasonably sized image takes about 100ms" -- that's way too slow. I bet the operation takes a few hundred MB of RAM too.

For anyone that uses this, scale down your images substantially first, or only sample every N pixels. Avoid loading the whole thing into memory if possible, unless this handled serially by a job queue of some sort.

You can operate this kind of algorithm much faster and with less RAM usage on a small thumbnail than you would on a large input image. This makes performance concerns less of an issue. And prevents a whole class of OOM DoS vulnerabilities!

As a defensive step, I'd add something like this https://github.com/iamcalledrob/saferimg/blob/master/asset/p... to your test suite and see what happens.

chrisweekly 25 seconds ago [-]
your gh link returned 404
jaen 2 hours ago [-]
I really wish people would read the article, the library does exactly this:

> Okmain downsamples the image by a power of two until the total number of pixels is below 250,000.

iamcalledrob 1 hours ago [-]
Somehow I missed that, oops. I see that the library samples a maximum of 250K pixels from the input buffer (I jumped over to the project readme)

That being said, this is sampling the fixed-size input buffer for the purposes of determining the right colour. You still have to load the bitmap into memory, with all the associated footguns that arise there. The library just isn't making it worse :) I suppose you could memmap it.

Makes me wonder if the sub-sampling is actually a bit of a red herring, as ideally you'd want to be operating on a small input buffer anyway. Or some sort of interface on top of the raw pixel data, so you can load what's needed on-demand.

vasco 2 hours ago [-]
That's 500x500, I'm sure you can get good results at 32x32 or 64x64 but then part of your color choice is also getting done by the downsampling algorithm. I wonder if you could get away with just using a downsampling algorithm into a 1x1 and just use that as the main color.
PaulHoule 1 hours ago [-]
That last one is talked about in the article -- it sucks!

I think if you were going to "downsample" for the purpose of creating a color set you could just scan through the picture and randomly select 10% (or whatever) of the pixels and apply k-means to that and not do any averaging which costs resources and makes your colors muddy.

dgroshev 30 minutes ago [-]
Random sampling makes a lot of intuitive sense, but unfortunately doesn't work well. I just answered over at lobsters: https://lobste.rs/s/t43mh5/okmain_you_have_image_you_want_co...

I should probably add this nuance to the post itself.

Edit: added a footnote

dgroshev 9 minutes ago [-]
Author here: the library just accepts RGB8 bitmaps, probably coming either from Rust's image crate [1] or Python's Pillow [2], which are both mature and widely used. Dealing with codecs is way out of scope.

As for loading into memory at once: I suppose I could integrate with something like libvips and stream strips out of the decoded image without holding the entire bitmap, but that'd require substantially more glue and complexity. The current approach works fine for extracting dominant colours once to save in a database.

You're right that pre-resizing the images makes everything faster, but keep in mind that k-means still requires a pretty nontrivial amount of computation.

[1]: https://crates.io/crates/image

[2]: https://pypi.org/project/pillow/

latexr 2 hours ago [-]
> I've built variants of this several times throughout my career.

Got any to share? A self-contained command-line tool to get a good palette from an image is something I’d have a use for.

dylan604 29 minutes ago [-]
Fred's dominantcolor script for imagemagick might work for you:

https://www.fmwconcepts.com/imagemagick/dominantcolor/index....

PaulHoule 2 hours ago [-]
Back in the late 1980s people thought about color quantization a lot because a lot of computers of the time had 16 or 256 colors you could choose out of a larger palette and if you chose well you could do pretty well with photographic images.
lemonad 2 hours ago [-]
This is nice! I looked into this quite a lot some years back when I was trying to summarize IKEA catalogs using color and eventually wrote an R package if you want to look into an alternative to e.g. k-means: https://github.com/lemonad/colorhull (download https://github.com/lemonad/ikea-colors-through-time/blob/mas... for more details on how it works)
latexr 4 hours ago [-]
I’d be interested in trying this out as a command-line tool. It would be useful on its own and the fastest way to evaluate results.
jcynix 54 minutes ago [-]
ImageMagick is a wonderful command line tool, IMO. You could use it to extract various information, e.g. the 5 most used colors of an image, as in

    convert $IMG -colors 5 -depth 8 -format "%c" histogram:info: | sort -nr
If needed you can easily remove colored borders first (trim subcommand with fuzz option) or sample only xy% from the image's center, or where the main subject might be.
dgroshev 6 minutes ago [-]
Good idea, I'll add a CLI tool over the weekend.
woodrowbarlow 3 hours ago [-]
looks like it's a rust lib with a python wrapper. making a CLI tool should be just a few lines of code.
latexr 2 hours ago [-]
Yeah, but then I’d have to be working with Python (which I don’t enjoy) and be pulling in dependencies (which I avoid) to have a custom system with moving parts (Python interpreter, library, script) (which I don’t want).

A rust CLI would make a lot of sense here. Single binary.

blipvert 1 hours ago [-]
This sounds like a job for <ta-ta-ta-taaaa> contrib-directory-man!
3 hours ago [-]
2 hours ago [-]
Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact
Rendered at 15:02:05 GMT+0000 (Coordinated Universal Time) with Vercel.