Search code examples
scalebufferedimagegrayscale

Autoscale range 16-bit grayscale image in Java


I have an 12-bit grayscale image. I want to display it in Java with BufferedImage, and I find BufferedImage.TYPE_USHORT_GRAY is the most suitable. However, it makes my display image almost black (my pixels are in 0 ~ 4095 range).

How can I autoscale it to clearly display it?

Thanks so much.


Solution

  • If your data is stored as 16 bit samples (as indicated in the comments), then you can either:

    • Multiply the samples (by 16) to the full 16 bit range, and create a BufferedImage.TYPE_USHORT_GRAY image. Straight forward, but requires massaging and copying the data.

    • Or, you could also create a custom BufferedImage with a 12 bit ColorModel, and just use the data as is. Probably faster, but more verbose/complicated code.

    Here's the code to create an image using a 12 bit gray color model:

    WritableRaster raster = Raster.createInterleavedRaster(new DataBufferUShort(twelveBitData, twelveBitData.length), w, h, w, 1, new int[]{0}, null);
    
    ColorSpace gray = ColorSpace.getInstance(ColorSpace.CS_GRAY);
    ColorModel twelveBitModel = new ComponentColorModel(gray, new int[]{12}, false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
    BufferedImage image = new BufferedImage(twelveBitModel, raster, twelveBitModel.isAlphaPremultiplied(), null);
    

    Full, runnable demo program below.

    Alternatively, if your data had been stored as "one and a half byte" packed 12 bit samples, the simplest solution would be to first pad the data to full 16 bit samples.


    Demo program:

    public class TwelveBit {
    
        public static void main(String[] args) {
            int w = 320;
            int h = 200;
            short[] twelveBitData = new short[w * h];
    
            createRandomData(twelveBitData);
    
            WritableRaster raster = Raster.createInterleavedRaster(new DataBufferUShort(twelveBitData, twelveBitData.length), w, h, w, 1, new int[]{0}, null);
    
            ColorSpace gray = ColorSpace.getInstance(ColorSpace.CS_GRAY);
            ColorModel twelveBitModel = new ComponentColorModel(gray, new int[]{12}, false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
            BufferedImage image = new BufferedImage(twelveBitModel, raster, twelveBitModel.isAlphaPremultiplied(), null);
    
            showIt(image);
    
        }
    
        private static void createRandomData(short[] twelveBitData) {
            Random random = new Random();
            for (int i = 0; i < twelveBitData.length; i++) {
                twelveBitData[i] = (short) random.nextInt(1 << 12);
            }
        }
    
        private static void showIt(final BufferedImage image) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame("test");
                    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    
                    frame.add(new JLabel(new ImageIcon(image)));
    
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    }