imagej / imagej-common

ImageJ core data model
https://imagej.net/libs/imagej-common
BSD 2-Clause "Simplified" License
9 stars 18 forks source link

Display ARGBType images as images with color channel #88

Closed frauzufall closed 4 years ago

frauzufall commented 4 years ago

We discussed this here in the forum (ping @hanslovsky @ctrueden). I would prefer a solution though where I actually see the colors... How would I do that?

ctrueden commented 4 years ago

@frauzufall Shall we go through this on Monday?

ctrueden commented 4 years ago

@frauzufall After playing around a bit, I believe we do not need DatasetView here after all. Below is working code. The only question is whether to put it directly into DefaultImageDisplay, or make a Converter plugin that the image display logic uses internally.

ImageJ ij = new ImageJ();
ij.ui().showUI();

// A nice ARGB image.
Img<ARGBType> argbImage = ArrayImgs.argbs(512, 384);
Cursor<ARGBType> c = argbImage.cursor();
for (int y = 0; y < argbImage.dimension(1); y++) {
    for (int x = 0; x < argbImage.dimension(0); x++) {
        int r = (x + y) % 255;
        int g = (x * y) % 255;
        int b = (y - x) % 255;
        int a = 255;
        c.next().set(ARGBType.rgba(r, g, b, a));
    }
}
// The ARGB image is not showable:
//ij.ui().show(argbImage);
ImageJFunctions.show(argbImage);

// Internal conversions needed to convert to Dataset.
// This could (should?) be a SciJava Converter plugin.
List<RandomAccessibleInterval<UnsignedByteType>> channels = Arrays.asList(
    Converters.argbChannel(argbImage, 1),
    Converters.argbChannel(argbImage, 2),
    Converters.argbChannel(argbImage, 3)
//  Converters.argbChannel(argbImage, 0)
);
Dataset dataset = ij.dataset().create(Views.stack(channels));
dataset.setAxis(new IdentityAxis(Axes.CHANNEL), dataset.numDimensions() - 1);

// NB: The following call gives a hint to the ImageJ Legacy layer that
// this dataset should be collapsed to IJ1's RGB type. The dataset must
// be uint8 with the third dimension axis of type Channel and length 3,
// or else an exception will be thrown.
dataset.setRGBMerged(true);
ij.ui().show(dataset);
maarzt commented 4 years ago

The methods DefaultDatasetService.create(...) are responsible for the conversion of RAI to Dataset. But the code lags support for ARGBType, and that's why we get the Exception. I think DefaultDatasetService is the place the fix the problem. And yes, the code for the legacy image display looks at the RGBMerged flag to decide whether to display the image colorful or multichannel.

maarzt commented 4 years ago

This Fix changes DatasetService.create(RandomAccessibleInterval<T> image) and DatasetService.create(ImgPlus<T> image) to support ARGBType. The methods now use the code that @ctrueden posted above to automatically split the ARGBType into channels before converting it to Dataset.

The following code can now be used to correctly convert an Img<ARGBType> to Dataset:

// Some RGB image
Img<ARGBType> image = ArrayImgs.argbs(10, 10);

// Convert it to dataset (this internally splits the RGB image into three channels)
Dataset dataset = datasetService.create(image); 

This fix also enables UIService (and DefaultImageDisplay) to show the ARGBType image correctly.

ctrueden commented 4 years ago

Thank you, @maarzt !

maarzt commented 4 years ago

@ctrueden Thank you for the quick review & merge! :heart_eyes: