Thank you Michael for all the details that often can be forgotten when dealing with regions inside regions. Thank you also Wayne for an alternative and also fast way of clearing regions. Just for the record, in my machine (normal macro mode) the flood fill still is ~1.6x faster, but those differences vanish in batch mode.
Best wishes

Gabriel

On 23/03/2024 19:21, Michael Schmid wrote:
(1) In case of particles with holes, doWand traces the outer boundary.
If there is a particle with a hole, and the hole contains another
(small) particle, the first doWand on the outer particle will create a
roi that encompasses also the small inner particle. In the current
macro, "Clear" will then eliminate the inner particle. Thereafter, the
loop will eventually reach the inner particle, which is not there any
more. doWand will then select the next particle to the right, or, if
there is no particle to the right, the whole image minus the particles
at the border. This can lead to undesired results.

This means that a macro that iterates over the xStart, yStart of the
particles using the Wand must set Particle Analyzer option "include"
(for "include holes") to suppress listing inner particles. Otherwise,
the results will be wrong if there is at least one particle inside the
hole of another particle.

This is different from floodFill, which only spreads out in contiguous
regions and does not reach inner particles when given a starting
coordinate of an enclosing (outer, ring-like) particle. When using
floodFill in conjunction with the Particle Analyzer, one should not
specify "include" holes.


(2) The problem of the Wand not selecting the full particle in legacy
mode can also happen at particles that do not touch the edge (it is more
likely to happen on edge particles, and the current macro creates such
particles only in rare cases).


(3) The main reason for the poor performance of the doWand version at
large image sizes probably lies in the fact that "Clear" with a
non-rectangular ROI requires creating a snapshot (duplicate) of the
image. If the image plus its copy don't fit the CPU cache, this takes
time, which becomes a serious issue for 300000 such operations.


Best,

Michael
_______________________________________________________________________


On 22/03/2024 20:35, Michael Schmid wrote:
Hi Gabriel,

concerning the bug of doWand at the upper image edge, using the XStart,
YStart:

This problem only occurs in "Legacy mode". It disappears in 8-connected
mode:
    doWand(x,y, /*tolerance=*/0, "8-connected");

The problem also disappears if the foreground is thresholded. It is
related to the statement (Wand.java, line 145)
   if (legacyMode)
       fourConnected = !thresholdMode && !(isLine(x, y));

Where isLine is some heuristics to determine whether there is a blob or
a line.  Many years ago, when implementing the tolerance and the 4- and
8-connected mode, since I did not understand the rationale behind it and
I did not want to break anything, I had tried to keep the previous
behavior unchanged. Either I had done this incorrectly or it is a bug
that dates back to the very early days of ImageJ.

Maybe Wayne knows why the wand was switching to 4-connected mode when it
was not a line (and not thresholded mode) in the very old days. It could
be that those days the ParticleAnalyzer was requiring a thresholded
image and did not work with an unthresholded binary image; I do not
remember.

Concerning the performance:
The thing that makes the Wand version so slow is not the wand operation
but the "Clear". There are about 300000 ROIs. Most operations in ImageJ
are optimized for processing large areas and sometimes inefficient for
small ROIs. In your example, the average ROI size is only about 2.5 pixels.

For each "Clear" operation, a LUT is created (in ImageProcessor.process)
and also a mask is created for the ROI, using an algorithm for generic
polygons (not taking into account that it is a traced ROI with only
horizontal and vertical boundaries). Each mask is an ImageProcessor on
its own. So there is quite some overhead.

What I do not understand: The processing time increases in a very
nonlinear way with image size. The number of ROIs is roughly
proportional to image size, and ROIs are very small, so also the masks
are small.
   256x256     0.6 s
   512x512     2.2 s
  1024x1024   11 s (expected about 4x longer, thus ok)
  2048x2048  170 s (expected 4x, actually 16x longer)
  2048x4096  700 s (expected 2x, actually 4x longer)
There might be some nonlinearity if the largest image does not fit into
the CPU cache, but the ROIs are sorted in y, so only the y region
currently processed needs to be in memory.

Michael
_________________________________________________________________

On 22/03/2024 12:54, Gabriel Landini wrote:
Hello,
Using the doWand to remove binary regions is quite slow compared to
the floodfill method (floodfill is approx 74 times faster in normal
macro mode and approx 260 faster (!) in batch mode in the example below).

But more importantly, I just noted that the doWand method fails to
remove all regions from the image.
Running the macro below you find many remaining regions close the the
top and right borders on the result image 1.
I suspect that the wand is missing some 8-connected pixels that form
part of the boundary of regions touching at the image borders.


- - - - -
newImage("Untitled", "8-bit black", 2048, 2048, 1);
run("Add Noise");
setThreshold(0, 5);
setOption("BlackBackground", true);
run("Convert to Mask");
run("Duplicate...", "title=1");
run("Analyze Particles...", "minimum=1 maximum=999999 bins=20
show=Nothing clear record");
selectImage("1");
t0=getTime();
for (i=0; i<nResults; i++) {
    x = getResult('XStart', i);
    y = getResult('YStart', i);
        doWand(x,y);
        run("Clear");
}
print ("Wand: "+getTime()-t0+" ms.");


selectImage("Untitled");
run("Duplicate...", "title=2");
setColor(0);
selectImage("2");

t0=getTime();
for (i=0; i<nResults; i++) {
    x = getResult('XStart', i);
    y = getResult('YStart', i);
    floodFill(x, y, "8-connected");
}
print ("Floodfill: "+getTime()-t0+" ms.");

- - - - -

Regards

Gabriel




On 22/03/2024 00:43, Wayne Rasband wrote:
The “Record starts” checkbox has been replaced by “Overlay” but
macros that use the ‘record’ keyword continue to work.

Here is an updated version of the CircularParticles macro linked to
in the ImageJ User Guide that uses ‘overlay’ instead of ‘record’:

// This macro demonstrates how to erase non-circular objects
run("Blobs (25K)");
setThreshold(125, 248);
run("Set Measurements...", "area perimeter circularity decimal=3");
run("Analyze Particles...", "clear overlay");
for (i=0; i<nResults; i++) {
    circularity = getResult('Circ.', i);
    if (circularity<0.85) {
        Overlay.activateSelection(i);
        run("Clear");
    }
}
run("Select None");
exit;

// Original version that uses "Record starts"
run("Select None");
requires("1.29n");
run("Blobs (25K)");
setThreshold(125, 248);
run("Set Measurements...", "area perimeter circularity decimal=3");
run("Analyze Particles...", "minimum=1 maximum=999999 bins=20
show=Nothing clear record");
for (i=0; i<nResults; i++) {
    x = getResult('XStart', i);
    y = getResult('YStart', i);
    circularity = getResult('Circ.', i);
    if (circularity<0.85) {
        doWand(x,y);
        run("Clear");
    }
}
run("Select None");

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

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

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

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

Reply via email to