读取图像的像素值

4

我正在尝试在使用Grassroots DICOM (GDCM)库的简单C++应用程序中读取DICOM文件中包含的图像的像素值。当读取文件元数据时,我收到有关图片的以下信息:

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

考虑到图像的分辨率为256x256且为MONOCHROME2类型,我预计像素缓冲区长度为256x256=65536个元素,但实际上它有131072个元素。
如果我使用MATLAB导入像素数据,我会得到在0-850范围内的65536个值,其中0代表黑色,850代表白色。
当我查看从GDCM读取到的像素缓冲区(在我的C++应用程序中)时,像素缓冲区具有131072个元素,其中每个偶数索引元素的范围为-128至+127,而每个奇数索引元素的范围为0-3,如下所示:
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 

这个值的排列方式代表什么意思?这是单色图像的典型像素表示吗?我已经搜索了“图像像素结构”等关键词,但找不到我要找的东西。是否有资源可以帮助我理解这些值的排列方式以及它们如何与每个像素相关联?

1
"INT16" 意味着每个像素都是由两个字节组成的整数。 - Christopher Oicles
谢谢,那帮了很大的忙。有什么好的方法将它们组合成一个INT16吗?我考虑使用类似 c = (b << 8) + a; 的东西,其中“a”是LSB,“b”是MSB,但当“a”为有符号时,这种方法不起作用。此外,“黑色”如何被认为是0,当我有负值时?我猜测负值不能被认为比“黑色”更黑? - MrCravon
你的想法是正确的,但你应该将所有字节和双字节值视为无符号。我不确定你的代码是什么样子的,但你可以从将字节读取为“unsigned char”开始,而不是“char”,或者你可以早期转换为无符号,或者晚期转换为无符号并只清除任何剩余的符号扩展位,例如:unsigned short c = (static_cast<unsigned short>(b) << 8) + (static_cast<unsigned short>(a) & 0xff);。这有点丑陋,但这种技术在大多数情况下都能奏效。 - Christopher Oicles
非常感谢,非常有效!现在我得到了与MATLAB提供的完全相同的值。 - MrCravon
1
或者你可以重新解释char指针指向的数据内存为int16_t *pixels = reinterpret_cast<int16_t *>(char_pointer);(或者对于无符号数据使用uint16_t,但如果我理解头信息正确的话,你有的是有符号数据)。然后int16_t pixel = pixels[256*y + x];。这只有在主机平台和数据具有相同的字节顺序时才有效,否则你必须交换字节以获取正确的值,或者执行自己的((a<<8) | b)操作,并按正确的顺序提取a b - Ped7g
关于负黑色... 好吧,16位有符号类型的范围是-32768..32767。您可能希望将值归一化到某个预期的范围内?比如搜索数据的最小/最大值,然后使用线性投影到0..255?这取决于您想要什么,任何事情都有可能。 - Ped7g
1个回答

1

我使用这段代码来读取16位的MONOCHROME2 Dicom文件:

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);
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接