Previewing the result of a Command

Hello,

After experimenting a bit with Commands I could implement a simple gaussian filter with the ImageJ2 API, and I would like to modify my code in order to preview the result of the filter for different values of the standard deviation sigma. What I want essentially is to see, in a separate window alongside the original, the effects of the filter as I change sigma, for instance via a slider.

For that purpose, I tried to mimic the commands-with-preview tutorial implementation, but despite all my efforts, I couldn’t get a working example. I’m actually having a hard time understanding:

  • which class/interface I should extend/implement,
  • which class (Data/DataView/Display/Other) I should use to be able to update the image displayed on the screen
  • which types (INPUT/OUTPUT/BOTH) I should use for my parameters.

I also took a look at the InteractiveImageCommand class and its super-classes to get a better understanding of how the Threshold and BrightnessContrast classes achieved similar goals but it seems specifically designed for interaction (feedback from displays?) rather than for previewing purposes, although I may be wrong.

So far, this is what I wrote:


  • by implementing the Command and Previewable interfaces, as advertised in the tutorial I mentionned,
import java.io.File;
import java.io.IOException;

import net.imagej.Dataset;
import net.imagej.DatasetService;
import net.imagej.ImageJ;
import net.imagej.ops.OpService;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.RealType;

import org.scijava.ItemIO;
import org.scijava.ItemVisibility;
import org.scijava.command.Command;
import org.scijava.command.Previewable;
import org.scijava.log.LogService;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import org.scijava.widget.FileWidget;
import org.scijava.widget.NumberWidget;

@Plugin(type = Command.class, menuPath = "Tutorials> My Plugin")
public class MyPlugin<T extends RealType<T> & NativeType<T>> implements Command, Previewable{
    
    @Parameter
    private DatasetService dss;
    
    @Parameter
    private OpService ops;
    
    @Parameter
    private LogService ls;
    
    @Parameter(type = ItemIO.INPUT)
    private Dataset image;
    
    @Parameter(type = ItemIO.OUTPUT)
    private Dataset result;
    
    @Parameter(label = "Sigma (slider)", persist = false, style = NumberWidget.SLIDER_STYLE,
            min = "0.1", max = "100.0", stepSize = "1.0")
    private double sigma;
    
    public MyPlugin(){
    }
    
    @Override
    public void preview() {
        run();
    }

    @Override
    public void cancel() {
        result = image.duplicate();
    }
    
    @Override
    public void run(){
        ls.info("Run");
        computeGaussian();
    }
    
    private void computeGaussian(){
        ls.info("Gaussian filter, sigma = " + sigma);
        RandomAccessibleInterval<T> rai = (RandomAccessibleInterval<T>) image.getImgPlus();
        RandomAccessibleInterval<T> res = (RandomAccessibleInterval<T>) ops.filter().gauss(rai, sigma);
        Dataset temp = dss.create(res);
        result = temp.duplicate();
    }
    
    public static void main(String... args) throws IOException{
        final ImageJ ij = net.imagej.Main.launch(args);
        final File file = ij.ui().chooseFile(null, FileWidget.OPEN_STYLE);
        Dataset d = ij.scifio().datasetIO().open(file.getPath());
        ij.ui().show(d);
        ij.command().run(MyPlugin.class, true);
    }
}

import java.io.File;
import java.io.IOException;

import net.imagej.Dataset;
import net.imagej.DatasetService;
import net.imagej.ImageJ;
import net.imagej.command.InteractiveImageCommand;
import net.imagej.display.DatasetView;
import net.imagej.display.ImageDisplayService;
import net.imagej.ops.OpService;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.RealType;

import org.scijava.ItemIO;
import org.scijava.ItemVisibility;
import org.scijava.command.Command;
import org.scijava.log.LogService;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import org.scijava.widget.FileWidget;
import org.scijava.widget.NumberWidget;

@Plugin(type = Command.class, menuPath = "Tutorials> My Plugin")
public class MyPlugin<T extends RealType<T> & NativeType<T>> extends InteractiveImageCommand{
    
    @Parameter
    private ImageDisplayService ids;
    
    @Parameter
    private DatasetService dss;
    
    @Parameter
    private OpService ops;
    
    @Parameter
    private LogService ls;
    
    @Parameter(label = "original",type = ItemIO.INPUT, persist = false, initializer = "initResultView")
    private Dataset image;
    
    @Parameter(label = "resultView", type = ItemIO.OUTPUT, persist = false)
    private DatasetView resultView;
    
    private Dataset result;
    
    @Parameter(label = "Sigma (slider)", style = NumberWidget.SLIDER_STYLE,
            min = "0.1", max = "100.0", stepSize = "1.0")
    private double sigma;
    
    public MyPlugin(){
        super();
    }
    
    private void initResultView(){
        ls.info("Initialize Result and ResultView");
        result = image.duplicate();
        resultView = (DatasetView) ids.createDataView(result);
    }
    
    @Override
    public void preview(){
        ls.info("Preview");
        computeGaussian();
    }
    
    @Override
    public void cancel(){
        ls.info("Cancel");
    }
    @Override
    public void run(){
        ls.info("Run");
        computeGaussian();
    }
    
    private void computeGaussian(){
        ls.info("Gaussian filter, sigma = "+sigma);
        RandomAccessibleInterval<T> rai = (RandomAccessibleInterval<T>) image.getImgPlus();
        RandomAccessibleInterval<T> res = (RandomAccessibleInterval<T>) ops.filter().gauss(rai, sigma);
        Dataset temp = dss.create(res);
        result.copyDataFrom(temp);
        resultView.update();
    }
    
    public static void main(String... args) throws IOException{
        final ImageJ ij = net.imagej.Main.launch(args);
        final File file = ij.ui().chooseFile(null, FileWidget.OPEN_STYLE);
        Dataset d1 = ij.scifio().datasetIO().open(file.getPath());
        ij.ui().show(d1);
        ij.command().run(MyPlugin.class, true);
    }
}

Both my implementations fail at either displaying the result window while tweaking the parameters or updating it.

I would really appreciate if someone could point me out, at the very least, the bits that I’m missing (I may totally be wrong in the choices I made) or give me general guidelines as to how to exploit already implemented classes.

Regards,
Elian

2 Likes

This seems rather old now but I am looking into the same thing and have found teh following example I intend to follow in order to get a preview…

More details as I manage play with this.

Best

Oli

1 Like

Thank you very much for sharing your findings with all necessary
code. It’s an old project and I don’t quite have the time just
right now to look into it but I will later on. I would be grateful
if you keep me posted about that.

Best

Elian