4
$\begingroup$

I have sets of images (each contains about 3000 images where many objects are seen, each image is 4 Megapixels large, format is 8bit, gray scale, png).

To get an impression about the trajectories of the objects I superpose all images and produce a single colorized image where the objects in each image have a specific color corresponding to the image number.

The background ist black, the tracks start with blue and stop with red.

The problem in the code below is that it crashes when many and larges images are used since all of them are read at once in memory.

Is there a solution that image by image can be read and superposed on top of each other, instead of reading them at once?

example image that contains only a single object:

enter image description here

a sample of small images for testing the code: http://tinyurl.com/ht5362l

code:

ChoiceDialog[{FileNameSetter[Dynamic[imageDir], "Directory"], Dynamic[imageDir]}];
SetDirectory[imageDir];

fNames = FileNames["*.png"];
numImages = Length[fNames];

colTable = {
   {Black}, 
      Table[
         {Blend[{Blue, Green, Yellow, Red}, x]}, 
         {x, 2/numImages, 1, 1/numImages}
      ]
}; 

colTable = Flatten[colTable];

threshold = FindThreshold[Import[fNames[[1]], Method -> "Entropy"]];

bins = Table[
          Clip[
             Import[fNames[[i]], "GrayLevels"], {threshold, threshold}, 
             {0, i/numImages}
          ], 
          {i, 1, numImages}
       ];

superImg = Colorize[
              Image[
                 Map[Max, Transpose[bins, {3, 1, 2}], {2}]
              ], 
              ColorFunction -> (Blend[colTable, #] &)
           ]

superposed image:

enter image description here

$\endgroup$
4
$\begingroup$

Just assemble the bins image one layer at a time. E.g. after computing threshold do

bins = 0;
Do[
  m = Clip[Import[fNames[[i]], "GrayLevels"], {threshold, threshold}, {0, 1}];
  bins = bins (1 - m) + m i/numImages,
  {i, 1, numImages}];

superImg = Colorize[Image[bins], ColorFunction -> (Blend[colTable, #] &)]

enter image description here

$\endgroup$
  • $\begingroup$ This is the solution ... probably there is no other way than to do it via a loop? For 10 images of 4 Megapixel AbsoluteTiming yields about 10 sec for my computer. $\endgroup$ – mrz Jul 4 '16 at 9:52
  • $\begingroup$ The timing will be dominated by the image import, there's probably no easy way to speed it up. $\endgroup$ – Simon Woods Jul 4 '16 at 11:20
  • $\begingroup$ You think therefore also compiling would not improve the speed? $\endgroup$ – mrz Jul 4 '16 at 14:38
7
$\begingroup$

I propose making use of ComponentMeasurements, especially the "Centroid"-Option of MorphologicalComponents, which calculates the center-of-mass, might be very convenient.

For example you might try the following:

SetDirectory[imageDir]
i = Import["2016071.gif"];
length = Length[i];
m[y_] := Module[{y0}, y0 = y;
  iframe = i[[y]];
  (*Poisson-Filter blures the image, edges are contained*)
  res = TotalVariationFilter[iframe, 0.35, Method -> "Poisson"];
  mean = ImageMeasurements[iframe, "MeanIntensity"];
  ib = MorphologicalBinarize[res, {mean + 0.5}];
  (*Delete Small Components  if necessary!*)
  delsmall = DeleteSmallComponents[ib, 10];
  t = MorphologicalComponents[delsmall] // Max;
  m1 = ComponentMeasurements[MorphologicalComponents[delsmall], 
     "Centroid"] /. Rule[_, x_] -> x;
  imageBuffer = iframe;
  If[y == 1, pointsbuffer = SetAlphaChannel[iframe, 0], 
   pointsbuffer = pointsbuffer;
   (*In each frame a loop will set dots a each com-
   position calculated*)
   For[p = 1, p < t + 1, p++, Print[p];
     points = 
      Show[pointsbuffer, 
       Graphics[{PointSize[0.01], ColorData["SolarColors"][y/50], 
         Point[Part[m1, p]]}]];
     pointsbuffer = points]
    (*Print to see the output on-the-fly*)
    Print[Show[iframe, pointsbuffer, ImageSize -> 350]]
    Export["outputDir/img_" <> ToString[y] <> ".png", 
     Show[iframe, pointsbuffer]]
   ]
  ]
(*Run through all frames*)
For[k = 1, k <= length, k++,
 m[k]
 ]

I should notice that I made a .gif out of your images. This code might not be the most efficient or beautiful, since it is written quite quickly. There is definetly room for improvement, but I think it is at least understandable.

My output looks like this (quality is reduced):

Output of ComponentMeasurements

P.S. If you want to know more about the procedure itself you might also consider printing "ib", which is the morphologically binarized image. By doing so one can see which component/area is used to calculate the center-of-mass.

$\endgroup$
  • $\begingroup$ Thank you for your solution. What I wanted was to have a quick overview on how objects move in an image with time without determining their position. What would you do if many object are seen? $\endgroup$ – mrz Jul 4 '16 at 14:39
  • $\begingroup$ If you are not interested in the center-of-mass but rather in an overview, you can also drop the "Centroid"-measurement and instead overlay the binarized images by MorphologicalBinarize. You will end up with a solution very similar to what you have done before in the opening-thread. This will also work with many objects. By the way, the code in my main thread will also work with more than one object! $\endgroup$ – P.B. Jul 6 '16 at 8:48
  • $\begingroup$ Incidentally, you might also be interested in ImageFeatureTrack. For instance you might choose the initial positions either by yourself or even by using MorphologicalComponents and ImageFeatureTrack might track those objects during your movie. $\endgroup$ – P.B. Jul 6 '16 at 23:27
  • $\begingroup$ Please see: mathematica.stackexchange.com/questions/120039/…. For accurate scientific subpixel measurements where it is necessary to define the method on how objects positions should be determined and tracked ImageFeatureTrack cannot be used. $\endgroup$ – mrz Jul 8 '16 at 7:38

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.