15

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

A = Import["https://i.stack.imgur.com/1bV4O.png"]

my image

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

colorized image

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!

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
DarrenM
  • 207
  • 1
  • 5

3 Answers3

14

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[DataPaclets`ColorDataDump`colorSchemes, "AvocadoColors", Infinity]
(* Out: {{141, 1, 1}} *)

So the colors are given by

List @@@ DataPaclets`ColorDataDump`colorSchemes[[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]
C. E.
  • 70,533
  • 6
  • 140
  • 264
13

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.stack.imgur.com/1bV4O.png"];
rimg = ImageMultiply[img, 0];
gimg = ImageMultiply[img, 1];
bimg = ImageMultiply[img, 0];
ColorCombine[{rimg, gimg, bimg}]

enter image description here

bill s
  • 68,936
  • 4
  • 101
  • 191
7

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[
                   Thread[\[FormalX] < ArrayPad[DeleteDuplicates[sg], -1]], 
                   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"];
Image[myAvocadoColors[ImageData[img]]]

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.

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574