Login  Register

Re: How to read 'raw' data as 32 bit unsigned in Java

Posted by Kenneth Sloan-2 on Feb 13, 2019; 3:07am
URL: http://imagej.273.s1.nabble.com/How-to-read-raw-data-as-32-bit-unsigned-in-Java-tp5021772p5021783.html

You started with a scalar (float) image.  You converted it to an 8-bit integer image.
The convertToRGB() simply replicates the 8-bit byte for the R,G,B channels and sets A==0;

By the time you converted to RGB, you had only 8 bits.

get(500) uses ImageProcessor.get() and returns an int.  I always treat images
as 2D and avoid fetching pixels by pretending to know how they are laid out
in memory - but I presume that get() returns the bits representing RGBA as an int.
I suppose stepping through a 1D array is "faster", but (to my taste) that's a false economy.

A negative value indicates that the R value is > 127.  Since it's a grayscale image, that
makes R=G=B > 127, so "brighter than middle gray".

None of this says anything about how many bits you started with.  If you want to know
the range of values in the original data, I recommend that you compute that yourself while
processing the original 32 bit ints.

How did you end up creating the ORIGINAL image - did you import it as a FloatProcessor, or
did you build your byte array and construct 32 bit ints?  

For absolute control, I would use your byte array methods to construct pixel values, determine
the range of actual values, and then create a (scaled, if necessary) 16-bit ShortProcessor.

I would then set min and max, and convert directly from the ShortProcessor to a ColorProcessor.

For ease of programming, I would try to import the original image as a 32-bit float image, and
then use get().  I'm guessing (because I don't even do this) that get() will return the actual 32-bits
used to represent the Float.  But, I could be wrong about that.  All of this simply avoids the bit-twiddling
you are doing with the byte array.  I would then proceed as above: determine range, create a (possibly scaled)
16-bit ShortProcessor, and convert to RGB.  I would probably only use the "import as Float" method if I
were *certain* that the raw data was no bigger than 24 bits.

The acid test is to display the image.  I might also create a test suite consisting of (small) 32-bit
images with known values testing the various boundaries - say 0xffffffff, and 0x7fffffff, and 0x00ffffff, and 0x0000ffff, for starters.  I would start with images that had constant values (one image for each of the above values), and then
images consisting of ramps from 0 to each of the above values.  Finally, ramps that start a bit higher than 0, to test
your setting of min/max.  That's 12 test images in all.

Have fun!

--
Kenneth Sloan
[hidden email]
Vision is the art of seeing what is invisible to others.




 

