This notebook is part of the PyImageJ Tutorial Series, and assumes familiarity with the ImageJ API. Dedicated tutorials for ImageJ can be found here.S
This notebook covers some basic troubleshooting with PyImageJ. Let's initalize ImageJ before exploring some troublehsooting options.
import imagej
# initialize ImageJ
ij = imagej.init()
print(f"ImageJ2 version: {ij.getVersion()}")
ImageJ2 version: 2.14.0/1.54f
Op
¶ij.py
is really good at converting numpy images into RandomAccessibleInterval
s. However many Op
s, like addPoissonNoise
, take other forms of ImageJ images, like IterableInterval
.
print(ij.op().help('filter.addPoissonNoise'))
Available operations: (RealType out) = net.imagej.ops.filter.addPoissonNoise.AddPoissonNoiseRealType( RealType out, RealType in, long seed?) (IterableInterval out) = net.imagej.ops.filter.addPoissonNoise.AddPoissonNoiseMap( IterableInterval out, IterableInterval in)
We can't call this Op
on a numpy array since it is a specialized type of RandomAccessibleInterval
, which does not extend IterableInterval
.
from skimage import io
# Create a numpy image using scikit
img = io.imread('https://imagej.net/images/clown.jpg')
ij.py.show(img)
print(type(ij.py.to_java(img)))
Operating in headless mode - the original ImageJ will have limited functionality.
<java class 'net.imagej.DefaultDataset'>
We can fix this by using transform.flatIterableView
on both the input and output, which will convert the ReferenceGuardedRandomAccessibleInterval
s into IterableInterval
s, allowing us to pass our numpy image into addPoissonNoise
:
import numpy as np
result = np.zeros(img.shape) # HINT: Uses float dtype, for more accurate noising.
imgIterable = ij.op().transform().flatIterableView(ij.py.to_java(img))
resIterable = ij.op().transform().flatIterableView(ij.py.to_java(result))
ij.op().filter().addPoissonNoise(resIterable, imgIterable)
ij.py.show(result)
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
Uh oh. Something's off with the data values—see next section!
If you need to troubleshoot op workings, look for implementations that use only IterableInterval
s or RandomAccessibleInterval
s. To find the implementations use the print(ij.op().help())
function.
For the multiply function the implementation we used is second to last (net.imagej.ops.math.IIToRAIOutputII$Multiply
)
If you need to troubleshoot op workings, look for implementations that use only IterableInterval
s or RandomAccessibleInterval
s. To find the implementations use the print(ij.op().help())
function.
For the multiply function the implementation we used is second to last (net.imagej.ops.math.IIToRAIOutputII$Multiply
)
This message is given either because (as described in the warning)
Let's be certain which is the culprit by checking some values of result
:
# grab the RGB values in a line from [0][5] to [0][10] in our image
print(result[0][5:10])
[[266. 148. 54.] [251. 169. 41.] [246. 168. 26.] [257. 148. 34.] [250. 168. 37.]]
Thus we not only have floats outside of [0..1] but also values outside of [0..255]; we are faulty of both points in the warning. We can fix this by first clipping the entire array within the integer range, then cast to uint8
so that the float range no longer applies:
ij.py.show(img.astype(int))
result = np.clip(result, 0, 255)
ij.py.show(result.astype(np.uint8))
Now our noisy image displays nicely alongside the original. Note that depending on your data this might not be the right path for you, but using clip
and astype
are great tools for rearranging your data within these bounds.
If you need to troubleshoot op workings, look for implementations that use only IterableInterval
s or RandomAccessibleInterval
s. To find the implementations use the print(ij.op().help())
function.
For the multiply function the implementation we used is second to last (net.imagej.ops.math.IIToRAIOutputII$Multiply
)
# print is required to render new lines
print(ij.op().help('multiply'))
Available operations: (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImageP$MultiplyByte( ArrayImg arg, byte value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImageP$MultiplyDouble( ArrayImg arg, double value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImageP$MultiplyFloat( ArrayImg arg, float value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImageP$MultiplyInt( ArrayImg arg, int value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImageP$MultiplyLong( ArrayImg arg, long value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImageP$MultiplyShort( ArrayImg arg, short value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImageP$MultiplyUnsignedByte( ArrayImg arg, byte value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImageP$MultiplyUnsignedInt( ArrayImg arg, int value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImageP$MultiplyUnsignedLong( ArrayImg arg, long value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImageP$MultiplyUnsignedShort( ArrayImg arg, short value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImage$MultiplyByte( ArrayImg arg, byte value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImage$MultiplyDouble( ArrayImg arg, double value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImage$MultiplyFloat( ArrayImg arg, float value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImage$MultiplyInt( ArrayImg arg, int value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImage$MultiplyLong( ArrayImg arg, long value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImage$MultiplyShort( ArrayImg arg, short value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImage$MultiplyUnsignedByte( ArrayImg arg, byte value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImage$MultiplyUnsignedInt( ArrayImg arg, int value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImage$MultiplyUnsignedLong( ArrayImg arg, long value) (ArrayImg arg) = net.imagej.ops.math.ConstantToArrayImage$MultiplyUnsignedShort( ArrayImg arg, short value) (IterableInterval out?) = net.imagej.ops.math.IIToIIOutputII$Multiply( IterableInterval out?, IterableInterval in1, IterableInterval in2) (NumericType out?) = net.imagej.ops.math.NumericTypeBinaryMath$Multiply( NumericType out?, NumericType in1, NumericType in2) (int result) = net.imagej.ops.math.PrimitiveMath$IntegerMultiply( int a, int b) (long result) = net.imagej.ops.math.PrimitiveMath$LongMultiply( long a, long b) (float result) = net.imagej.ops.math.PrimitiveMath$FloatMultiply( float a, float b) (double result) = net.imagej.ops.math.PrimitiveMath$DoubleMultiply( double a, double b) (RealType out) = net.imagej.ops.math.BinaryRealTypeMath$Multiply( RealType out, RealType in1, RealType in2) (IterableInterval out?) = net.imagej.ops.math.ConstantToIIOutputII$Multiply( IterableInterval out?, IterableInterval in, NumericType value) (PlanarImg arg) = net.imagej.ops.math.ConstantToPlanarImage$MultiplyByte( PlanarImg arg, byte value) (PlanarImg arg) = net.imagej.ops.math.ConstantToPlanarImage$MultiplyDouble( PlanarImg arg, double value) (PlanarImg arg) = net.imagej.ops.math.ConstantToPlanarImage$MultiplyFloat( PlanarImg arg, float value) (PlanarImg arg) = net.imagej.ops.math.ConstantToPlanarImage$MultiplyInt( PlanarImg arg, int value) (PlanarImg arg) = net.imagej.ops.math.ConstantToPlanarImage$MultiplyLong( PlanarImg arg, long value) (PlanarImg arg) = net.imagej.ops.math.ConstantToPlanarImage$MultiplyShort( PlanarImg arg, short value) (PlanarImg arg) = net.imagej.ops.math.ConstantToPlanarImage$MultiplyUnsignedByte( PlanarImg arg, byte value) (PlanarImg arg) = net.imagej.ops.math.ConstantToPlanarImage$MultiplyUnsignedInt( PlanarImg arg, int value) (PlanarImg arg) = net.imagej.ops.math.ConstantToPlanarImage$MultiplyUnsignedLong( PlanarImg arg, long value) (PlanarImg arg) = net.imagej.ops.math.ConstantToPlanarImage$MultiplyUnsignedShort( PlanarImg arg, short value) (IterableInterval out?) = net.imagej.ops.math.IIToRAIOutputII$Multiply( IterableInterval out?, IterableInterval in1, RandomAccessibleInterval in2) (RandomAccessibleInterval out) = net.imagej.ops.math.ConstantToIIOutputRAI$Multiply( RandomAccessibleInterval out, IterableInterval in, NumericType value)