imagej / imagej-ops

ImageJ Ops: "Write once, run anywhere" image processing
https://imagej.net/libs/imagej-ops
BSD 2-Clause "Simplified" License
88 stars 42 forks source link

Map namespace methods type safety #612

Open Xanthorapedia opened 5 years ago

Xanthorapedia commented 5 years ago

When I was trying to copy an image converted with LUT to a freshly created Img, the following happens:

RandomAccessibleInterval<FloatType> floatImg = ArrayImgs.floats(128, 128);
RandomAccessibleInterval<ARGBType>  argbRAI = Converters.convert(floatImg, new RealLUTConverter<FloatType>(0, 1, ColorTables.GRAYS), new ARGBType());
Img<ARGBType> argbImg = ArrayImgs.argbs(128, 128);
ops.copy().rai(argbImg, argbRAI);

Output:

net.imglib2.converter.read.ConvertedRandomAccessibleInterval cannot be cast to net.imglib2.IterableInterval

java.lang.ClassCastException: net.imglib2.converter.read.ConvertedRandomAccessibleInterval cannot be cast to net.imglib2.IterableInterval
    at net.imagej.ops.map.MapUnaryComputers$IIToIIParallel.compute(MapUnaryComputers.java:87)
    at net.imagej.ops.copy.CopyRAI.compute(CopyRAI.java:90)
    at net.imagej.ops.copy.CopyRAI.compute(CopyRAI.java:54)
    at net.imagej.ops.special.hybrid.UnaryHybridCF.run(UnaryHybridCF.java:75)
    at net.imagej.ops.special.hybrid.UnaryHybridCF.run(UnaryHybridCF.java:97)
    at org.scijava.command.CommandModule.run(CommandModule.java:199)
    at net.imagej.ops.OpEnvironment.run(OpEnvironment.java:950)
    at net.imagej.ops.OpEnvironment.run(OpEnvironment.java:157)
    at net.imagej.ops.copy.CopyNamespace.rai(CopyNamespace.java:167)
    ...

The cause seems to me that while matching ops, a ConvertedRandomAccessibleInterval is recognized as directly convertible to an II in DefaultOpMatchingService.canConvert() and this leads the op service to believe that IIToIIParallel is a suitable op for the task. I haven't dug deeper than that. Any insights?

Xanthorapedia commented 4 years ago

The problem seems to be that when CopyRAI is looking for suitable computers, IIToIIParallel instead of IIToRAIParallel is selected since the second argument can be cast into II, which outputs an II instead of RAI.

A similar problem occurs when calling ops.map() with arguments being both II and RAI but cast into RAI. The selected method signature is map(RAI, RAI) -> RAI, but op matching always returns IIToII-ish ops, which returns an II.