Extending ImgPlus: how is the object passed through the UI?

scijava
imagej
imagej2

#1

Hi

I wanted to add some custom functionality to the ImgPlus. So I extended the class:

class ExtendedImgPlus extends ImgPlus {

    public ExtendedImgPlus(Img img) {
        super(img);
    }

    public void additionalMethod() {
        System.out.println("this is " + this.getClass().toString());
    }
}

A minimal use case is implemented by the following command:

@Plugin(type = Command.class, menuPath = "Plugins > ExtendedImgPlus")
public class ExtendedImgPlusPlugin implements Command {

    @Parameter
    ImgPlus imgp;


    @Override
    public void run() {
        if (imgp instanceof ExtendedImgPlus) {
            ExtendedImgPlus eimgp = (ExtendedImgPlus) imgp;
            eimgp.additionalMethod();
        } else {
            System.out.println("this is " + imgp.getClass().toString());
        }
    }


    public static void main(String[] args) throws IOException {
        ImageJ ij = new ImageJ();
        ij.ui().showUI();

        ImagePlus imp = new ImagePlus("http://imagej.nih.gov/ij/images/blobs.gif");
        Img img = ImageJFunctions.wrap(imp);

        ExtendedImgPlus eimgp2 = new ExtendedImgPlus(img);
        ij.ui().show("Img -> ExtendedImgPlus", eimgp2);

        ExtendedImgPlus eimgp1 = new ExtendedImgPlus(new ImgPlus(img));
        ij.ui().show("ImgPlus -> ExtendedImgPlus", eimgp1);
        
        ij.command().run(ExtendedImgPlusPlugin.class, true);
    }
}

Now the following happens:

  1. when I open any image and feed it as Img to my new ExtendedImgPlus, running the plugin yields:
    this is a class ExtendedImgPlus
  2. when I feed a ImgPlus to the ExtendedImgPlus the running the plugin yields:
    this is class net.imagej.ImgPlus

Why does the ExtendedImgPlus not come through in both cases?
Besides I now also asking myself if I this way of trying to attach addtional information/functionality is really the way to go…


#2

Dear @FelixM,

Can you elaborate how exactly you have tried to do that? In the legacy UI? In the modern UI?

Well, that depends on you are trying to achieve. Happy to discuss if you share some more information :wink:

Best,
Stefan


#3

I did that in the legacy UI


#4

Sorry for misleading you! My guess is that the issue originates in the @Parameter harvesting. When specifying an ExtendedImgPlus instance and passing that as a parameter to the CommandService, everything seems to work as expected:

ExtendedImgPlus eimgp1 = new ExtendedImgPlus(new ImgPlus(img));
ij.ui().show("ImgPlus -> ExtendedImgPlus", eimgp1);
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("imgp", eimgp1);

ij.command().run(ExtendedImgPlusPlugin.class, true, parameters);

Some more digging has revealed the issue in

When requesting an @Parameter ImgPlus and using a previously opened image, the opened image will actually be a Dataset. This is converted via a ConvertService to the type you are asking for (i.e. ImgPlus), hence you are loosing the ExtendedImgPlus.

Do those ramblings make sense to you @FelixM?


#5

Thanks for looking into this issue.
So in that case I should rather extend Dataset?


#6

Indeed, if you extend DefaultDataset (Dataset is an interface) everything works as expected (in my tests) since the ConvertService does no conversion.