Perform connected components along specific dimensions

Dear all,
I would like to apply the ops opService.labeling().cca to specific dimensions of a multi-dimensional image. For instance to perform it separately on every time point or per 2D slice.

Is this possible and what is the best way of doing it?

I tried using op.slice

final Img <IntType> labelImg = ArrayImgs.ints(Intervals.dimensionsAsLongArray(binImg));
        ImgLabeling<Integer, IntType> labeling = new ImgLabeling<>(labelImg);
 final UnaryComputerOp op_cca = (UnaryComputerOp) opService.op("cca",  binImg, ConnectedComponents.StructuringElement.EIGHT_CONNECTED);
opService.slice(labeling, binImg, op_cca, new int[]{0,1});

but this fails with the error

[ERROR] Module threw exception
java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.ClassCastException: net.imglib2.view.IntervalView cannot be cast to net.imglib2.roi.labeling.ImgLabeling
	at net.imagej.ops.thread.chunker.DefaultChunker.run(DefaultChunker.java:103)
	at org.scijava.command.CommandModule.run(CommandModule.java:199)
	at net.imagej.ops.OpEnvironment.run(OpEnvironment.java:950)
	at net.imagej.ops.OpEnvironment.run(OpEnvironment.java:157)
	at net.imagej.ops.map.MapUnaryComputers$IIToIIParallel.compute(MapUnaryComputers.java:101)
	at net.imagej.ops.map.MapUnaryComputers$IIToIIParallel.compute(MapUnaryComputers.java:87)
	at net.imagej.ops.slice.SliceRAI2RAI.compute(SliceRAI2RAI.java:78)
	at net.imagej.ops.slice.SliceRAI2RAI.compute(SliceRAI2RAI.java:54)
	at net.imagej.ops.special.computer.UnaryComputerOp.run(UnaryComputerOp.java:77)
	at net.imagej.ops.special.computer.UnaryComputerOp.run(UnaryComputerOp.java:92)
	at org.scijava.command.CommandModule.run(CommandModule.java:199)
	at net.imagej.ops.OpEnvironment.run(OpEnvironment.java:950)
	at net.imagej.ops.OpEnvironment.run(OpEnvironment.java:157)
	at net.imagej.ops.OpEnvironment.slice(OpEnvironment.java:811)
	at de.mpibpc.liveim.cavazza.processBinary.run(processBinary.java:85)
	at org.scijava.command.CommandModule.run(CommandModule.java:199)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:168)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:127)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:66)
	at org.scijava.thread.DefaultThreadService$3.call(DefaultThreadService.java:238)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

This is the same issue as

did @imagejan or @juliomateos found a solution? Does some of the developers @tpietzsch have an idea?

greetings
antonio

@apoliti You cannot run CCA on a slice of an ImgLabeling at the moment. This is a limitation that Ops inherits from the underlying imglib2 algorithm (https://github.com/imglib/imglib2-algorithm/blob/51b56a827a2802c27b19ffca4f952faf6f73de63/src/main/java/net/imglib2/algorithm/labeling/ConnectedComponents.java#L104-L109)
It might be possible to change the algorithm to make it work in the future, but there are some details that are problematic/unclear. For example it would not be (trivially) possible to run CCA on two slices in parallel, because for labeling cc in slice 2, it is necessary to know which labels have already been used in labeling cc in slice 1.

In the meantime, you could:

  • Views.hyperslice() the input image for extracting individual slices
  • Create a new ImgLabeling for every slice
  • In the end (if desired) use Views.stack() to stack the slice labelings into one big labeling of the same dimensions as the input image.
2 Likes

thanks for your answer.
Currently I am performing a 2D particle analyzer IJ1 first to remove very small objects and then perform the 3D IJ cca to connect everything.

There is also the net.imglib2.algorithm.labeling.ConnectedComponentAnalysis in imglib2-algorithm. It is less flexible than the ImgLabeling but for simple scalar labels it will do the trick. You can pass a Shape that defines the structuring element. AFAIK there is no Shape that does what you want but you could implement one. Another route would be to create labelings for each slice independently as suggested by @tpietzsch. I have a similar problem for segmentation except I run CC (or rather watersheds) on blocks of 3D data on a Spark cluster. Here is what I do:

  1. Create connected components in each block with non-background labels starting at 1. Report the number of non-background labels in each block (can be done in parallel)
  2. Use number of labels per block to create a label offset for each block. (sequential)
  3. Re-label each block according to its label offset (parallel)
  4. (This may not be necessary for your task) Run connected-components along block boundaries and re-label each block according to that.
1 Like