转自:https://blog.csdn.net/ancewer/article/details/73277895 有删改
当你看这个帖子的时候,假设你也因为这个问题而感到困惑。
在使用这个函数的时候纠结了很久,各种google、百度都没查到相关资料,测试了好多次,并计算了许多二进制像素值,才终于搞明白,getoutdata()里的参数到底应该怎么写;
首先我们需要弄清楚dicom文件中单个像素值是怎么存的,说下一般的情况,以16位二进制方式存储为例,分析需要通过pixel模块的,bitstored, bitsallocated, highbit, pixel representation这四个值。
- pixel representation
pixel representation的值有0和1两种,0代表无符号,1代表有符号,比如二进制1001如果是无符号存储,表示9,如果是有符号(第一位代表符号位)的话就是-1;二进制0001不管是有符号还是无符号都代表1。 - bitsallocated
bitsallocated表示用多少位来储存,通俗来说就是开辟多少空间来存一个像素值,bitsallocated的存在是为了凑整,8或16或32,方便二进制计算. - bitstored
在CT中一般bitsallocated=16位,因为16位所占空间很大,肯定是用不完的,所以又有bitstored这个值来表示用bitsallocated中的多少位来存像素值,剩余几位全部置0就行了。 - highbit
因为像素值可能是有符号或无符号,highbit这个值的存在是为了确定符号位(Highbit位是符号位,则有符号时有效位只有bitsstored-1位)。
下面举几个例子:
- 例1:pixel representation=0, bitsallocated=16, bitsstored=12, highbit=11,假设像素值为100,按照标准存储如下:
|0000|0000|0110|0100| - 例2:pixel representation=1, bitsallocated=16, bitsstored=12, highbit=11,假设像素值为100,按照标准存储如下:
|0000|1000|0110|0100| - 例3:pixel representation=1, bitsallocated=16, bitsstored=16, highbit=15,假设像素值为100,按照标准存储如下:
|1000|0000|0110|0100|
特别注意
其实上面例2、例3都是错的,没看出来么?
上面的储存方式是我们人脑所方便理解的,但对于计算机而言,负数如果是这么存储的话,计算机处理时候需要先做个判断,第一位是不是1,然后再计算,这显然对于傻瓜的只能处理0、1的计算机而言是个沉重的负担,所以负数的存储用了补码(想深入理解原码、反码、补码推荐博客),对于正数而言补码还是其本身,对于负数而言补码是撇除符号位后进行反码运算后+1。
所以:
- 例2的真实存储情况是|0000|1111|1001|1100|
其实例2这种情况只是我臆想的,真是应该是不存在的,一般按照例1或例3这种比较规律的方式,当然,储存情况是厂家订制的,鬼知道他们会怎么干。 - 例3的真实存储情况是|1111|1111|1001|1100|
考虑大端小端后
前面都是没有考虑大小端情况,对于不同系统存储方式有大端、小端的区别(大端、小端知识可以参考博文),所以若是大端的则不用变化,如果是小端,则结果为:
- 例1的存储情况是|0100|0110|0000|0000|
- 例2的存储情况是|1100|1001|1111|0000|
- 例3的存储情况是|1100|1001|1111|1111|
关于getoutdata()
DicomImage类中getoutdata()函数的使用与上述储存情况息息相关,函数参数作用是取bitsstored的后面多少位,函数参数设为bitsstored的值,然后读出的来的值为实际像素值(自己对有符号无符号进行转换)
DicomImage *image = new DicomImage("test.dcm");
Uint16* a= (Uint16*)image->getOutputData(12);
vector<Uint16> PixelData;
for (int i = 0; i < 512 * 512; i++)
{PixelData.push_back(*(a + i));
}