LoopBuilder to combine channels

Hello,

I was searching for some examples of using the loopbuilder. I want to combine a FloatType image with an IntType image and create an output image whose fist channel is FloatType and second channel is IntType. Are there any examples of such operations?

1 Like

Does this documentation help?


As far as I can tell, that’s not possible if you want to stay with a standard RandomAccessibleInterval<T>, as it can only be typed to a single type, either FloatType or IntType.

You could maybe use two separate RandomAccessibleIntervals for the two channels, and only combine them for viewing (e.g. using ImgLib2 converters),

or you could consider using a custom composite type implementation that has something like setCh1(DoubleType t) and setCh2(IntType t), but I don’t think that would be very useful …

What’s your use case? Displaying label images on top of raw data?

2 Likes

Thanks @imagejan for the references. I kept the type the same and made this function to convert a hyperstack to a channels + hyperstack image.

         public static ImgPlus<FloatType> createHyperStack(ImagePlus imp, ImagePlus impSeg) {
		
		RandomAccessibleInterval<FloatType> imageOrig = SimplifiedIO.openImage(
				imp.getOriginalFileInfo().directory + imp.getOriginalFileInfo().fileName, new FloatType());
		
		RandomAccessibleInterval<FloatType> imageSeg = SimplifiedIO.openImage(
				impSeg.getOriginalFileInfo().directory + impSeg.getOriginalFileInfo().fileName, new FloatType());
		
		
		long[] newDim = new long[] { imageOrig.dimension(0), imageOrig.dimension(1),2, imageOrig.dimension(2), imageOrig.dimension(3) };
		final Img<FloatType> out = new CellImgFactory<FloatType>(new FloatType()).create(newDim);
		ImgPlus<FloatType> output = new ImgPlus<FloatType>(out);
		RandomAccessibleInterval<FloatType> channelRaw = Views.hyperSlice(output, 2, 0);
    	RandomAccessibleInterval<FloatType> channelSeg = Views.hyperSlice(output, 2, 1);
		LoopBuilder.setImages(imageOrig, imageSeg, channelRaw, channelSeg).forEachPixel(
			    (a, b, r, g) -> {
			    	
			            r.set(a.get());
			            g.set(b.get());
			        
			    }
			);
		
		return output;
		
	}



That worked well. I will try what you suggested for mixing two different types together.

If you just want to combine two images into a 2-channel image (within the same type), you don’t even need LoopBuilder, I think it should be sufficient to use Views.stack() which will stack the images along a new dimension (that can be treated as channel).

1 Like

Hi @imagejan, I tried this however I could not control the axis of the final image and C and T got swapped.

A RandomAccessibleInterval has no notion about axis types, it’s just an n-dimensional interval. When you convert it into an ImageJ1.x object, e.g. by wrapping it into an ImagePlus, the default axis order XYCZT is always assumed.

If you want to make the image axis-aware within the scope of ImageJ2/ImgLib2, you’ll have to make e.g. an ImgPlus and provide the correct axis order:

AxisType[] axes = new AxisType[] {Axes.X, Axes.Y, Axes.TIME, Axes.CHANNEL};
Img<T> img = new ImgPlus(rai, name, axes);

(untested code)

2 Likes

Yeah, thanks @imagejan that I have seen being used, I will look more extensively into tutorials and code examples for this as this is super useful.

Hi Jan, How would I set the AxisType of an ImgPlus in a jython script? I tried

axes = AxisType[] {Axes.X, Axes.Y, Axes.Time}

error message:     axes = AxisType[]{Axes.X, Axes.Y, Axes.TIME}
                   ^
SyntaxError: no viable alternative at input ']'

I don’t think you can instantiate an array in python like this.

The following script worked for me to assign the 3rd dimension of the input image an axis type CHANNEL:

#@ ImgPlus imgPlus
#@output newImgPlus

from net.imagej.axis import Axes
from net.imagej import ImgPlus

axes = [Axes.X, Axes.Y, Axes.CHANNEL]

newImgPlus = ImgPlus(imgPlus.copy(), "Result", axes)
1 Like

Yup thanks that worked for TIME as well.