ImagePlus, ImageProcessor <--> BufferedImage, for 16-bit unsigned gray image?
Posted by Bill Christens-Barry on Jul 24, 2006; 8:07pm
URL: http://imagej.273.s1.nabble.com/ImagePlus-ImageProcessor-BufferedImage-for-16-bit-unsigned-gray-image-tp3702045.html
I'm stumped in my efforts to move between an ImagePlus and a
BufferedImage for a TYPE_USHORT_GRAY image in a program that use ij.jar.
The main problem seems to be related to how to manipulate values in a
short array, given Java's lack of unsigned short integers. I've been
playng with ij-ImageIO BufferedImageCreator class, which has a
create(ij.process.ShortProcessor src) method that creates a
BufferedImage from a ShortProcessor, but this hasn't gotten me home yet.
I didn't see an obvious solution when I searched the list archives, and
wonder if anyone can set me straight on how to do this.
I have a 16-bit gray TIFF input image that has pixel values from 0 to
around 26722 (although they could range up to 65535). I want to invert
and linearly rescale these values so that they cover the range from 0 to
65535, with 0 --> 65535, and 26722 --> 0. In particular, I want to get
these values back into a BufferedImage that will be saved to disk and
used elsewhere in the program.
The following code yields an image that does not have the desired range
of values (0 to 65535). I've tried many different ways to manipulate the
values in :
my ImageProcessor ipin, but none of them result in an output image that
has the desired range of values. Here's my code:
public static void generateProcImage() {
ImagePlus imageProc = new ImagePlus(gelFile.getAbsolutePath());
//load the image
ImageProcessor ipin = new ShortProcessor(width, height);
ipin = imageProc.getProcessor();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
ipin.putPixel(x, y, (int) (2.4524736*ipin.getPixel(x, y)));
imageProc.setProcessor(null, ipin);
ipin.putPixel(x, y, (short) ((int) (65535 - (int)
(0xffff & ipin.getPixel(x, y))))); // I've tried all kinds of tricks here.
imageProc.setProcessor(null, ipin);
}
}
BufferedImage tempCB =
BufferedImageCreator.create((ShortProcessor) ipin);
File f2=new File(theGel.getProcessedImagePath() + "/" +
gelFile.getName().replaceAll(".tif", "") + "-PR.tif");
newGelImageFile = new File(theGel.getProcessedImagePath() + "/"
+ gelFile.getName().replaceAll(".tif", "") + "-PR.tif");
FileOutputStream f2b = null;
try {
f2b = new FileOutputStream(f2);
} catch (FileNotFoundException ex) {
ex.printStackTrace();
System.exit(0);
}
TIFFEncodeParam params = new TIFFEncodeParam();
params.setCompression(TIFFEncodeParam.COMPRESSION_NONE);
ImageEncoder encoder =
ImageCodec.createImageEncoder("TIFF",f2b,params);
if(encoder == null) {
System.out.println("imageEncoder is null");
System.exit(0);
}
try {
encoder.encode(tempCB);
//encoder.encode(tempBI);
} catch (IOException ex) {
System.exit(0);
}
}
Perhaps related, the ImageJ source code for TiffEncoder contains the
following (fragment):
public TiffEncoder (FileInfo fi) {
this.fi = fi;
fi.intelByteOrder = false;
bitsPerSample = 8;
samplesPerPixel = 1;
nEntries = 9;
int bytesPerPixel = 1;
switch (fi.fileType) {
case FileInfo.GRAY8:
photoInterp = fi.whiteIsZero?0:1;
break;
case FileInfo.GRAY16_UNSIGNED:
case FileInfo.GRAY16_SIGNED:
bitsPerSample = 16;
photoInterp = fi.whiteIsZero?0:1;
bytesPerPixel = 2;
break;
case FileInfo.GRAY32_FLOAT:
bitsPerSample = 32;
photoInterp = fi.whiteIsZero?0:1;
bytesPerPixel = 4;
break;
case FileInfo.RGB:
photoInterp = 2;
samplesPerPixel = 3;
bytesPerPixel = 3;
break;
case FileInfo.COLOR8:
photoInterp = 3;
nEntries = 10;
break;
default:
photoInterp = 0;
}
I see here that the case for GRAY16_UNSIGNED has no code. Why don't the
relevant variable values as for the other cases need to be assigned for
GRAY16_UNSIGNED?
As you can see, I'm really perplexed by the use of unsigned 16-bit
images in a world lacking 16-bit unsigned types. Thanks for any
explanations, pointers, or other comments.
Bill Christens-Barry