以下链接是本系列文章,不足之处,可在评论区讨论:
系列文章
以下链接中的代码是完整的且可运行的,链接如下,可按需下载:
dicom成像程序
本篇文章对应 专栏 从零讲解DICOM协议-成像协议中的文章DICOM成像协议剖析和DICOM成像协议实现思路,建议先看以上两篇文章以了解DICOM底层协议,有助于理解代码实现。
本篇文章讲解了DICOM解析引擎的实现思路和整体代码框架,并完成
- 读取DICOM文件至内存中
- 读取文件头到文件头对象中
- 按照元数据组特性读取元数据组中的各个DataElement
- 按照数据组特性读取数据组中的各个DataElement
- 如果PixelData是压缩格式,则用相应的解压算法解压
- CT值转BMP,保存BMP图像
协议剖析文章中阐述了,DICOM图像主要由以下几部分组成:
- 文件头
- 元数据组
- 数据组
除文件头外,元数据组和数据组都是由DICOM协议中的DataElement结构组成
DataElement由Tag,VR,Length,Value组成
Tag由group和elment组成,VR有显式和隐式之分,Length所在字节由显隐式和VR类型决定,Value长度是偶数等
复杂点的图像还包含SQ序列嵌套数据,多帧数据
更复杂的图像为不规范图像,即没有严格按照DICOM协议来组织结构,要兼容这些图像,需要对应的处理逻辑。可以通过收集各厂家设备和PACS输出的DICOM图像来测试系统兼容性,不断丰富处理逻辑,提高系统兼容性。
元数据组是小端显式格式
数据组受元数据组中的传输语法影响,PixelData受传输语法影响,有大小端和是否压缩之分,数据组除PixelData以外的只受传输语法的大小端格式影响。
基于以上,代码实现的思路如下:
5. 读取DICOM文件至内存中
6. 读取文件头到文件头对象中
7. 按照元数据组特性读取元数据组中的各个DataElement
8. 按照数据组特性读取数据组中的各个DataElement
9. 如果PixelData是压缩格式,则用相应的解压算法解压
一. 读取DICOM文件至内存中
使用父类FileRead,以设计模式中的模板模式结构组织,完成文件读取,并用抽象函数完成DICOM解析骨架搭建,具体实现由子类完成。头文件代码如下:
class FileRead
{
public:
FileRead();
//传入图像路径
FileRead(string path);
//传入图像内存指针和图像数据长度
FileRead(char *buffer, int len);
virtual ~FileRead() = 0;
public:
//读取DICOM数据至内存
virtual bool ReadFile(string path);
//释放内存指针
virtual void Clear() = 0;
protected:
//读取文件头
virtual void GetHead() = 0;
//读取元数据组
virtual void GetMetadata() = 0;