Multiple Ops matching error

Hello, @ctrueden @imagejan @haesleinhuepf

We are getting below error, running such a line of code:

final Histogram1d< T > histogram = opService.image().histogram( Views.iterable( rai ) );

We are sorry for not providing a reproducible example at this stage, but the code is in fact running fine on my computer (within in IntelliJ) but not at @Alex_H computer (within Eclipse). Thus, before spending (potentially a lot of) time to create a reproducible example, we were wondering whether someone would have some pointers what the issue could be.

Exception in thread "main" java.lang.IllegalArgumentException: Multiple 'net.imagej.ops.Ops$Image$Histogram' ops of priority 0.0:
1. (Histogram1d out) =
    net.imagej.ops.image.histogram.HistogramCreate(
        Iterable in,
        int numBins?)
2. (Histogram1d out) =
    net.imagej.ops.image.histogram.HistogramCreate(
        Iterable in,
        int numBins?)

Request:
-    net.imagej.ops.Ops$Image$Histogram(
        IntervalView)

Candidates:
1.     (Histogram1d out) =
    net.imagej.ops.image.histogram.HistogramCreate(
        Iterable in,
        int numBins?)
2.     (Histogram1d out) =
    net.imagej.ops.image.histogram.HistogramCreate(
        Iterable in,
        int numBins?)

    at net.imagej.ops.DefaultOpMatchingService.singleMatch(DefaultOpMatchingService.java:432)
    at net.imagej.ops.DefaultOpMatchingService.findMatch(DefaultOpMatchingService.java:97)
    at net.imagej.ops.DefaultOpMatchingService.findMatch(DefaultOpMatchingService.java:83)
    at net.imagej.ops.OpEnvironment.module(OpEnvironment.java:269)
    at net.imagej.ops.OpEnvironment.run(OpEnvironment.java:157)
    at net.imagej.ops.image.ImageNamespace.histogram(ImageNamespace.java:237)

Hi @Christian_Tischer

Unless I’m having a brain cramp, both candidates look identical to me. This usually happens if you somehow load two copies of imagej-ops. I’ve seen this happen in Eclipse when I’m working with multiple projects that reference each other, but both reference different version of imagej-ops (or have a different scijava parent). I’ve also seen it when I’ve packed (shaded) several jars into a plug-in and accidently packed imagej-ops in with it.

Without knowing your setup I’m not sure why you’d potentially have two version of imagej-ops, but the first thing I would do is check over your references and build process and look for clues.

3 Likes

Correct. I recently encountered the same issue in notebooks also, after re-running a cell that I had edited to get the latest version of ImageJ.

First run:

%classpath add mvn net.imagej imagej 2.0.0-rc-68

Second run:

%classpath add mvn net.imagej imagej 2.0.0-rc-71

… which pulled in two different versions of imagej-ops. (In this case the fix was as simple as to restart the kernel.)

1 Like

Thank you both very much for the answers!
Could you maybe also remind me how I specify one specific implementation of the particular Op?
…in order to circumvent the matching issue?

Hey @Christian_Tischer,

You find the explicit call in the implementation of the histogram() method in the namespace class: (in IntellIJ using CTRL_B):

Cheers,
Robert

1 Like

It’s true that with an ops.run invocation, you can request a specific implementation of a particular op—for example, ops.run(net.imagej.ops.image.histogram.HistogramCreate.class, ...). However, this will still invoke the ops matcher. It’s just that it will only match that specific given class, and therefore the match (from a human perspective) is trivial. However, in this case, there are two op plugins available with that same class name (presumably at different versions, as discussed above). So it may or may not work to invoke the desired op implementation in this way (@Christian_Tischer feel free to test it and report back here).

If you really want to completely avoid matching then your best bet is just to instantiate the op implementation class directly and use it. Here is a Groovy script (untested):

#@ OpService ops
histogramCreateOp = new net.imagej.ops.image.histogram.HistogramCreate()
histogramCreateOp.numBins = 128 // if you want to change it
histogramCreateOp.calculate(myInputImage)

Note that the above relies on Groovy’s ability to ignore field visibility, so that you can set the value of numBins directly even though it is private. To set it from Java is more annoying, but can be done. (The next iteration of Ops, currently in progress, tries to minimize these secondary parameter fields in favor of all arguments being part of the function call. So e.g. the HistogramCreate will be a BiFunction<Iterable<T>, Integer> so that you can call apply(myImage, numBins) directly instead of baking values into fields.)

Anyway, @Christian_Tischer, it is vital that you get your classpath sorted, since that is really the root of your issue. Otherwise, you may have other baffling problems that won’t go away just by hacking around the ops matcher.

2 Likes

In fact it is not my classpath, as it works on my computer, but we will do our best :slight_smile:

Maybe the new scijava-search class searcher could help. If you download the latest scijava-search snapshot and replace it in the problematic Fiji installation, then type HistogramCreate into the search bar, you might see multiple class matches from different JAR files.

1 Like