9
$\begingroup$

is there a faster way to change the colors of an image from grayscale to something like this:

Manipulate[coltest2 = (Blend[{{a, Black}, {b, Lighter[Blue, 0.3]}, {c,Lighter[Cyan,0.3]}, {d, White}}, #] &);
Plot[0.2, {x, 0, 1}, ColorFunction -> coltest2, PlotStyle -> Directive[Thickness[1]], PlotRange -> {{0, 1}, {0, 0.5}}, Frame -> True, FrameTicks -> {True, False, None, None}, AspectRatio -> 1/8],
{{a, 0.35}, 0, b, Appearance -> "Labeled"},
{{b, 0.58}, 0, c, Appearance -> "Labeled"},
{{c, 0.7}, 0, d, Appearance -> "Labeled"},
{{d, 0.95}, 0, 1, Appearance -> "Labeled"}]

than using:

Colorize[image,ColorFunction->coltest2]

I would like to have the image in the manipulate rather than the sample of the ColorFunction, but Colorize is way to slow for that...

$\endgroup$
  • 1
    $\begingroup$ When the colours you use are fixed for this manipulate, you could create a compiled function which does the blending. This should be fast enough. How big are the images you want to use? $\endgroup$ – halirutan Jan 7 '15 at 10:39
  • $\begingroup$ The images are 1000 x 1000 px, I want to manipulate the blending parameters of the colorfunction, so the colors themselves are fixed. $\endgroup$ – DJJ Jan 7 '15 at 11:50
  • $\begingroup$ How do I create a compiled function to replace colorize? (I hope I got this right - this is the idea?) $\endgroup$ – DJJ Jan 7 '15 at 13:19
9
$\begingroup$

What you can do is, you mimic the behaviour of Blend by creating a function that interpolates linearly between colours. What you change with your parameters are the values where the color transitions take place.

Let me give you a simplified example: I use 3 colours. In the compiled function, I only work with their {r,g,b} values. As result, I want a compiled function which does the following:

  • it takes a parameter a between 0 and 1 and a pixel value between 0 and 1
  • with 3 colours c1, c2 and c3 it will colorise the pixel: from a pixel value of 0 to a it will be colorised with the transition c1 to c2. If the pixel value is greater than a it will be colorised by blending c2 and c3.
  • the compiled function should be able to work in parallel on all pixels of an image

Here is a sample implementation of a function that creates such a colorising compiled function for us:

createColorFunc[colors : {_, _, _}] :=
 Function[{c1, c2, c3},
   Compile[{{a, _Real, 0}, {value, _Real, 0}},
    If[value < a,
     c1 + ((-c1 + c2)*value)/a,
     (c3*(a - value) + c2*(-1 + value))/(-1 + a)
     ], Parallelization -> True, RuntimeAttributes -> {Listable}
    ]
   ] @@ List @@@ (ColorConvert[#, "RGB"] & /@ colors)

To test is, we load the Lena image in grayscale an build a small Manipulate:

With[{lena = ColorConvert[ExampleData[{"TestImage", "Lena"}], "Grayscale"]},
 Manipulate[
  func = createColorFunc[{c1, c2, c3}];
  Image[func[a, ImageData[lena, "Real"]]],
  {{a, .5}, 0, 1},
  {c1, Black},
  {c2, Gray},
  {c3, White}
  ]
 ]

Mathematica graphics

You task is now to extend this for more than 3 colours and one color transition position.

$\endgroup$
  • $\begingroup$ Wow great, thanks a lot! It even has more interactivity than needed, because I will use it with fixed colors. $\endgroup$ – DJJ Jan 7 '15 at 14:17
  • $\begingroup$ @DJJ I think this is what you're looking for: mathematica.stackexchange.com/a/67217/5 The question might even be a duplicate. $\endgroup$ – rm -rf Jan 7 '15 at 15:33
  • $\begingroup$ Is there some reason to prefer Image[ f[ ImageData[image ] ]] over ImageApply[f,image] ? $\endgroup$ – george2079 Jan 7 '15 at 15:53
  • $\begingroup$ It worked out fine, thanks again. @rm-rf: I think it is not the same question, though it is clearly related. $\endgroup$ – DJJ Jan 7 '15 at 16:18
  • 1
    $\begingroup$ follow up: ImageApply[ func[a, #] & , lena ] works ok but is a good bit slower. Also I think pre extracting the imagedata improves this somewhat ( With[{ idata = ImageData[lena, "Real"] , .... Image[func[a, idata]] .. $\endgroup$ – george2079 Jan 7 '15 at 18:17
4
$\begingroup$

While not as fast as halirutan's compiled function, Mr.Wizard's renderImage function (from this question) can be used here with reasonable performance:

renderImage[array_?MatrixQ, cf_, opts : OptionsPattern[Image]] := 
 Module[{tbl}, 
  tbl = List @@@ Array[cf[#/2047`] &, 2048, 0] // N // Developer`ToPackedArray;
  Image[tbl[[# + 1]] & /@ Round[2047 array], opts]]

img = ImageData @ ColorConvert[ExampleData[{"TestImage", "Lena"}], "Grayscale"];

Manipulate[
 coltest2 = (Blend[{{a, Black}, {b, Lighter[Blue, 0.3]}, {c, Lighter[Cyan, 0.3]}, {d, White}}, #] &);
 renderImage[img, coltest2],
 {{a, 0.35}, 0, b, Appearance -> "Labeled"},
 {{b, 0.58}, 0, c, Appearance -> "Labeled"},
 {{c, 0.7}, 0, d, Appearance -> "Labeled"},
 {{d, 0.95}, 0, 1, Appearance -> "Labeled"}]
$\endgroup$

Not the answer you're looking for? Browse other questions tagged or ask your own question.