0

I want to display an image received in a short[] of pixels from a server. The server(C++) writes the image as an unsigned short[] of pixels (12 bit depth). My java application gets the image by a CORBA call to this server. Since java does not have ushort, the pixels are stored as (signed) short[].

This is the code I'm using to obtain a BufferedImage from the array:

private WritableImage loadImage(short[] pixels, int width, int height) {
    
    int[] intPixels = new int[pixels.length];

    for (int i = 0; i < pixels.length; i++) {
        intPixels[i] = (int) pixels[i];            
    }

    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    WritableRaster raster = (WritableRaster) image.getData();
    raster.setPixels(0, 0, width, height, intPixels);

    return SwingFXUtils.toFXImage(image, null);
}

And later:

 WritableImage orgImage = convertShortArrayToImage2(image.data, image.size_x, image.size_y);                   

 //load it into the widget
 Platform.runLater(() -> {
      imgViewer.setImage(orgImage);
  });

I've checked that width=1280 and height=1024 and the pixels array is 1280x1024, that matches with the raster height and width. However I'm getting an array out of bounds error in the line:

raster.setPixels(0, 0, width, height, intPixels);

I have try with ALL ImageTypes , and all of them produce the same error except for:

  • TYPE_USHORT_GRAY: Which I thought it would be the one, but shows an all-black image
  • TYPE_BYTE_GRAY: which show the image in negative(!) and with a lot of grain(?)
  • TYPE_BYTE_INDEXED: which likes the above what colorized in a funny way

I also have tried shifting bits when converting from shot to int, without any difference:

intPixels[i] = (int) pixels[i] & 0xffff;

So..I'm quite frustrated after looking for days a solution in the internet. Any help is very welcome

Edit. The following is an example of the images received, converted to jpg on the server side. Not sure if it is useful since I think it is made from has pixel rescaling (sqrt) :

enter image description here

dummyhead
  • 81
  • 2
  • 9
  • 2
    I'm not sure why you are using Swing in a JavaFX application. JavaFX provides a [WriteableImage](https://openjfx.io/javadoc/17/javafx.graphics/javafx/scene/image/WritableImage.html) that supplies a [PixelWriter](https://openjfx.io/javadoc/17/javafx.graphics/javafx/scene/image/PixelWriter.html) which can write pixels in a [PixelFormat](https://openjfx.io/javadoc/17/javafx.graphics/javafx/scene/image/PixelFormat.html) of a variety of [PixelFormat.Type](https://openjfx.io/javadoc/17/javafx.graphics/javafx/scene/image/PixelFormat.Type.html)s. – jewelsea Jul 01 '22 at 20:01
  • 1
    If the pixel format that you are using is not directly supported for the pixel data your server application is generating, then you will need to manipulate it to a supported format before writing it to your image. If you need assistance with that, you need to provide the example data so that somebody could try it out as well as a specification of how the data is actually encoded (down to the bit-level). Trying random encoding types and hoping it might work is not a good strategy. – jewelsea Jul 01 '22 at 20:04
  • By a bit-level data specification, I mean the same information provided in the [PixelFormat](https://openjfx.io/javadoc/17/javafx.graphics/javafx/scene/image/PixelFormat.html) javadoc that defines where and how the bits of data for the ARGB values are stored. If you really need it, the [PixelFormat source](https://github.com/openjdk/jfx/blob/86b854dc367fb32743810716da5583f7d59208f8/modules/javafx.graphics/src/main/java/javafx/scene/image/PixelFormat.java) contains the encoding implementations for the standard pixel format types. – jewelsea Jul 01 '22 at 20:10
  • You may be interested in [Can we make unsigned byte in Java](https://stackoverflow.com/questions/4266756/can-we-make-unsigned-byte-in-java) in case you need that to work with the data in your input stream. – jewelsea Jul 01 '22 at 20:16
  • Many thanks @jewelsea . I have made some attempts with PixelWriter without sucess. I totally lack of experience with image processing in java. I have included in the description an example of the received image converted to jpg in the server side, in case it helps – dummyhead Jul 03 '22 at 10:57
  • The image you posted is just a gray box. I don’t think it will help solve your problem. Without providing the pixel encoding information for your data, I don’t believe your question can be answered. – jewelsea Jul 04 '22 at 04:44
  • Thanks again @jewelsea. I thought someone could get the pixels information from that. Unfortunately, The only thing I kwow is that it is 12bits image in grayscale – dummyhead Jul 04 '22 at 10:07
  • New image example added. Also posted the solution I found. Thanks again for the help – dummyhead Jul 05 '22 at 17:56

1 Answers1

1

Well, finally I solved it.

Probably not the best solution but it works and could help someone in ether....

Being the image grayscale 12 bit depth, I used BufferedImage of type TYPE_BYTE_GRAY, but I had to downsample to 8 bit scaling the array of pixels. from 0-4095 to 0-255.

I had an issue establishing the higher and lower limits of the scale. I tested with avg of the n higher/lower limits, which worked reasonably well, until someone sent me a link to a java program translating the zscale algorithm (used in DS9 tool for example) for getting the limits of the range of greyscale vlues to be displayed: find it here

from that point I modified the previous code and it worked like a charm:

    //https://github.com/Caltech-IPAC/firefly/blob/dev/src/firefly/java/edu/caltech/ipac/visualize/plot/Zscale.java
    Zscale.ZscaleRetval retval = Zscale.cdl_zscale(pixels, width, height,
            bitsVal, contrastVal, opt_sizeVal, len_stdlineVal, blankValueVal);

    double Z1 = retval.getZ1();
    double Z2 = retval.getZ2();      
    
    try {
        int[] ints = new int[pixels.length];
        for (int i = 0; i < pixels.length; i++) {
            if (pixels[i] < Z1) {
                pixels[i] = (short) Z1;
            } else if (pixels[i] > Z2) {
                pixels[i] = (short) Z2;
            }                
            ints[i] = ((int) ((pixels[i] - Z1) * 255 / (Z2 - Z1)));

        }

        BufferedImage bImg
                = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
        bImg.getRaster().setPixels(0, 0, width, height, ints);
        return SwingFXUtils.toFXImage(bImg, null);

    } catch (Exception ex) {
        System.out.println(ex.getMessage());
    }
    return null;
dummyhead
  • 81
  • 2
  • 9