> On Feb 12, 2019, at 18:22, Robert Lockwood <[hidden email]> wrote:
>
> OK, I'm soldiering on...
> My IDE tells me I need a cast:
>        ColorProcessor cp = (ColorProcessor)
> sp.convertToByteProcessor(true).convertToRGB()
> sp.getMin() & sp.getMax() return reasonable values.
> cp.get(500) for both .convertToRGB() and convertToColorProcessor() return
> negative values. Apparently there are 3 color components so there's no
> alpha.  Does this mean that the data are 24 bit?
>
>
>
>
> On Tue, Feb 12, 2019 at 3:12 PM Kenneth Sloan <[hidden email] <mailto:[hidden email]>>
> wrote:
>
>> Once you have a ShortProcessor, you can convert directly to a
>> ColorProcessor using:
>>
>>        ColorProcessor cp = sp.convertToColorProcessor();
>>
>> I am not sure how the 16-bit values are converted to 8+8+8 RGB.  You may
>> have to call
>>
>>        sp.setMinAndMax(min,max);
>>
>> before the conversion.
>>
>> But...it looks as if the safest route might be:
>>
>>        sp.setMinAndMax(min,max); // in case you want to adjust these
>>        ColorProcessor cp = sp.convertToByteProcessor(true).convertToRGB()
>>
>> I'm unclear on the difference between convertToRGB() and
>> convertToColorProcessor.  From the documentation:
>>
>> public ColorProcessor <
>> https://imagej.nih.gov/ij/developer/api/ij/process/ColorProcessor.html <https://imagej.nih.gov/ij/developer/api/ij/process/ColorProcessor.html>>
>> convertToColorProcessor()
>> Returns an RGB version of this image as a ColorProcessor.
>>
>> public ImageProcessor <
>> https://imagej.nih.gov/ij/developer/api/ij/process/ImageProcessor.html <https://imagej.nih.gov/ij/developer/api/ij/process/ImageProcessor.html>>
>> convertToRGB()
>> Returns an RGB version of this image as a ColorProcessor.
>>
>> The only difference is in the declared type of the returned processor.
>> Both are actually "ColorProcessor", but notice
>> that "convertToRGB()" returns an "ImageProcessor" (which just happens to
>> be a "ColorProcessor".
>>
>> Can someone explain the reason for this apparent duplication?
>>
>> --
>> Kenneth Sloan
>> [hidden email]
>> Vision is the art of seeing what is invisible to others.
>>
>>
>>
>>
>>
>>> On Feb 12, 2019, at 16:21, Robert Lockwood <[hidden email]> wrote:
>>>
>>> Thanks, Kenneth, this is a stand-alone program to detect adjacent pixels
>>> that have t:
>>> he same values and save the probably converted data as grayscale
>>> with the detected pixels in color.
>>>
>>> Here is the code I have now, compiles and runs but unfinished
>>>
>>>           // read raw image file
>>>           byte[] bytes = Files.toByteArray(dFile);
>>>           // represent as integers
>>>           IntBuffer rawIntImage = ByteBuffer.wrap(bytes).asIntBuffer();
>>>
>>>           // set up for data using imageJ
>>>           final ImagePlus imp = IJ.createImage(dFile.getName(),
>> "16-bit",
>>>                   NCOLS, NROWS, 1);
>>>           final ShortProcessor sp = (ShortProcessor) imp.getProcessor();
>>>           final short[] shortImage = (short[]) sp.getPixels();
>>>           int index = 0;
>>>           while(rawIntImage.hasRemaining()) {
>>>               shortImage[index++] = (short) rawIntImage.get();
>>>           }
>>>           // sp.convertToByte(true).convertToRGB(); // What is returned
>>> here?
>>>
>>> I need "IntBuffer rawIntImage" to use to detect the adjacent duplicate
>>> pixels
>>> I'm assuming that 'convertToByte' will do the brightness and contrast
>>> mapping returning a ByteProcessor, is that correct?  Then I need to
>> convert
>>> to RGB ?
>>>
>>>
>>> On Tue, Feb 12, 2019 at 1:19 PM Kenneth Sloan <[hidden email]>
>>> wrote:
>>>
>>>> Ah...if the data are really 16-bit, then my recommendation is to
>>>> import the image as a 32-bit float, apply Brightness/Contrast,
>>>> and use an OVERLAY to highlight the problem pixels.
>>>>
>>>> But, if you really want RGB, import as 32-bit, adjust,
>>>> and use Image->Type->RGB and you are done.
>>>>
>>>> Note that this loses precision (but, you can't see much more than
>>>> 8-bits on the screen anyway).
>>>>
>>>> You also lose access to the actual original pixel values - but
>>>> perhaps that's not important.
>>>>
>>>> I do this routinely with data that claim to be 32-bit floats in the
>>>> range [0.0..1.0).  These are essentially 24-bit unsigned integers.
>>>>
>>>> It looks like there is no reason for you to import a byte array
>>>> and twiddle bits to construct ints.  Fiji will happily import
>>>> the image as 32-bit float, adjust brightness/contrast, and convert
>>>> to RGB (if that's what you want).
>>>>
>>>> Is your code to find and highlight problem pixels written as a
>>>> Fiji plugin, or as a stand-alone Java program?
>>>>
>>>>
>>>> --
>>>> Kenneth Sloan
>>>> [hidden email]
>>>> Vision is the art of seeing what is invisible to others.
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>> On Feb 12, 2019, at 14:48, Robert Lockwood <[hidden email]>
>> wrote:
>>>>>
>>>>> When I look at the imported images in Fiji I apply Brightness/Contrast
>>>> with
>>>>> auto for a decent image.
>>>>>
>>>>> If I can do the same thing in Java and then convert to RGB I can then
>>>>> manipulate the pixels I've identified by my comparison code.
>>>>>
>>>>> BTW the values in my 32 bit first came from the camera as defined as C
>>>>> unsigned shorts so all the values are less than 64K so I can extract
>> the
>>>>> Java short values easily.
>>>>>
>>>>> On Tue, Feb 12, 2019 at 11:20 AM Kenneth Sloan <
>> [hidden email]>
>>>>> wrote:
>>>>>
>>>>>> If you do this in Java, I think there are a couple of workarounds.
>>>>>>
>>>>>> Here's one idea: Since you already can "process these data as ints",
>> you
>>>>>> should be able to create your own 8-bit RGB image.  Of course, you
>> only
>>>>>> get 8-bits of gray scale.
>>>>>>
>>>>>> Here's another idea: you should be able to import the image as a
>> 32-bit
>>>>>> float image.  If there is non-zero data in the upper 8 bits, the image
>>>>>> will look
>>>>>> very strange, but at least you'll have a 32-bit array.  Next, take
>> each
>>>>>> 32-bit float pixel value and use Float.floatToRawIntBits to get
>>>>>> your 32-bit integer values.
>>>>>>
>>>>>> Since you can already create the int values from your byte array, I
>>>> would
>>>>>> start
>>>>>> with that idea.
>>>>>>
>>>>>> Be careful about signed/unsigned.
>>>>>>
>>>>>> Finally, I would consider creating a 24-bit integer gray-scale value,
>>>> and
>>>>>> using
>>>>>> that as a 32-bit float (using Float.intBitsToFloat).  This gives you a
>>>>>> float image
>>>>>> where the values are between 0.0 and 1.0.  You can then use an Overlay
>>>> to
>>>>>> highlight
>>>>>> the problem pixels.  Use either idea above to get a 32-bit unsigned
>>>> value,
>>>>>> and
>>>>>> scale it to 24-bits.  Convert that to a float, and store it in a
>> 32-bit
>>>>>> float image.
>>>>>>
>>>>>> Or, simply create a 16-bit integer gray scale image, and use an
>> Overlay.
>>>>>>
>>>>>> Your choice may depend on what you know about the range of values.
>> The
>>>>>> advantage of
>>>>>> my 24-bit version above is that you have a bit more flexibility in
>>>>>> dynamically adjusting
>>>>>> the range of displayed gray levels.  The disadvantage is that the
>>>> numbers
>>>>>> will all
>>>>>> be presented as (0.0..1.0) instead of [0..65535] (for the 16-bit
>>>> version)
>>>>>>
>>>>>> --
>>>>>> Kenneth Sloan
>>>>>> [hidden email]
>>>>>> Vision is the art of seeing what is invisible to others.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> On Feb 12, 2019, at 12:37, Herbie <[hidden email]> wrote:
>>>>>>>
>>>>>>> Good day,
>>>>>>>
>>>>>>> ImageJ doesn't support 32 bit integer gray scale images.
>>>>>>>
>>>>>>> Supported are 8bit and 16bit integer as well as 32bit float.
>>>> Furthermore
>>>>>> 24bit (3 X 8bit) RGB and index color 8bit.
>>>>>>>
>>>>>>> Regards
>>>>>>>
>>>>>>> Herbie
>>>>>>>
>>>>>>> :::::::::::::::::::::::::::::::::::::::::::::
>>>>>>> Am 12.02.19 um 19:15 schrieb Robert Lockwood:
>>>>>>>> Working with Java I have raw data files with 32 bit integer gray
>> scale
>>>>>> data
>>>>>>>> which I read into a byte[] array.  I process these data as ints
>>>> looking
>>>>>> for
>>>>>>>> adjacent pixels that have the same value in order to debug a problem
>>>>>> with
>>>>>>>> the camera.
>>>>>>>> I'd like to create a scaled grayscale RGB from the original data so
>>>>>> that I
>>>>>>>> may color the detected adjacent pixels to allow us to detect
>> patterns
>>>>>>>> visually but I don't understand how to create and populate a
>> grayscale
>>>>>>>> integer ImageJ array and have not found an example by Google
>>>> searching.
>>>>>>>> How do I do this?
>>>>>>>> TIA
>>>>>>>> --
>>>>>>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>>>>>
>>>>>>> --
>>>>>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>>>>
>>>>>> --
>>>>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>>>>
>>>>>
>>>>> --
>>>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>>
>>>> --
>>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>>
>>>
>>> --
>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>
>>
>> --
>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html <http://imagej.nih.gov/ij/list.html>
>>
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html <http://imagej.nih.gov/ij/list.html>

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html