Censor - a perceptual palette analyser

Source: https://github.com/Quickmarble/censor.
License: MIT.
Version info

Censor is a standalone command-line palette analyser inspired by DawnBringer's Palette Analyser for GrafX2 and having a compatible layout. Among numerous differences,

  • All widgets use CAM16UCS with perceptual colour distance;
  • You can load palettes from command arguments, text files, images and Lospec;
  • Daemon mode can be used for larger numbers of analysis requests;
  • There will be support for using the analyser in web pages after compiling it into WASM;
  • Palette metrics can be computed and printed without producing an image;
  • It is swift. As of 0.5.0, hyperfine benchmarks show that a 256 colour palette is processed in 64ms-on-my-machine (for comparison, the same palette is processed in 442ms-on-my-machine by DB analyser running with luajit through a shim by PureAsbestos).






You can find more detailed description and installation instructions on GitHub.

Interesting & nifty!

hi, nice job! i'd like to make few suggestions regarding vectorscope (polar hue-chroma diagram) and non-palette elements:

  1. i believe vectorscope would be more practical if it was hue-saturation. because a) digital vectorscopes work like that, b) dawnbringer's palette analyzer works like that, c) usually all painting softwares provide users with control over saturation, but not chroma, so it is rather alien concept for most. as a result it is confusing to see fully saturated yellows to be close to the center of the diagram, while one would expect them to be on the outside edge of the circle. right now it makes proper assesments about the palette balance harder.

  2. it shouldn't be rotated and mirrored compared to other diagrams (notice the location of primaries in polar hue-lightness diagrams).

  3. the skin tone line would be nice.

  4. vectorscope should show location of primaries (RYGCBM). it's hard to estimate where the colours are located in relation to primaries.
    and of course, if you don't want to change vectorscope to hue-saturation, then this is even more important feature. in that case it would actually be better to show not just primaries, but all main colours (R, O, Y, G, C, A, B, M) if not all hues separated by 30 degrees. it seems like there are areas of the disk where no colours will ever be present and users should be able to see that clearly.

  5. i recommend the background and elements which aren't part of palette itself to be presented in neutral greys - black, 50% grey and white only. having one of the palette colours to be dominant colour significantly affects the overall look of the palette and perception of its colours. for instance, one of your examples with green background creates the feeling the palette is green heavy, while the opposite is actually true.

i made a quick example here:

also, it would be neat if you could colour the lines in spectral distribution and temparature diagrams with corresponding palette entries.

@b236, thank you for the feedback!

  1. One of my primary goals was to make all the widgets as perceptual as possible. As a result, I don't want to use RGB saturation anywhere - it's perceptually misleading. Breaking possible assumptions about how colour analysing software works is fine then, I guess?
  2. Oops, I forgot to invert the Y axis there. I'll release a bugfix soon.
  3. Do you mean making the central foreground colour closer to skintones or adding a widget to show possibilities for skintones in the palette? I have some plans for analysing what materials could be depicted with the provided colours, but it'll require some time and work. Concerning the foreground colour, it's chosen automatically to be visible in context of other UI colours for an arbitrary palette. I don't see any good way of adjusting it without sacrificing some readability for certain cases.
  4. I'll think of how primary colour marks could be added while being visible even for a 256-colour palette.
    Probably I'll add a contour showing the area where the colours might be.
  5. In this example, the green was chosen as an approximation of 50% grey. It does affect the perception of the palette but I'm not sure it's bad. Well, I can add alternative UI colours as an option.

P. S. I considered making distribution lines colourful, but that'll cause problems for darker colours, such as barely visible segments. But maybe adding marks like under the rectangular lightness-hue widget will work?

hi! sorry for the late reply.

i understand. i was considering it only from practical perspective, but you make a valid point. and after all, if there are going to be marked primaries and contour line (great idea, btw.) it will show both chroma as distance from center to outline and saturation as distance from center to contour.
i don't think you have to be concerned about visibility for bigger palettes, because palettes like this: https://raw.githubusercontent.com/Quickmarble/censor/master/examples/aurora.png basically show everything by themselves. but i guess primaries can be marked also like this:

skin tone line: there's a line (often marked as -I) in vectorscopes which shows approximate location of skin tones. of course, it works only for normal light conditions, but generally it is very useful for colour grading. i couldn't find any technical specification for that, so i can post only how it looks like:


alternative UI with greys would be great option.

PS: you're right about visibility of darker colours, your solution sounds better.

btw. i just got confused by spectral distribution graph, could you please explain it to me? i assumed that 4100 - 6650 range is in Kelvins, but that doesn't seem right.

Yeah, marking hues could be ok.

I'll test some skin tones and add the line.

Alternative UI colours are already added (the -g flag).

The range of wavelengths in spectral distribution is currently 4100-6650 angstroms (in other words, 410-665 nm).
It was supposed to be wider, but I had issues in the 0.1 version (which was in Python) with computing CIExy hues because XYZ values were near-zero and lack of precision made the hue function outside of those boundaries non-monotone. I'll test if switching to f64 in Rust will allow to expand it again.

i see, thank you very much!

I sampled some colours from an image of von Luschan's chromatic scale and here's the result:
plot (19).png
Looking at the plots, I doubt that there can be a vectorscope-like line for skin tones: the range of hues is at least 60°.
I could still add a curve approximating skin colours, but it seems it won't be visible for most palettes because of low chroma.

@quickmarble thanks for the test! i wouldn't rely on von luschan's work as it is quite old, but yeah, the skin tone line is just an approximation (i believe it is cca 15 degrees, but i don't know for sure) so there's always going to be some spread:
anyway, it was just an idea, i don't think it is crucial to be included.

How did you make this? Was it hard?

@pixel-potter, if you mean the program, it wasn't very hard (and I already had the 0.1 version written in Python). As you can see from the source code, it's quite straightforward. XYZ to CAM16UCS conversion is one of less trivial parts, but I just followed the algorithm from the CAM16 paper. A couple of metrics/distributions used are described in other threads of this forum section.

@quickmarble That's really cool!

@b236, the contour and RGB primaries are now added.

@quickmarble amazing! thank you!

0.4 update: daemon command parser is upgraded, now it's using the same library as for the command-line interface. In particular, it means that it can finally do ~everything the command-line app could.

Nice job!
It seems a visual studio installation is needed, at least it didn't work for me without one, but the note after the installation error referred to it thankfully. Maybe you can include that into the Readme?

Restrictions summon creativity!

@marcomics, thank you!
I checked this, and Visual Studio Build Tools are indeed required for Windows installation of Rust toolchain with default options. I'll add a note into readme.

Probably I should start generating binary releases for all platforms at some point.

Having observed your palette, I decided there should be an additional mode where a big (like 1280x1280) gif would be generated, showing slowly rotating 3D CAM16UCS representation with the important graph structure of the palette (ramps and cycles).
But there're some other things I need to do before that.

Sounds great! But maybe add GIF only as an additional option, PNG should stay the main output (Does the lospec forum support GIFs yet?).

Restrictions summon creativity!

@marcomics, the analyse subcommand will stay, of course.

It should support all common image formats, I think.

0.5 update: added experimental multithreaded mode (-j).

Experimental because it's currently 8% slower than singlethreaded for some reason.