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$

3 Answers 3

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, 2018 at 10:58
  • 1
    $\begingroup$ Your code seems simplest and fastest. $\endgroup$ May 4, 2018 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, 2018 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 and acknowledge you have read our privacy policy.

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