ijpb / MorphoLibJ

Collection of mathematical morphology methods and plugins for ImageJ
http://imagej.net/MorphoLibJ
GNU Lesser General Public License v3.0
98 stars 49 forks source link

Using Distance Transform Watershed without a GUI / UI #79

Open satorstefan opened 8 months ago

satorstefan commented 8 months ago

Hello David,

I would like to use MorphoLibJ without any UI. For the moment I am focused on DistanceTransformWatershed().

Currently it seems to me the code assumes a UI is present.

Could you add a constructor to DistanceTransformWatershed() so I can pass all mandatory arguments? Or using some sort of builder pattern for DistanceTransformWatershed() would also be nice.

What I tried, but it did not work because of java.awt.HeadlessException: null:

webcam.addValueChangeListener(e -> {
            value = e.getValue();

            String[] split = value.split(",");

            data = Base64.getDecoder().decode(split[1]);

            BufferedImage img = null;
            try {
                img = ImageIO.read(new ByteArrayInputStream(data));
            } catch (IOException ex) {

            }

            ImagePlus imp = new ImagePlus("test", img);

            var watershed = new DistanceTransformWatershed();
            watershed.setup("", imp);

            ImageProcessor processor =  imp.getProcessor();
            processor.autoThreshold();

            //this is false
            BinaryImages.isBinaryImage(imp);

            GenericDialog gd = new GenericDialog("Distance Transform Watershed");
            gd.setInsets(0, 0, 0);
            gd.addMessage("Distance map options:", new Font("SansSerif", 1, 12));
            gd.addChoice("Distances", ChamferWeights.getAllLabels(), "Chessboard (1,1)");
            String[] outputTypes = new String[]{"32 bits", "16 bits"};

            boolean floatProcessing = true;
            gd.addChoice("Output Type", outputTypes, outputTypes[floatProcessing ? 0 : 1]);

            gd.setInsets(0, 0, 0);
            gd.addCheckbox("Normalize weights", false);
            gd.setInsets(20, 0, 0);
            gd.addMessage("Watershed options:", new Font("SansSerif", 1, 12));
            gd.addNumericField("Dynamic", (double)2, 2);

            String[] connectivity = {"4", "8"};
            gd.addChoice("Connectivity", connectivity, "4");
            gd.setInsets(20, 0, 0);

            watershed.dialogItemChanged(gd, null);
            watershed.run(processor);

            FileSaver fileSaver = new FileSaver(imp);

            fileSaver.saveAsBmp("...");
        });
iarganda commented 8 months ago

Thanks, @satorstefan for bringing this to our attention! While we create a public method for that and publish a new release, you may want to write in your code the few lines equivalent to the process in that plugin:

https://github.com/ijpb/MorphoLibJ/blob/master/src/main/java/inra/ijpb/plugins/DistanceTransformWatershed.java#L263-L268

satorstefan commented 8 months ago

Hello Ignarcio,

For now it seems it also works to set: System.setProperty("java.awt.headless", "false");

But I struggle to get a binary image out of my greyscale image.

So far I tried:

 ImagePlus imp = new ImagePlus("test", img);

        ImageProcessor processor =  imp.getProcessor();
        processor.autoThreshold();

        ImagePlus binaryPlus = new ImagePlus("binary", processor);

        if(!BinaryImages.isBinaryImage(binaryPlus)){
            System.out.println("Huston we got a problem!");
        }

and I also see that ByteProcessor.threshold(int level1, int level2) gets called.

iarganda commented 8 months ago

To binarize an image, you can use our own method from the Threshold class:

https://github.com/ijpb/MorphoLibJ/blob/master/src/main/java/inra/ijpb/segment/Threshold.java#L57

satorstefan commented 8 months ago

Hello Ignarcio,

I will try your approach.

What I did try so for seems to "work", but the image result.png is just the unchanged binary that I put in.


            watershed.dialogItemChanged(gd, null);
            watershed.run(processor);

            BufferedImage bufferedImage = processor.getBufferedImage();
            print("result.png", bufferedImage)
```;
satorstefan commented 8 months ago

@iarganda Hello Ignarcio,

with your hint I could implement the algorithm.

I have one last question. Is there a easy way to give each object its own color like shown in the picture on the right here: https://imagej.net/plugins/distance-transform-watershed?

Best regards Stefan

dlegland commented 5 months ago

Hi Stefan, maybe late for reply, but you can assign colors to regions in a label map when performing the connected component analysis. Either via the plugin, or by using the computation classes.

best, David