FME has now colour vision
Recently, I published RasterColorAnalyzer, a custom transformer, which maps the colours of an image to the named colours. Here, I'd like to share some details how it works "under the hood" because the idea behind the transformer can be useful for similar datasets and transformations.
FME Workbench can transform pixels of a raster
Back in 2015 when I spent a year playing #Minecraft for living, I had to solve the following problem - if we take a SketchUp model, how could we map its colours to a limited set of 16 hues available for some Minecraft blocktypes? I created a point cloud that combined all possible RGB24 combinations (24 bit per colour). The point cloud was a cube with 256 units along each side. Then, I calculated 3D distances to the 16 Minecraft RGB triads
So, the process of converting a SketchUp model to Minecraft looked as follows:
Here is an example of such a transformation:
This was a nice solution for the problem, but I never turned it into a more universal process. Until now - when our FME Evangelist Mark Ireland asked me whether it would be possible to tell what colours make a flag of a country.
I thought I could quickly implement my Minecraft workflow to work with images, but quickly realized, it wouldn't work very nicely for pale, muted, pastel tones - they may have a colour, which would be distinctively pink or green for a human eye, but fall into the gray part of my colour filter cube - just because the RGB values are close to each other. Instead, I decided to use a slightly different approach.
I found a few sources of named colours - W3C, Wikipedia list of named colours, Pantone colours (taken from hexcolor.co), and built a transformer that extracts RGB triads from images with RasterToPolygonCoercer and maps them to the closest named colour.
We can think of this method as a 3D implementation of NeighborFinder. Under the hood, it works as follows:
This is it, now we know, what is the nearest named colour to each colour of the image. I want to note here - we find the closest color, not the exact match, although sometimes, we can get such matches.
领英推荐
Have a look at this #ThreeJS visualization of the mapping. I took the photo of two macaws my family fostered for year, and applied the process described above to it. The cubes represent the colours of the images (the reduced number), the spheres - the named Wikipedia colours. The pipe connectors show the mapping. You can click on cubes to see their RGB values, and spheres to get the RGB values, names, and shades.
You may notice that some colours have pretty poetic, imaginative, but not very telling names. Do you know what do Byzantium, Flirt or Paua look like? I probably could guess the first one, but I'd be completely lost with the other two.
This is why I added a shade to each colour. I did it by scraping the Encycolorpedia.com website - I was sending requests with a hexadecimal value of the colour as a parameter, extracting the shade name from the response, and adding it to the colour name JSON inside the transformer:
If you are a fan of regular expressions
shade of <strong>([\w\s-]+)</strong>
With colours, we use 3 dimensions - one for each element of the color triad. However, this method is not limited to 3D - we can easily adopt it to 4 or more dimensions - for situations where we need to map values by more than 3 sets of values. We can't use the normal VertexCreator and LengthCalculator transformers - they are limited to 2D/3D, however, we can calculate distances between multidimensional points with AttributeCreator - all we need is to apply Pythagorean theorem:
The rest is the same. I think this is really cool.
So, this is how RasterColorAnalyzer came to life. You can try it yourself with FME or check the report I generated on the world flag colours. Maybe just one note about the report - I cannot guarantee the flags in the dataset contain accurate representations of the colours established by their respective countries.