4
votes

I am trying to read the pixel values of an image contained in a DICOM file in my simple c++ application using the Grassroots DICOM (GDCM) library. When reading the file metadata I get the following information about the picture:

Bits allocated: 16
Bits Stored: 16
High Bit: 15
Unsigned or signed: 1
Samples pr pixel: 1
Dimensions: 2
Dimension values: 256x256
Pixel Representation: 1
SamplesPerPixel: 1
ScalarType: INT16
PhotometricInterpretation: MONOCHROME2
Pixel buffer length: 131072

Given that the image has a resolution of 256x256 and is of MONOCHROME2 type, I expected the pixel buffer length to be 256x256=65536 elements but it is in fact 131072 elements long.

If I use MATLAB instead to import the pixel data i get exactly 65536 values in the range of 0 - 850 where 0 is black and 850 is white.

When i look at the pixel buffer i get from the GDCM readout in my c++ application the pixelbuffer is 131072 elements where every even indexed element is in the range -128 to +127 and every odd indexed element is in the range 0-3. like this:

Exerpt:    

PixelBuffer[120] = -35
PixelBuffer[121] = 0
PixelBuffer[122] = 51
PixelBuffer[123] = 2
PixelBuffer[124] = 71
PixelBuffer[125] = 2
PixelBuffer[126] = 9
PixelBuffer[127] = 2
PixelBuffer[128] = -80
PixelBuffer[129] = 2
PixelBuffer[130] = 87
PixelBuffer[131] = 3
PixelBuffer[132] = 121
PixelBuffer[133] = 3
PixelBuffer[134] = -27
PixelBuffer[135] = 2
PixelBuffer[136] = 27
PixelBuffer[137] = 2
PixelBuffer[138] = -111
PixelBuffer[139] = 1
PixelBuffer[140] = 75
PixelBuffer[141] = 1
PixelBuffer[142] = 103 

What does this arrangement of values mean? Is this some kind of typical pixel representation for monochrome images? I have been "googeling image pixel structure" and similar but cant find what I am looking for. Is there some resource available that can help me understand this arrangement of values and how they correlate to each pixel?

1
INT16 means each pixel is an integer consisting of 2 bytes.Christopher Oicles
Thanks, that helped a lot. What is a good way to combine them to one INT16. I thought about using something like c = (b << 8) + a; where "a" is LSB and "b" is MSB but that doesn't work when "a" is signed. Also, how is "black" considered 0 when I have negative values? I am guessing a negative value cant be considered "more black" than "black"?MrCravon
You have the right idea, but you should treat all bytes and double-byte values as unsigned. I'm not sure what your code looks like, but you might start by reading bytes as unsigned char instead of char, or you could cast to unsigned early, or cast to unsigned late and just zero out any leftover sign-extended bits like: unsigned short c = (static_cast<unsigned short>(b) << 8) + (static_cast<unsigned short>(a) & 0xff);. That is kind of ugly, but this technique is likely to work in most cases.Christopher Oicles
Thanks a lot, that worked great! Now i get exactly the same values that MATLAB provides.MrCravon
Or you can reinterpret the char pointer to the data memory as int16_t *pixels = reinterpret_cast<int16_t *>(char_pointer); (or use uint16_t for unsigned data, but if I understand that header info, you have signed data). Then int16_t pixel = pixels[256*y + x];. This works only when both host platform and the data have the same endianness, otherwise you must swap bytes to get the correct value, or do yours ((a<<8) | b), and fetch a b in correct order.Ped7g

1 Answers

1
votes

I use this code to read 16 bit MONOCHROME2 Dicom file:

byte[] signedData = new byte[2];
        List<int> tempInt = new List<int>();
        List<ushort> returnValue = new List<ushort>();

        for (i = 0; i < PixelBuffer.Length; ++i)
        {
            i1 = i * 2;
            signedData[0] = PixelBuffer[i1];
            signedData[1] = PixelBuffer[i1 + 1];
            short sVal = System.BitConverter.ToInt16(signedData, 0);

            int pixVal = (int)(sVal * rescaleSlope + rescaleIntercept);

            tempInt.Add(pixVal);
        }

        int minPixVal = tempInt.Min();
        SignedImage = false;
        if (minPixVal < 0) SignedImage = true;

        foreach (int pixel in tempInt)
        {
            ushort val;
            if (SignedImage)
                val = (ushort)(pixel - short.MinValue);
            else
            {
                if (pixel > ushort.MaxValue) val = ushort.MaxValue;
                else val = (ushort)(pixel);
            }

            returnValue.Add(val);
        }