lunactic
lunactic

Reputation: 318

How to convert an image from 8-Bit to RGB in ImageJ2 using Java

I'm trying to use ImageJ2 directly from Java to create a binarised image coming from an input image.

A somewhat working version of my code looks like this:

final File file = new File("input.png");

try {
    DefaultDataTypeService dataTypeService = new DefaultDataTypeService();
    Dataset dataset = imageJ.dataset().open(file.getAbsolutePath());
    Img inputImg = dataset.getImgPlus();

    PluginInfo pluginInfo = imageJ.plugin().getPlugin(Binarize.class);
    Binarize binarizeOp = (Binarize) pluginInfo.createInstance();
    binarizeOp.setContext(imageJ.getContext());
    binarizeOp.setChangeInput(true);
    binarizeOp.setFillMaskBackground(true);
    binarizeOp.setFillMaskForeground(true);
    binarizeOp.setInputData(dataset);
    binarizeOp.setInputMask(null);
    binarizeOp.setMaskColor(Binarize.WHITE);
    binarizeOp.setMaskPixels(Binarize.INSIDE);
    binarizeOp.setThresholdEachPlane(false);
    binarizeOp.setDefaultThresholdMethod();
    binarizeOp.run();

    dataset.rgbChange();
    DefaultDatasetService defaultDatasetService = new DefaultDatasetService();
    Img outputImg = dataset.getImgPlus();
    outputImg = outputImg.factory().imgFactory(new UnsignedByteType()).create(outputImg,new UnsignedByteType());
    Dataset outputDataset = defaultDatasetService.create(outputImg);
    imageJ.dataset().save(outputDataset,"input_binary.png");

} catch (IOException e) {
    e.printStackTrace();
} catch (InstantiableException e) {
    e.printStackTrace();
} catch (IncompatibleTypeException e) {
    e.printStackTrace();
}

Running this code I have the problem that "input_binary.png" will be completely black, a behaviour I can reproduce using the ImageJ client application.

What I need to do in the client is to change the image type from "8-bit Color" to "RGB-Color". But I can not figure out how to reproduce that in Java using the current version of the net.imagej library.

I know that it would be possible using the 1.x library but I would like to to it using the 2.x.

Any help would be greatly appreciated.

Upvotes: 1

Views: 857

Answers (1)

hineroptera
hineroptera

Reputation: 769

You're getting black images because of this:

outputImg = outputImg.factory().imgFactory(new UnsignedByteType()).create(outputImg,new UnsignedByteType());

Which is just copying the dimensionality of your source image, not its values.

A few other key points:

  • It's best practice to have your Contextual objects (e.g. Services) derived from the Context instead of manually constructed.
  • The Binarize command has a Dataset output so it's not necessary to go Dataset > ImgPlus > Dataset
  • If you do want to write the dataset out you need to convert from the BitType output by Binarize to one that's supported.

See below for an example of running Binarize, getting the output, converting it and writing it out. Hope that helps!

public static void main(String... args) {
    final File file = new File("inpath.png");
    final File out = new File("outpath.png");

    // This is just sugar for the point of illustration.
    // The purpose here is just to have access to a Context
    ImageJ imagej = new ImageJ();

    // Cache the context for future use.
    Context context = imagej.getContext();

    try {
        // Use the context to get the services we want to ensure they are all
        // properly initialized.
        // If this was a Command these could all be @Parameters to be populated
        // automatically.
        DatasetService datasetService = context.getService(DatasetService.class);
        CommandService commandService = context.getService(CommandService.class);
        DatasetIOService datasetIOService =
            context.getService(DatasetIOService.class);

        Dataset input = datasetIOService.open(file.getAbsolutePath());

        // Start the command
        Future<CommandModule> future =
            commandService.run(Binarize.class, true, "inputData", input);

        // Get the command output
        Dataset binarized = (Dataset) future.get().getOutput("outputMask");

        // The output type is a binary image which, at the moment, needs to be
        // explicitly converted to something that can be written out.
        // Adapted from:
        // http://fiji.sc/ImgLib2_Examples#Example_2c_-_Generic_copying_of_image_data
        Img inputImg = input.getImgPlus().getImg();
        Img outputImg = binarized.getImgPlus().getImg();
        Img typedImg =
            inputImg.factory().create(inputImg, inputImg.firstElement());
        scale(outputImg, typedImg);

        Dataset output = datasetService.create(typedImg);

        // Save the output dataset
        datasetIOService.save(output, out.getAbsolutePath());
    }
    catch (IOException exc) {
        exc.printStackTrace();
    }
    catch (InterruptedException exc) {
        exc.printStackTrace();
    }
    catch (ExecutionException exc) {
        exc.printStackTrace();
    }
    finally {
        // Dispose of the context to shut down
        context.dispose();
    }

}

public static <T extends IntegerType<T>> void scale(
    final RandomAccessible<BitType> source, final IterableInterval<T> target)
{
    // create a cursor that automatically localizes itself on every move
    Cursor<T> targetCursor = target.localizingCursor();
    RandomAccess<BitType> sourceRandomAccess = source.randomAccess();
    // iterate over the input cursor
    while (targetCursor.hasNext()) {\
        // move input cursor forward
        targetCursor.fwd();
        // set the output cursor to the position of the input cursor
        sourceRandomAccess.setPosition(targetCursor);
        // set the value of this pixel of the output image
        BitType b = sourceRandomAccess.get();
        if (b.get()) {
            targetCursor.get().setOne();
        }
        else {
            targetCursor.get().setZero();
        }
    }
}

Upvotes: 2

Related Questions