继续手搓DICOM解析 (3)

上回书说到,我们已经解析到了pixel数据了。但是这个TAG标签我们解析成了(ffe0,0010),其实应该是数据范围问题,读取使用的是char类型,它的范围是-127到127,如果是0到255就不会出现这个问题了。读到的低8位e0是没有问题的,它的二进制位11100000,16进制就是e0。高8位是11111111,是两个f。如果想变成7fe0,只需要&0x7fff就可以了。
Dicom 解析结果,最后的【7fe0,0010】
长度没有解析出来,可以根据行和列还有数据的位数进行计算就可以。这里面使用的是512X512X2,因为像素是16位,两个字节。

为了显示图像,我们使用了OpenCV库,进行快速显示,见代码如下:

void display(unsigned short *pixel, int rows, int cols){
    //
    cv::Mat dstMat(rows,cols,CV_16SC1,pixel);
    // 根据传入的行和列,创建16位单通道图像。
    cv::Mat image;
    cv::normalize(dstMat,image,0,255,cv::NORM_MINMAX,CV_8UC1);
    // 进行归一化,创建的图像是16位,我们显示器只可以显示8位,256个色阶
    // 因此,医学影像中有窗宽窗位的概念,窗位是在0-65535之间选一个像素
    // 位置,然后在此位置上下范围进行限制,上限-下限<=256。
    cv::imshow("DICOM Image",image);
    cv::waitKey(0);
}

然后我们就获取图像吧,代码如下:

void getPixel(std::fstream& file,unsigned short* pixel){
    // 512X512X2 bytes
    // 使用传递指针的方法将数据直接写到pixel中。
    // short是两字节16位(-32767~32767)
    // unsigned short 影像中常用的数据类型,16位(0~65535)
    int size=512*512;      // 像素大小(16位)
    int buffersize=size*2;     //读取时使用的数组的大小(8位)
    char byte[buffersize];     //读取时使用的数组
    file.read(byte,buffersize);

    for(int i=0;i<size;i++){
        *pixel=byte[2*i]|byte[2*i+1]<<8;
        // 使用小端字节序 little endian
        pixel++;
    }

}

然后进行测试,看看是不是直接就是数据文件。结果没错,就是Tag后面是VR,然后就是数据了。
在这里插入图片描述
本文中使用的DICOM数据在这里:https://download.csdn.net/download/kangdehua/89850946
这个DICOM文件呢,是BrainLab计划系统里面导出的图像,相对于CT机里面dicom出来的数据简化了很多信息,因此本文使用了此数据。

总结:
这个手搓项目基本完成了,除了最后一个Tag [7fe0,0010]这个有问题之外,其他的基本正确吧,有这方面的专业人员可以在评论区或者是私信中指导一下。
里面的重点是数据类型,小端字节序,指针传递。
数据类型
char: 通常占用一个字节,用于存储字符。
short: 短整型,占用两个字节,范围-32767~32767
unsigned short: 短整型,占用两个字节,范围0~65535
int: 整型,占用四个字节。
图像使用两个字节,需要使用unsigned short数组进行存储数据,否则会出现错误。char数组是C++中iostream中读取字符的最小单元,每次读取一个字节的整数单位。
一般商用软件都会自己写自己公司的DICOM解析方法的,使用DCMTK来验证自己的方法。但是也可以购买第三方的解析库,比如DCMTK,只要付钱就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值