I was curious (and procrastinating)… but couldn’t solve it.
Here’s a Groovy script that investigates:
import ij.ImagePlus
import ij.process.ShortProcessor
import javax.imageio.ImageIO
import java.awt.image.BufferedImage
import java.awt.image.IndexColorModel
// Create a 16-bit image
int width = 256
int height = 256
def ip = new ShortProcessor(width, height)
for (int i = 0; i < width*height; i++)
ip.setf(i, i)
// Create a random 16-bit LUT
int n = Math.pow(2, 16)-1 as int
def r = new byte[n]
def g = new byte[n]
def b = new byte[n]
def rand = new Random()
rand.nextBytes(r)
rand.nextBytes(g)
rand.nextBytes(b)
def model = new IndexColorModel(16, n, r, g, b)
// Set the color model (ok until we try to display it...)
ip.setColorModel(model)
// Create a 16-bit BufferedImage
def raster = model.createCompatibleWritableRaster(width, height)
def buffer = raster.getDataBuffer()
System.arraycopy(ip.getPixels(), 0, buffer.getData(), 0, buffer.getData().length);
def img = new BufferedImage(model, raster, false, null)
// Create an RGB version by drawing it
def img2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
def g2d = img2.createGraphics()
g2d.drawImage(img, 0, 0, null)
g2d.dispose()
// Optionally write the 16-bit image directly (change the path!)
// ImageIO.write(img, "PNG", new File("testing_lut16.png"))
// Optionally write the 'painted' RGB 16-bit version of the 16-bit image (change the path!)
// ImageIO.write(img2, "PNG", new File("testing_lut16_RGB.png"))
// Show the RGB version in ImageJ
def imp16RGB = new ImagePlus("Original 16-bit", img2)
imp16RGB.show()
// Try to show the image in ImageJ (doesn't work!)
// Fails with java.lang.IllegalArgumentException: Raster ByteInterleavedRaster: width = 256 height = 256 #numDataElements 1 dataOff[0] = 0 is incompatible with ColorModel IndexColorModel: #pixelBits = 16 numComponents = 3 color space = java.awt.color.ICC_ColorSpace@384e4aaa transparency = 1 transIndex = -1 has alpha = false isAlphaPre = false
def imp16 = new ImagePlus("Original 16-bit", ip)
imp16.show()
Basically, you can create a 16-bit IndexColorModel
. And you can pass it to a ShortProcessor
, but ImageJ will internally use an 8-bit representation for display and there it goes wrong.
If the BufferedImage
was displayed by drawing it to a canvas, that it should work - as shown by creating the RGB version in the above code. But the fact that an 8-bit image is being generated instead using the same color model appears to thwart this.
I’d be very interested in any solution I’m missing. Otherwise I’d tend towards either going for RGB (and preferably storing a reverse LUT to be able to regain the original value from the packed RGB representation), or else trying to just shuffle the labels.