6
$\begingroup$

I would like to optimize this code

fadeAndShine[old_, new_] := If[old == new, {1, 0.8, 0.2}, new];
ImageApply[fadeAndShine, {imageA, imageB}]

Is it possible, and if yes, on what should I focus?


Applying fadeAndShine to following image takes 0.53 sec on my pc, while applying Max takes 0.31 sec.

imageA =  
  Rasterize[Graphics[Table[Circle[{x, 0}, x], {x, 1, 25}]], "Image", 
   ImageSize -> 500];
imageB =  
  Rasterize[Graphics[Table[Circle[{0.8 x, 0}, x], {x, 1, 25}]], 
   "Image", ImageSize -> 500];

I'm willing to use another functionality as long as I get same result for any pair of images.

$\endgroup$
6
$\begingroup$

Your If codition is pretty simple and can be precomputed on all pixels more efficiently to generate a composition mask

mask = Binarize[ImageDifference[imageA, imageB], 0]

mask

You can then use simple arithmetic to combine it

ImageAdd[
 ImageMultiply[ColorNegate[mask], RGBColor @@ {1, 0.8, 0.2}],
 ImageMultiply[mask, imageB]
]

composition

Putting all together

fadeAndShine2[old_, new_, color: _?ColorQ : RGBColor[1, 0.8, 0.2]] := 
With[
    {mask = Binarize[ImageDifference[old, new], 0]},
    ImageAdd[
        ImageMultiply[ColorNegate[mask], color],
        ImageMultiply[mask, new]
    ]
]
fadeAndShine2[imageA,imageB]//AbsoluteTiming//First

(* => 0.012 *)

And

MinMax[
 fadeAndShine2[imageA, imageB] - 
  ImageApply[fadeAndShine, {imageA, imageB}]]

(* => {0., 0.} *)
$\endgroup$
2
  • $\begingroup$ Very neat. (+1) $\endgroup$ May 4 '18 at 10:58
  • 1
    $\begingroup$ Your code seems simplest and fastest. $\endgroup$ May 4 '18 at 13:11
4
$\begingroup$

You can try to use compiled code and apply it to the ImageData of your images:

fadeAndShine[old_, new_] := If[old == new, {1, 0.8, 0.2}, new];

cFadeAndShine = Compile[{{old, _Real, 1}, {new, _Real, 1}},
   If[old == new, {1., 0.8, 0.2}, new],
   CompilationTarget -> "C",
   RuntimeAttributes -> {Listable},
   Parallelization -> True
   ];

And here the usage example with timings:

imageA = Rasterize[Graphics[Table[Circle[{x, 0}, x], {x, 1, 25}]], 
   "Image", ImageSize -> 500];
imageB = Rasterize[Graphics[Table[Circle[{0.8 x, 0}, x], {x, 1, 25}]],
    "Image", ImageSize -> 500];

imageC = ImageApply[fadeAndShine, {imageA, imageB}]; // 
  AbsoluteTiming // First
imageD = Image[cFadeAndShine[ImageData[imageA], ImageData[imageB]]]; //
   AbsoluteTiming // First
ImageData[imageC] - ImageData[imageD] // Abs // Max

0.355039

0.035754

0.

$\endgroup$
1
  • $\begingroup$ I actually forgot about this way. Making a Listable compiled function is indeed a very useful trick for more complex behaviours. $\endgroup$
    – Batracos
    May 4 '18 at 17:11
4
$\begingroup$
imageA=Rasterize[Graphics[Table[Circle[{x,0},x],{x,1,25}]],"Image",ImageSize->500];
imageB=Rasterize[Graphics[Table[Circle[{0.8 x,0},x],{x,1,25}]],"Image",ImageSize->500];

data1=ImageApply[Function[{old,new},If[old==new,{1.,0.8,0.2},new]],{imageA,imageB}]//
  ImageData;//AbsoluteTiming

data2=Map[With[{old=#[[{1,2,3}]],new=#[[{4,5,6}]]},If[old==new,{1.,0.8,0.2},new]]&,
  Join[ImageData[imageA],ImageData[imageB],3],{2}];//AbsoluteTiming

data3=With[{old=ImageData[imageA],new=ImageData[imageB]},
  With[{k=Unitize[new-old]},Map[{1.,0.8,0.2}#&, 1-k,{2}]+new k]];//AbsoluteTiming

data1==data2==data3

{0.637831, Null}

{0.249619, Null}

{0.0957136, Null}

True

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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