I have an image, I want to change all the colors in the image from a color map eg. {(10,20,212) : (60,40,112)...}
Currently, I am reading the image OpenCV and then iterating over the image array and changing each pixel, but this is very slow.
Is there any way I can do it faster?
I am providing two answers to this question. This answer is more based in PIL/Pillow and the other is more based in OpenCV. Read this answer in conjunction with my other answer and potentially mix and match.
You can do it using the palette. In case you are unfamiliar with palettised images, rather than having an RGB value at each pixel location, you have a simple 8-bit index into a palette of up to 256 colours.
So, what we can do, is load your image as a PIL Image, and quantise it to the set of input colours you have. Then each pixel will have the index of the colour in your map. Then just replace the palette with the colours you want to map to.
Input Image
Output Image
So, to do specifically what you asked with a dictionary that maps old colour values to new ones, you will want to initialise
oldPalette
to the keys of your dictionary andnewPalette
to the values of your dictionary.Keywords: Python, PIL, Pillow, image, image processing, quantise, quantize, specific palette, given palette, specified palette, known palette, remap, re-map, colormap, map.
There are some hopefully useful words about palettised images here, and here.
I am providing two answers to this question. This answer is more based in OpenCV and the other is more based in PIL/Pillow. Read this answer in conjunction with my other answer and potentially mix and match.
You can use Numpy's
linalg.norm()
to find the distances between colours and thenargmin()
to choose the nearest. You can then use a LUT "Look Up Table" to look up a new value based on the existing values in an image.Input Image
Output Image
Keywords: Python, PIL, Pillow, image, image processing, quantise, quantize, specific palette, given palette, specified palette, known palette, remap, re-map, colormap, map, LUT, linalg.norm.
I think you might find using the built in LUT function of opencv helpful, as documented here.
There is already a python binding for the function, and it takes as input the original matrix and a LUT, and returns the new matrix as an output.
There isn't a tutorial for using it in python, but there is one for using it in C++ which I imagine will be useful, found here. That tutorial lists this method as the fastest one for this sort of problem.