Login  Register

Re: Python iteration through Pixel/ROI to slow ... ?

Posted by Rasband, Wayne (NIH/NIMH) [E] on Oct 28, 2013; 3:12am
URL: http://imagej.273.s1.nabble.com/Python-iteration-through-Pixel-ROI-to-slow-tp5005274p5005339.html

Yesterday's message was missing the JavaScript version of the Python example. Instead, the message had two copies of the Python script. Below is an enhanced version of the JavaScript, along with some notes about it.

1. This version of the script downloads the test image from the ImageJ website.

2. The test image contains metadata (a description of the image) added using the macro editor's Edit>Copy to Image Info command. The metadata is displayed when you check
"Show metadata" in the dialog box.

3. The test image was saved using File>Save As>ZIP, which reduced its size by a factor of 18 by using lossless compression.

4. The IJ.error("Macro canceled") statement aborts the script without displaying a message.

5. The script uses an overlay instead of the ROI Manager. In many cases, overlays are faster, simpler and easier to use.

6. It uses the setValue() method instead of setColor() because setColor() only works with integer values in ImageJ 1.48e and earlier.

7. It uses the fill(roi) method instead of add() because add(), like most ImageProcessor methods, only works with rectangular ROIs. The getStatistics() method does work with non-rectangular ROIs.

8. The dummy first argument of the Plot() constructor ("") is needed because JavaScript displays an error message if it is missing.

Here is the script:

  path = "http://imagej.nih.gov/ij/images/Pseudotsuga_menziesii.zip"
  gd = new GenericDialog("Options")
  gd.addCheckbox("Show source image", false)
  gd.addCheckbox("Show metadata", false)
  gd.addCheckbox("Show 32-bit image", false)
  gd.showDialog()
  if (gd.wasCanceled())
     IJ.error("Macro canceled")
  showSourceImage = gd.getNextBoolean()
  showSourceImageMetadata = gd.getNextBoolean()
  show32bitImage = gd.getNextBoolean()
  imp = IJ.openImage(path)
  imp32 = imp.duplicate()
  IJ.run(imp32, "Analyze Particles...", "show=[Overlay Outlines] clear")
  overlay = imp32.getOverlay()
  IJ.run(imp32, "32-bit", "")
  ip = imp32.getProcessor()
  for (i=0; i<overlay.size(); i++) {
     roi = overlay.get(i)
     ip.setRoi(roi)
     stats = ip.getStatistics()
     ip.setValue(ip.width/stats.pixelCount)
     ip.fill(roi)
  }
  ip.resetRoi()
  ip.setInterpolationMethod(ImageProcessor.NONE)
  ip = ip.resize(1, ip.height, true)
  plot = new Plot("", "Row Averages", "X", "Y", null, ip.getPixels())
  plot.show()
  if (showSourceImage)
     imp.show()
  if (show32bitImage) {
     imp32.setOverlay(null)
     IJ.run(imp32, "Enhance Contrast...", "saturated=0.4")  
     imp32.show()
  }
  if (showSourceImageMetadata)
     IJ.showMessage(imp.getTitle(), imp.getProperty("Info"));


-wayne


On Oct 26, 2013, at 9:19 PM, Rasband, Wayne (NIH/NIMH) [E] wrote:

> On Oct 23, 2013, at 5:04 AM, Michael Schmid wrote:
>
>> On Oct 22, 2013, at 22:14, Andreas Rzepecki wrote:
>>
>>> so here is what I want to do with this code:
>>>
>>> 1. Iterating through every pixel of the picture (row by row)
>>> 2. If the pixel is inside a certain ROI calculate a value for this pixel determined by the ROI and divided by the amount of pixel of this ROI (= pix_sap; nu ,L, p are constant))
>>> 3. Calculating the sum of pix_sap per pixel row
>>> 4. Print the sum of pix_sap per pixel row
>>
>> Hi Andreas,
>>
>> as Gabriel wrote already, it is much better to have a loop over the rois.
>> If I understand your problem correctly, what about something like the following approach:
>>
>> Create an empty float (32 bit) image.
>> For each roi {
>> determine the value that depends on the roi and divide by roi area, this gives you 'pix_sap'
>> select the roi in the float image
>> Process>Math>Add add 'pix_sap' to the float image (it will be restricted to the roi)
>> }
>> Take the float image and resize it to width=1, height=original size, 'Average when downsizing" and Interpolation=none.  This gives you the average of each row.  Then multiply the values by the previous width, so you have the sum.
>> Have a line selection from (0,0) to (0, height-1) and use
>> array = getProfile (macro) or
>> pp =  new ProfilePlot(imp); array = pp.getProfile(); (scripting).
>> This is your array of the sums of 'pix_sap' over each row.
>>
>> As it does not use any loop over pixels, an implementation in the imageJ macro language with BatchMode will be about as fast as any other implementation.
>
> Here is a Python script that iterates over the ROIs, which are created by the particle analyzer. In a float image, each ROI is filled with a value that is inversely proportional to the ROI area. The float image is then resized to a width of 1 to get the average for each row.
>
> imp = IJ.getImage()
> imp32 = imp.duplicate()
> IJ.run(imp32, "Analyze Particles...", "show=[Overlay Outlines] clear")
> overlay = imp32.getOverlay()
> IJ.run(imp32, "32-bit", "")
> ip = imp32.getProcessor()
> for i in range(overlay.size()):
>   roi = overlay.get(i)
>   ip.setRoi(roi)
>   stats = ip.getStatistics()
>   ip.setValue(float(ip.getWidth())/stats.pixelCount)
>   ip.fill(roi)
> ip.resetRoi()
> ip.setInterpolationMethod(ImageProcessor.NONE)
> ip = ip.resize(1, ip.getHeight(), True)
> plot = Plot("Values", "X", "Y", None, ip.getPixels())
> plot.show()
>
> Here is a JavaScript version of the Python script:
>
> imp = IJ.getImage()
> imp32 = imp.duplicate()
> IJ.run(imp32, "Analyze Particles...", "show=[Overlay Outlines] clear")
> overlay = imp32.getOverlay()
> IJ.run(imp32, "32-bit", "")
> ip = imp32.getProcessor()
> for i in range(overlay.size()):
>   roi = overlay.get(i)
>   ip.setRoi(roi)
>   stats = ip.getStatistics()
>   ip.setValue(float(ip.getWidth())/stats.pixelCount)
>   ip.fill(roi)
> ip.resetRoi()
> ip.setInterpolationMethod(ImageProcessor.NONE)
> ip = ip.resize(1, ip.getHeight(), True)
> plot = Plot("Values", "X", "Y", None, ip.getPixels())
> plot.show()
>
> A sample image is attached, courtesy of Andreas Rzepecki. It is a picture of the transition zone of two tree rings of Douglas-fir (left side: early wood, right side: late wood).
>
> -wayne

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html