byte[] to ushort[]
Asked Answered
B

2

10

Here is my question. Bear with me giving a little explanation:

I am reading tiff image into buffer; Each pixel of my tiff is represented by a ushort (16 bits data, non-negtive).

My image size is 64*64 = 4096. When my tiff is loaded into buffer, the buffer length is therefore 8192 (twice as much as 4096). I guess this is because in my buffer, the computer uses 2 bytes to store a single pixel value.

I want to get the value for any particular pixel, in this case should I combine every 2 bytes to 1 ushort?

For example: 00000000 11111111 -> 0000000011111111?

Here is my code:

public static void LoadTIFF(string fileName, int pxlIdx, ref int pxlValue)
        {
            using (Tiff image = Tiff.Open(fileName, "r"))
            {
                if (image == null)
                    return;

                FieldValue[] value = image.GetField(TiffTag.IMAGEWIDTH);
                int width = value[0].ToInt();

                byte[] buffer = new byte[image.StripSize()];
                for (int strip = 0; strip < image.NumberOfStrips(); strip++)
                    image.ReadEncodedStrip(strip, buffer, 0, -1);

                // do conversion here:
                //ushort bufferHex = BitConverter.ToUInt16(buffer, 0);            

                image.Close();

            }
        }

How do I read the byte[] buffer to ensure that I can get the 16 bits ushort pixel value?

Thanks

Bolingbroke answered 13/2, 2013 at 15:30 Comment(0)
L
5

Since each pixel is represented as 16 bits, it may be more convenient from a programming perspective to represent the byte[] as a ushort[] of half the length, but it is not required.

The best solution depends on how you want to consume the buffer.

You could just as easily define a helper method

ushort GetImageDataAtLocation(int x, int y) 
{ 
    offset = y * HEIGHT + x;
    return BitConverter.ToUInt16(buffer, offset);
}

that uses the input coordinates to determine the offset in the original byte[] and returns a ushort composed of the appropriate bytes.

If the TIFF stores data big-endian and your system is little-endian, you would have to reverse the order of the bytes prior to conversion. One way to do that is:

ushort GetImageDataAtLocation(int x, int y) 
{ 
    offset = y * HEIGHT + x;
    // Switch endianness e.g. TIFF is big-endian, host system is little-endian
    ushort result = ((ushort)buffer[0]) << 8 + buffer[1];
    return result;
}

If your code might ever run on platforms with different endianness (Intel and AMD are both little-endian) you can determine the endianness at runtime using

BitConverter.IsLittleEndian

For details on BitConverter, see http://msdn.microsoft.com/en-us/library/system.bitconverter.touint16.aspx

Luke answered 13/2, 2013 at 15:34 Comment(1)
Although the offset seems multiplication of 2, and y is actually (y-1), and same for x. Well depending on the 0 based or 1 based index.Bolingbroke
D
1

You need to do it in a loop: BitConverter.ToUInt16() takes 2 bytes, convert them to one ushort.

WARNING: as Eric pointed out, it has endianness problems (it always assumes endianness of the platform on which it is executing). Use Bitconverter only if you are sure the source byte stream is produced on a machine with the same endianness (in case of TIFF images, you probably cannot assume it).

You may use some LINQ... for example there is a nice Chuncks function here. You may use it as:

rawBytes.Chunks(2).Select(b => BitConverter.ToUInt16(b)).toArray()
Dupre answered 13/2, 2013 at 15:37 Comment(5)
No it doesn't... it has no way of implicitly knowing if the TIFF stored the data big- or little-endian. It jus assumes the data is the same endianness as the platform .NET is running on The order of bytes in the array must reflect the endianness of the computer system's architecture msdn.microsoft.com/en-us/library/…Luke
@EricJ. oh, you are right... I keep forgetting it, and I used to work on TIFF images to... I edited my answer, and upvoted yours since it is more completeTi
@EricJ. I would measure it before using it in production.. still, I am often surprised by how much optimized is IEnumerable in some cases. Especially if you use it for stream-like processing. And it has PLINQ. And it is nice to read :)Ti
For almost every use case I have come across, Linq is plenty fast compared to traditional alternatives (usually a bit slower, but never so much that it matters to the overall use case). I doubt that's the case though for image processing :-)Luke
Hmmm....bad news I have to do a double loop, but this is definitely useful information. Thanks!Bolingbroke

© 2022 - 2024 — McMap. All rights reserved.