# How to speed up Colorize

I have a list of about 500 images similar to the following:

A = Import["https://i.sstatic.net/1bV4O.png"]


AbsoluteTiming[Colorize[A, ColorFunction -> "AvocadoColors"]]


takes ~ 0.6 seconds, which scales to around 5 minutes for applying the Colorize function to my list of 500 images.

In other programs, this general feature of mapping grayscale values to colors is quite fast. I'd like to find a way to speed this up if possible. Thanks!

• Question 71310 is closely related. Commented May 20, 2015 at 23:50
• Although it might not save speed in terms of computation time, you might find ImageFileApply to be a useful function, especially when processing a large number of images.
– chuy
Commented May 20, 2015 at 23:55
• and finally before this get likely gets locked: Graphics[Raster[ImageData[A, DataReversed -> True], ColorFunction -> "AvocadoColors"]]
– chuy
Commented May 20, 2015 at 23:59
• Related: (21482), (71278) Commented May 21, 2015 at 7:40

It is also pretty straightforward to create your own color map. For example, the following code reads in the image, and multiplies each of the color channels by an appropriate factor, then recombines the three into a single color image. It is very fast. Change the constants (in this case, 0, 1, and 0) at will.

img = Import["https://i.sstatic.net/1bV4O.png"];
rimg = ImageMultiply[img, 0];
gimg = ImageMultiply[img, 1];
bimg = ImageMultiply[img, 0];
ColorCombine[{rimg, gimg, bimg}]


## Approach

As halirutan suggested in Apply ColorFunction to an Image, we can create a custom, compiled color function and apply it using the trick

Image[colorFunction @ ImageData @ img]


On my computer with my custom avocado color function, this is more than eight times faster than Colorize, taking only 0.035 seconds.

## How to create a fast custom color function

In order to create a faster avocado color function, we first need to find out what colors that color function is based on. Mr. Wizard explains that in his answer to Is it possible to insert new colour schemes into ColorData?.

Position[DataPacletsColorDataDumpcolorSchemes, "AvocadoColors", Infinity]
(* Out: {{141, 1, 1}} *)


So the colors are given by

List @@@ DataPacletsColorDataDumpcolorSchemes[[141, 5]]
(* Out: {{0., 0., 0.}, {0., 0.442859, 0.0749256}, {0.289326, 0.685107,
0.108759}, {0.683989, 0.830896, 0.145815}, {1., 0.984375, 0.230411}} *)


So we've got five different colors. Just like halirutan, I will do a linear interpolation between these colors which is what Blend does, which is what Colorize uses (thanks J. M. for debugging help to make it work perfectly). I'm also using the Parallelization and Listable settings like halirutan to make the function fast. I also added CompilationTarget -> "C" which improves the speed even more.

avocadoColors = Compile[value, Module[{c1, c2, c3, c4, c5},
c1 = {0., 0., 0.};
c2 = {0., 0.442859, 0.0749256};
c3 = {0.289326, 0.685107, 0.108759};
c4 = {0.683989, 0.830896, 0.145815};
c5 = {1., 0.984375, 0.230411};
Which[
value < 0.25, c1 + (c2 - c1) (value/0.25),
value < 0.5, c2 + (c3 - c2) ((value - 0.25)/0.25),
value < 0.75, c3 + (c4 - c3) ((value - 0.5)/0.25),
True, c4 + (c5 - c4) ((value - 0.75)/0.25)
]
],
Parallelization -> True,
RuntimeAttributes -> {Listable},
CompilationTarget -> "C"
]


You can now test this using

Image[avocadoColors @ ImageData @ img]

• "…even though that may not be exactly what ColorData["AvocadoColors"] does…" - Blend[] actually does linear interpolation, last time I checked, so the compiled version ought to be equivalent. Commented May 21, 2015 at 0:57
• @J.M. I added an image that compares the final result between Colorize and the custom color function. Commented May 21, 2015 at 1:14
• That darkening certainly is odd. What happens if you do Colorize[img, ColorFunction -> (RGBColor @@ avocadoColors[#] &)]? Commented May 21, 2015 at 1:32
• @J.M. That is the same as Image[avocadoColors@ImageData@img]. Commented May 21, 2015 at 2:11
• I think I understand the difference now; the increments should be 0.25 instead of 0.2; if these are changed, there should no longer be any difference. Commented May 21, 2015 at 4:44

This answer is effectively a generalization of the approach by halirutan and Pickett. Here, I present a function that when given a list of colors, a list of positions and colors, or a color gradient known to ColorData[], it yields a listable compiled function effectively equivalent to Blend[]:

makeCompiledBlend[colors : (_String | _List), opts___] :=
Module[{cl = colors, sg},
If[StringQ[cl], cl = ColorData[cl, "BlendArgument"]];
If[! ListQ[cl], Return[\$Failed]];
If[! VectorQ[cl],
{sg, cl} = Transpose[SortBy[cl, {First}]],
sg = Range[0, 1, 1/(Length[cl] - 1)]];
cl = (List @@ ColorConvert[#, RGBColor]) & /@ cl;
With[{compileBody = Which @@ Riffle[Append[
True],
With[{u = (\[FormalX] - #1)/(#2 - #1)}, {1 - u, u}.#3] & @@@
DeleteCases[Append @@@ First[
Partition[{sg, cl}, {2, 2}, 1]],
{Repeated[x_?NumericQ, {2}], __}]]},
Compile[{{\[FormalX], _Real}}, compileBody, opts,
RuntimeAttributes -> {Listable},
RuntimeOptions -> "Speed"]]]


Thus,

myAvocadoColors = makeCompiledBlend["AvocadoColors"];

should yield the expected image. I had omitted the option settings CompilationTarget -> "C", Parallelization -> True in this version, but you can add them in if you wish.