Studying plugins: How is FrangiVesselness.class wired up to the Process>Filters>Frangi Vesselness Fiji menu entry?

Tags: #<Tag:0x00007fd69c08a9d8> #<Tag:0x00007fd69c08a848> #<Tag:0x00007fd69c089d80>


In short, why does the Frangi Vesselness command still show
up in the Fiji menu bar after I hide the plugin class?

For educational purposes I am playing with the IJ2-style Frangi
Vesselness plugin. (Process>Filters>Frangi Vesselness in stock
Fiji 1.51s.)

I took the (educational) liberty of unjarring the jar that
contains FrangiVesselness.class:


hiding FrangiVesselness.class,and rejarring the jar.

With this tweak, Fiji launches, has nearly full functionality, but,
as expected, the Frangi Vesselness command won’t run. However, its
menu entry (Process>Filters>Frangi Vesselness) still shows up in
the Fiji menu bar. Trying to run it throws the sensible error:

[ERROR] Cannot create module: net.imagej.ops.commands.filter.FrangiVesselness
Caused by: java.lang.ClassNotFoundException: net.imagej.ops.commands.filter.FrangiVesselness

I see in the source:

the plugin annotation:

@Plugin(type = Command.class, menuPath = "Process>Filters>Frangi Vesselness")
public class FrangiVesselness<T extends RealType<T>> implements Command {

which, I assume, tells the Fiji / ImageJ2 / SciJava framework
where to put the menu entry. Because the menu entry still shows
up after hiding the class, I look elsewhere, and find:

META-INF/json/org.scijava.plugin.Plugin (in imagej-ops-0.39.0.jar)

It contains the entry:

{"class":"net.imagej.ops.commands.filter.FrangiVesselness","values":{"menuPath":"Process>Filters>Frangi Vesselness","type":"org.scijava.command.Command"}}

Is this how the Frangi Vesselness menu item gets wired up to FrangiVesselness.class? Is this json entry generated from the @Plugin annotation in If so, is the json entry generated by the java compiler, or by a separate SciJava framework tool that is run at build time? This is probably more of a pure java question, but is the @Plugin annotation preserved in any way in FrangiVesselness.class or is it absent from the class file and only shows up in some non-java resource, such as the json file?

(Just to clear up a related point of confusion on my part,
am I right that


is unrelated to


other than implementing a similar algorithm? And that
DefaultFrangi is not accessible from the stock Fiji menu
bar? And while we’re on the subject, I see in its source,

public class DefaultFrangi<T extends RealType<T>, U extends RealType<U>> extends
	AbstractUnaryComputerOp<RandomAccessibleInterval<T>, RandomAccessibleInterval<U>>
	implements Ops.Filter.FrangiVesselness

Where is the source that defines the Ops.Filter.FrangiVesselness
interface? I am looking for something like net/imagej/ops/,
but don’t see it anywhere.)

Thanks, mm.




Others might correct me or extend the explanation, but in short, SciJava makes use of standard Java annotation processing throughout its architecture, e.g. with @Plugin, @Parameter and @Service annotations.

See also:

I’m not sure, others might know…

No, that’s wrong.

The Command defined by the FrangiVesselness class calls the OpService to run the filter.frangiVesselness op:

The OpService then looks up all possible candidate ops that match the required op type and inputs, and then runs the best matching op. In this case, there’s only one possible op available: DefaultFrangi.

This architecture allows to add different (possibly better and/or faster) implementations at a later time, without the need to change the calling code.

This is a bit tricky, because the Ops interfaces are generated from templates at compile time.

  • The definition is in Ops.list
  • … and the generated classes live in the subfolder ./target/generated-sources/from-template/net/imagej/ops of your Maven project once you’ve run mvn.

Hope that clarifies the situation a bit for you. Don’t hesitate to ask more specific follow-up questions. Someone will be able to answer… :slight_smile:


Thank you for your reply Jan. It clears up a lot of things.

Yes, thanks. I should have seen this, as
clearly doesn’t implement any actual algorithm.

Thanks, I’m starting to get a cartoon picture of how these things
fit together. I’ll take a deeper look at some point and and follow
up with further questions as they arise.

Yes, this is a good start. I’ll be back …

Thanks again, mm.