I have a set of 2700 consecutive png images (8bit, 2048*2048 pixels).

I would like to visualize the intensity variation of each pixel vs. image number.

Here is an example of 10 images: http://goo.gl/52McV3

At first I wanted to store the intensity of each pixel in each image into an array. Unfortunately the code below does not work properly. What am I doing wrong?

ChoiceDialog[{FileNameSetter[Dynamic[imageDir], "Directory"], 
fNames = FileNames["*.png"];
numFiles = Length[fNames];


pixelIntensity = Array[0 &, {2048, 2048, numFiles , 1}];


  image = Import[fNames[[i]]];

   pixelIntensity[[r, c, i]] = 
    ImageData[ImageTake[image, {r, r}, {c, c}]],
   {r, 1, 2048}, {c, 1, 2048}

  {i, 1, numFiles}


I have RAM problems when many images (2700) have to be processed

  • $\begingroup$ So you want to visualize 4194304 curves of 2700 points each? ... $\endgroup$ – Dr. belisarius Feb 4 '16 at 17:32
  • $\begingroup$ These images are taken with a CMOS chip which has a few (some 1000s) pixels that have after calibration (reset to 0 brightness) still non-zero brightness values. Their amplifier are not working properly. I would like especially to find these pixels (their coordinates) and investigate their brightness variation. $\endgroup$ – mrz Feb 4 '16 at 18:07
  • 1
    $\begingroup$ I think you'll find Import[] swamps the time of everything else. If you want to load the data just do something like this: Transpose[ImageData@Import[#] & /@ fNames, {3, 2, 1}] $\endgroup$ – george2079 Feb 4 '16 at 19:45
  • $\begingroup$ @mrz could you comment on the performance of the different approaches offered in the answers for your particular data? There are things to do after your question is answered. Better approaches may come later improving over previous replies. Participation is essential for the site, please come back to do your part tomorrow $\endgroup$ – rhermans Feb 5 '16 at 19:17
  • $\begingroup$ Excuse me, I had to do some other work last week and could not continue the work on the asked question ... I will try to do it in the next days $\endgroup$ – mrz Feb 10 '16 at 9:13

The data

(* {"image_01.png", "image_02.png", "image_03.png", \
"image_04.png", "image_05.png", "image_06.png", "image_07.png", \
"image_08.png", "image_09.png", "image_10.png"} *)

All at once

If there are no memory constraints, you can load all in a single array (read below for other cases).

data = ImageData[Import[#], "Byte"] & /@ FileNames["image_*.png"];

(* {0, 97}*)

 ListPlot[data[[All, x, y]], PlotRange -> {0, 100}]
 , {x, 1, Length[data[[1]]], 1}
 , {y, 1, Length[data[[1, 1]]], 1}

Mathematica graphics

Efficient memory use

Loading data only for the requested pixel coordinates, by taking advantage of the options of Import that allow loading only specific parts of components using Import["file.png", {"Data", row, column}]

Mathematica graphics Mathematica graphics Mathematica graphics

Also using Memoization, so if you call for the same data more than once, no work is repeated.

For a single coordinate pair

xyd[x_Integer, y_Integer] := 
 xyd[x, y] = 
  ParallelMap[Import[#, {"Data", x, y}] &, FileNames["image_*.png"]]

ListPlot[xyd[822, 920]]

Mathematica graphics

For a list of coordinates

xyld[list_] :=
 xyld[list] =
    Diagonal@Import[#, {"Data", list[[All, 1]], list[[All, 2]]}] &
    , FileNames["*.png"]
  • 1
    $\begingroup$ This is great ... but I have RAM problems when many images (2700) have to be processed $\endgroup$ – mrz Feb 4 '16 at 17:44
  • $\begingroup$ Thank you ... I will try that tomorrow and inform you. $\endgroup$ – mrz Feb 4 '16 at 17:59
  • $\begingroup$ I have edited considerably the answer, please let me know if this is what you need. $\endgroup$ – rhermans Feb 5 '16 at 11:00
  • 1
    $\begingroup$ My experience has been it is actually faster to import a whole image and extract the required part ( Import[file,"Data"][[row,col]] ) than to use Import's subelement feature.. $\endgroup$ – george2079 Feb 5 '16 at 17:57
  • $\begingroup$ @george2079 Thanks for your comment. What would that be? I guess it depends on how much RAM there is available in relation with file size. I would expect that Import should offer a lower level approach that avoids loading unnecessary data, but as always, the devil in in the details. $\endgroup$ – rhermans Feb 5 '16 at 19:13

This is what I'd do: You say most of the pixels are dark, and thus uninteresting, but some of them are bright. So I'd start by summing all images up to find the "bad" pixels:

files = FileNames[

totalBrightness = 0.0;
   totalBrightness = ImageData[Import[f]] + totalBrightness, {f, 
    files}], f];

meanBrightness = totalBrightness/Length[files];    

brightestPixels = Reverse[Sort[Flatten[meanBrightness]]][[;; 100]];

ListLinePlot[brightestPixels, PlotRange -> All, 
 PlotLabel -> "Top 100 brightest pixel values (mean over all images)"]

enter image description here

Then you can load the images a second time and extract the pixel values for these positions:

brightestPixelLocations = 
  Position[meanBrightness, #][[1]] & /@ brightestPixels;

Monitor[pixelValues = 
   Table[Extract[ImageData[Import[f]], brightestPixelLocations], {f, 
     files}], f];

and plot them any way you like:

ListLinePlot[pixelValues\[Transpose][[;; 10]], 
 PlotLabel -> "Top 10 brightest pixels", PlotRange -> All, 
 AxesLabel -> {"Image Index", "Brightness"}]

enter image description here

ArrayPlot[pixelValues, ColorFunction -> GrayLevel, ImageSize -> 800, 
 FrameLabel -> {"Image index", "Top 100 Pixels"}]

enter image description here

  • $\begingroup$ Great solution for picking the bright pixels ... it would be good to be able to a accept more than one answer as a (different) solution ... unfortunately this not possible. $\endgroup$ – mrz Feb 17 '16 at 22:04

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.