Identifying single-pixel thick cell boundaries

Hi all, I am trying to identify the cell boundaries of a binary image using the Analyze Particles feature of ImageJ. If I start with Image1 and use Analyze Particles, everything is mostly fine. The only issue is that adjacent cells do not share a boundary, and have some undetected space in between them (Image2). I would like adjacent cells to share a boundary because this will allow me to easily recognize which boundary points are common between adjacent cells and how that boundary changes overtime (for future analysis).

image1.tif (104.4 KB)
image2.tif (312.5 KB)

Potential solution #1: To overcome this I modified Image1 why by inverting the image, using the Skeletonize command, and inverting again -resulting in Image3. Now each cell has close to a single-pixel thick boundary, but the Analyze Particles command no longer detects cells, I think because some boundaries are not exactly single-pixel thickness (Image4). Is there a command different from Skeletonize that might be more appropriate? I don’t think Erode-Dilate operations would work for this?

image3.tif (104.4 KB)
image4.tif (858 Bytes)

Potential solution #2: I use Analyze Particles on Image1 to identify the centroids of all cells. Use Image3 to identify (x,y) coordinates of all boundary points (in matlab). Then, for each centroid, determine which boundary points belong to that centroid. This seems like a potential solution but I can’t think of what programming logic to use to know which (x,y) points belong to a particular cell?

solution #1

The Particle analyzer - which is simply a connected component analysis https://en.wikipedia.org/wiki/Connected-component_labeling - assumes that connected pixels have a 8-connected neighborhood, thus are connected horizontally, vertically and diagonally. After skeletonization your objects are not separated diagonally anymore and thus fall all into 1 object. If you add an additional pixel using dilation (if your border is white and has a value 255) or erode if it is inverted then you should be able to use the particle analyzer again.

solution #2

you can export the xy coordinates of the outline per roi using:
File > Save As… > XY Coordinates…
Then you can load them in another program and associate them with other information such as your centroid.

Buuut…

…I don’t understand your problem to begin with. Particulary:

The particle analyzer delineates the objects (white, 255 value) in your image1 and in this example all the objects are nicely separated. This is perfect as far as the particle analyzer is concerned. There is no undetected space, because that is not what is detected.

I think the particle analyzer is simply not the correct tool for your underlying problem.
What measurements are you interested in? Membrane thickness?

The ParticleAnalyzer is already prepared to work with 4-connected border lines.

This option is not available via setup GUI or macro code because two important aspects have to be considered:

  1. In 4-connection mode holes inside cells can not be excluded.
  2. If all cells are surrounded by one big ‘cell’ all cells get lost inside the big one. So, there must be a network of cells, ideally dense connected one to another touching all borders
    The image3 is a perfect example for such conditions.

The ParticleAnalyzer can be called per plugin with the option FOUR_CONNECTED activated.

The result can be seen below:

.

Here is the plugin code:

import ij.IJ;
import ij.ImagePlus;
import ij.Prefs;
import ij.measure.ResultsTable;

import ij.plugin.PlugIn;
import ij.plugin.filter.Analyzer;
import ij.plugin.filter.ParticleAnalyzer;


public class PA_4connected implements PlugIn {
		
	public void run(String arg) {
		ImagePlus imp = IJ.getImage();

		double minSize = 0.0;
		double maxSize = Double.POSITIVE_INFINITY;
		double minCirc = 0.0;
		double maxCirc = 1.0;

		int options = Prefs.getInt("ap.options", ParticleAnalyzer.CLEAR_WORKSHEET);		
		options |= ParticleAnalyzer.INCLUDE_HOLES;
		options |= ParticleAnalyzer.ADD_TO_MANAGER;		
		options |= ParticleAnalyzer.FOUR_CONNECTED;
				
		ResultsTable rt = new ResultsTable();
		
		int measurements = Analyzer.getMeasurements();
		measurements &= ~ParticleAnalyzer.LIMIT;
		
		ParticleAnalyzer pa = new ParticleAnalyzer(options, measurements, rt, minSize, maxSize, minCirc, maxCirc);

		if ( !pa.showDialog())
			return;
		
		pa.analyze(imp);	
	}
}

Peter
2 Likes