6
$\begingroup$

I have about 1000 images of 1000px $\times$ 1000px and a list which contains the coordinates of the pixels to select, for each of the 1000 images. Each pixel is used once, so the final image is a full image made of parts of all the other images.

Here is an example code for 2 images:

img1 = ImageData[Import["ExampleData/lena.tif"]];
img2 = ImageData[ColorNegate[Import["ExampleData/lena.tif"]]];
img = img1;
ptsToReplace = RandomInteger[{1, 116}, 10000] // Partition[#, 2] &;
Table[img[[Sequence @@ ptsToReplace[[i]]]] = 
   img2[[Sequence @@ ptsToReplace[[i]]]], {i, 1, 
   Length[ptsToReplace]}];
ImageAssemble[Map[Image, {img1, img2, img}]]

Below are the two images and the output on the right which is a mix of them:

enter image description here

My question is about what strategy to use:

  • Loading all the images, then converting all of them as arrays with ImageData and then building the final image by iterating on the pixel works, but is of course quickly limited by the memory as it stores everything (images + arrays).
  • I also tried to iterate on the images: for each image, get all the pixels that I will need to take, copy them to the final image, and proceed again with next image. This is OK as far as memory is concerned, but it is too slow.
  • I thought about more efficient ways such as creating mask images which would have black dots on the coordinates of the pixels which have to be used for a given image, and then multiply the images. The goal being to avoid iteration on pixels and use faster build-in functions. But I don't know how to do this efficiently (e.g. not building the mask by iterating over the pixels).

What would be an efficient technique, in both CPU and memory? I insist that the coordinates to replace (ptsToReplace here) are independent of the images, so I really have to use a table (for each image) of table of points as an input.

$\endgroup$
9
$\begingroup$

This produces the same result ( about 5x faster )

img1 = Import["ExampleData/lena.tif"];
img2 = ColorNegate[Import["ExampleData/lena.tif"]];
ImageAdd[
   ImageMultiply[img1, 
         Image[1 - SparseArray[ ptsToReplace -> 1 ,
              Reverse@ImageDimensions[img2]]]],
   ImageMultiply[img2, 
         Image[SparseArray[ ptsToReplace -> 1 , 
              Reverse@ImageDimensions[img2]]]]]

For a bunch of files you might do something like this:

dim=Reverse@ImageDimensions@Import@files[[1]];
 (*assumes all images are the same size*)
Fold[ImageAdd[#1,
     ImageMultiply[
        Import[files[[#2]]], 
        Image@SparseArray[ ptsToReplace[[#2]] -> 1 , dim]
                  ]
             ] &,  
          Image@SparseArray[{1, 1} -> 0, dim] , Range@Length@files ]

where files is a list of file names and ptsToReplace is a list of the points to keep for each file.

$\endgroup$
  • $\begingroup$ I tested the second code as well and: i) it works fine (you can edit your answer to remove untested) ii) i solves the memory problem iii) it is still not very fast; of course I loaded 500 images of 1Mo so I guess it has to take some time, but would you see any possible strategy to gain more speed? Thank you anyway! $\endgroup$ – anderstood Sep 13 '15 at 2:17
  • $\begingroup$ Fold is only loading one file at a time, so memory should not be an issue. My guess the file i/o is the main bottleneck. Not much you can do about that. $\endgroup$ – george2079 Sep 14 '15 at 13:29
  • $\begingroup$ I just "translated" the program into Python, with basically the same algorithm as the one you propose. I am surprised by how much faster it goes (about 6 times). My guess is that it is because I used "packed" low-level (in C) commands of numpy, while mathematica is at a much higher level. $\endgroup$ – anderstood Sep 14 '15 at 16:36

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.