视频教程:https://www.bilibili.com/video/av66144772
- DICOM(Digital Imaging and Communications in Medicine)即医学数字成像和通信,是医学图像和相关信息的国际标准(ISO 12052)。它定义了质量能满足临床需要的可用于数据交换的医学图像格式。
- https://www.dicomstandard.org/
一.Dicom文件的主要结构
-
主要包括文件头和像素数据两部分,文件头包括文件引言(Meta Information)和数据集(Data set)
1.数据元素的组成规则
- Tag:信息的唯一性编码,两个十六进制的数的组合(Group, Element)
* group的数值是偶数,代表是标准数据字典
* group的数值是奇数,代表是自定义的私有数据字典 - VR(Value Representations):DICOM定义得的数据类型
- Value Length(数据长度):所有的数据元素都应该为偶数长度,若为奇数,需要加空格或空。
* 奇数长度的字符串加空格
* 奇数长度的数字加空NULL - Value Field:数据值,长度必须是偶数
2.文件引言MetaInfo:标识一些常用信息,存储在0x0002Group里
Group | Element | Tag Description | 中文解释 | VR | VM | |
---|---|---|---|---|---|---|
0002 | 0000 | File Meta Information Group Length | Meta Info的长度 | UL | 1 | 180 |
0002 | 0001 | File Meta Information Version | Meta Info的版本 | OB | 1 | |
0002 | 0002 | Media Storage SOP Class UID | SOP Class UID 同Data Set里的SOP class UID | UI | 1 | |
0002 | 0003 | Media Storage SOP Instance UID | SOP Instance UID 同Data Set里的SOP Instance UID | UI | 1 | 算出 |
0002 | 0010 | Transfer Syntax UID | DataSet的编码方式 | UI | 1 | |
0002 | 0012 | Implementation Class UID | Implementation Class UID | UI | 1 | 实现类库决定 |
0002 | 0013 | Implementation Version Name | Implementation版本名 | SH | 1 | |
0002 | 0016 | Source Application Entity Title | 最后一个编辑该文件的实体 | AE | 1 | |
0002 | 0017 | Sending Application Entity Title | 网络上发送该文件的实体 | AE | 1 | |
0002 | 0018 | Receiving Application Entity Title | 网络上接收该文件的实体 | AE | 1 | |
0002 | 0100 | Private Information Creator UID | 私有信息的Creator的UID | UI | 1 | |
0002 | 0102 | Private Information | Meta里面的私有信息 | OB | 1 |
3.数据集DataSet:医学图像的相关的信息
Patient:病人信息,键值为Patient ID(0010, 0020)
Group | Element | Tag Description | 中文解释 | VR |
---|---|---|---|---|
0010 | 0010 | Patient’s Name | 患者姓名 | PN |
0010 | 0020 | Patient ID | 患者ID | LO |
0010 | 0030 | Patient’s Birth Date | 患者出生日期 | DA |
0010 | 0032 | Patient’s Birth Time | 患者出生时间 | TM |
0010 | 0040 | Patient’s Sex | 患者性别 | CS |
0010 | 1001 | OtherPatientNames | 患者其他姓名 | PN |
0010 | 1030 | Patient’s Weight | 患者体重 | DS |
0010 | 21C0 | Pregnancy Status | 怀孕状态 | US |
0010 | 4000 | Patient’s Comments | 患者注解 | LT |
Study:检查信息,键值为Study Instance UID(0020, 000D)
Group | Element | Tag Description | 中文解释 | VR |
---|---|---|---|---|
0008 | 0050 | Accession Number:A RIS generated number that identifies the order for the Study. | 检查号: RIS的生成序号,用以标识做检查的次序. | SH |
0020 | 0010 | Study ID | 检查ID. | SH |
0020 | 000D | Study Instance UID:Unique identifier for the Study. | 检查实例号: 唯一标记不同检查的号码. | UI |
0008 | 0020 | Study Date:Date the Study started. | 检查日期: 检查开始的日期. | DA |
0008 | 0030 | Study Time:Time the Study started. | 检查时间: 检查开始的时间. | TM |
0008 | 0061 | Modalities in Study | 一个检查中含有的不同检查类型. | CS |
0008 | 0015 | Body Part Examined | 检查的部位. | CS |
0008 | 1030 | Study Description | 检查的描述. | LO |
0008 | 0090 | Referring Physician's Name | 医师名称 | PN |
0010 | 1010 | Patient’s Age | 做检查时刻的患者年龄,而不是此刻患者的真实年龄. | AS |
Series:序列信息,键值为Series Instance UID(0020, 000E)
Group | Element | Tag Description | 中文解释 | VR |
---|---|---|---|---|
0020 | 0011 | Series Number:A number that identifies this Series. | 序列号: 识别不同检查的号码. | IS |
0020 | 000E | Series Instance UID:Unique identifier for the Series. | 序列实例号: 唯一标记不同序列的号码. | UI |
0008 | 0060 | Modality | 检查模态(MRI/CT/CR/DR) | CS |
0008 | 103E | Series Description | 检查描述和说明 | LO |
0008 | 0021 | Series Date | 检查日期 | DA |
0008 | 0031 | Series Time | 检查时间 | TM |
0020 | 0032 | Image Position (Patient):The x, y and z coordinates of the upper left hand corner of the image, in mm. | 图像位置: 图像的左上角在空间坐标系中的x,y,z坐标,单位是毫米.如果在检查中,则指该序列中第一张影像左上角的坐标. | DS |
0020 | 0037 | Image Orientation (Patient):The direction cosines of the first row and the first column with respect to the patient. | 图像方位: | DS |
0018 | 0050 | Slice Thickness:Nominal slice thickness, in mm. | 层厚. | DS |
0018 | 0088 | Spacing Between Slices | 层与层之间的间距,单位为mm | DS |
0020 | 1041 | Slice Location:Relative position of exposure expressed in mm. | 实际的相对位置,单位为mm. | DS |
0018 | 0023 | MR Acquisition | CS | |
0018 | 0015 | Body Part Examined | 身体部位. | CS |
Image:SOP影像信息,键值为SOP Instance UID(0008, 0018)
Group | Element | Tag Description | 中文解释 | VR |
---|---|---|---|---|
0008 | 0008 | Image Type:Image identification characteristics. | CS | |
0008 | 0018 | SOP Instance UID | SOP实例UID. | |
0008 | 0023 | Content Date:The date the image pixel data creation started. | 影像拍摄的日期. | DA |
0008 | 0033 | Content Time | 影像拍摄的时间. | TM |
0020 | 0013 | Image/Instance Number:A number that identifies this image. | 图像码: 辨识图像的号码. | IS |
0028 | 0002 | Samples Per Pixel:Number of samples (planes) in this image. | 图像上的采样率. | US |
0028 | 0004 | Photometric Interpretation:Specifies the intended interpretation of the pixel data. | 光度计的解释,对于CT图像,用两个枚举值 MONOCHROME1,MONOCHROME2. 用来判断图像是否是彩色的, MONOCHROME1/2是灰度图, RGB则是真彩色图,还有其他. | CS |
0028 | 0010 | Rows: Number of rows in the image. | 图像的总行数,行分辨率. | US |
0028 | 0011 | Columns: Number of columns in the image. | 图像的总列数,列分辨率. | US |
0028 | 0030 | Pixel Spacing:Physical distance in the patient between the center of each pixel. | 像素间距. 像素中心之间的物理间距. | DS |
0028 | 0100 | Bits Allocated:Number of bits allocated for each pixel sample. Each sample shall have the same number of bits allocated. | 分配的位数: 存储每一个像素值时分配的位数,每一个样本应该拥有相同的这个值. | US |
0028 | 0101 | Bits Stored:Number of bits stored for each pixel sample. Each sample shall have the same number of bits stored. | 存储的位数:有12到16列举值. 存储每一个像素用的位数.每一个样本应该有相同值. | US |
0028 | 0102 | High Bit:Most significant bit for pixel sample data. Each sample shall have the same high bit. | 高位. | US |
0028 | 0103 | Pixel Representation:Data representation of the pixel samples. Each sample shall have the same pixel representation.Enum: 0000H=unsigned integer,0001H=2’s complement. | 像素数据的表现类型: 这是一个枚举值,分别为十六进制数0000和0001. 0000H = 无符号整数, 0001H = 2的补码. | US |
0028 | 1050 | Window Center | 窗位. | DS |
0028 | 1051 | Window Width | 窗宽. | DS |
0028 | 1052 | Rescale Intercept:The value b in relationship between stored values (SV) and the output units.Output units = m*SV + b.Required if Modality LUT Sequence (0028, 0030) is not present. | 截距: 如果表明不同模态的LUT颜色对应表不存在时,则使用方程 Units = m*SV + b,计算真实的像素值到呈现像素值。 其中这个值为表达式中的b。 | DS |
0028 | 1053 | Rescale Slope:m in the equation specified by Rescale Intercept (0028,1052).Required if Rescale Intercept is present. | 斜率. 这个值为表达式中的m。 | DS |
0028 | 1054 | Rescale Type:Specifies the output units of Rescale Slope (0028,1053) and Rescale Intercept (0028,1052).Enum: US=Unspecified Requried if Photometric Interpretation is MONOCHROME2, and Bits Stored is greater than 1.This specifies an identity Modality LUT transformation. | 输出值的单位. 这是一个枚举值, | LO |
4.UID的分类和三级层级关系
UID | 含义 |
---|---|
第一级:StudyInstanceUID | 标识同一患者的一次检查 |
第二级:SeriesInstanceUID | 标识一次检查下的一次序列 |
第三级:SOPInstanceUID | 标识一次序列下的产生的其中一个图像 |
- UID的生成可自行写方法生成,也可使用第三库生成(DCMTK有相应的函数)
enum UID_Type
{
UID_Study = 1,
UID_Series,
UID_Image
}
std::string GenerateUniqueId(UID_Type type)
{
char uid[100];
switch (type)
{
case UID_Study:
dcmGenerateUniqueIdentifier(uid, SITE_STUDY_UID_ROOT);
break;
case UID_Series:
dcmGenerateUniqueIdentifier(uid, SITE_SERIES_UID_ROOT);
break;
case UID_Image:
dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT);
break;
default:
std::cout << "The type of unique id that is not supported! type :" << type << std::endl;
break;
}
return std::string(uid);
}
5.Dicom文件的解读步骤
- 前128个字节为00H,然后读取4个字节,值为“DICM”,确认是DICOM格式文件
- 其后就是meta info和data set,根据Tag读取文件数据信息
- 直到(7fe0, 0010),存储图像数据的位置
- 读写一定要统一编码方式,否则同样的数据在不同的平台下会得出不同的结果
二.Dicom标准定义的数据字典
1.标准数据字典(Stardard Data Dictionary)
2.私有数据字典(Private Data Dictionary)
3.数据字典格式
- Tag:属性标识,为两个十六进制的数的组合(0x0002, 0x0003),分别是Group和Element
- Tag是按照Group和Element标签编号来排序的
- Attribute:属性名称,和Tag是一一对应的
- VR(Value Representation):数据类型,总共有27个值
- VM(Value Multiplicity):规定了这个属性可以包含一个或多个数据值
- 如果是二进制的多个值,直接拼接就好,可以根据字节数来获取
- 如果是字符串的多个值,则用‘''来分隔
4.标准命令字典(Standard Command Dictionary)
- Group为0x0000,表示的都是操作命令,例如"打印","存储","Get请求"等
- 例如(0x0000,0100)为command type,(0x0000,0110)为command message id
三.VR定义表
VR | 含义 | 允许的字符 | 数据长 |
---|---|---|---|
**CS **- Code String 代码字符串 | 开头结尾可以有没有意义的空格的字符串,比如“CD123_4” | 大写字母,0-9,空格以及下划线字符 | 最多 16 个字符 |
SH - Short String 短字符串 | 短字符串,比如:电话号码,ID等 | 最多 16 个字符 | |
LO - Long String 长字符串 | 一个字符串,可能在开头、结尾填有空 格。比如“Introduction to DICOM” | 最多 64 个字符 | |
ST - Short Text 短文本 | 可能包含一个或多个段落的字符串 | 最多 1024 个字符 | |
LT - Long Text 短文本 | 可能包含一个或多个锻炼的字符串,与LO相同,但可以更长 | 最多 10240 个字符 | |
UT - Unlimited Text 无限制文本 | 包含一个或多个段落的字符串,与LT 类似 | 最多(2的32次方–2)个字符 | |
AE- Application Entity 应用实体 | 标识一个设备的名称的字符串,开头和 结尾可以有无意义的字符。比如“MyPC01” | 最多 16 个字符 | |
PN - Person Name 病人姓名 | 有插入符号()作为姓名分隔符的病人姓名。比如“SMITHJOHN” “Morrison- JonesSusan^^Ph.D, Chief Executive Officer” | 最多 64 个字符 | |
UI- Unique Identifier (UID) 唯一标识符 | 一个用作唯一标识各类项目的包含UID 的字符串。比如“1.2.840.10008.1.1” | 0-9 和半角句号(.) | 最多64 个字符 |
DA - Date 日期 | 格式为 YYYYMMDD 的字符串;YYYY 代表年;MM 代表月;DD 代表日。比 如“20050822”表示2005 年 8 月 22 日 | 0-9 | 8个字符 |
TM - Time 时间 | 格式为 HHMMSS 的字符串。FRAC; HH 表示小时(范围“00”-“23”); MM 表示分钟(范围“00”-“59”); 而 FRAC 包含秒的小数部分,即百万分 之一秒。比如“183200.00” 表示下午 6:32 就是微秒(microsecond) | 0-9 和半角句号(.) | 最多 16 个字符 |
DT - Date Time 日期时间 | 格式为 YYYYMMDDHHMMSS. FFFFFF,串联的日期时间字符串。字符串的各部分从左至右是:年YYYY;月 MM;日 DD;小时HH;分钟 MM;秒 SS;秒的小数FFFFFF。比如20050812183000.00”表示 2005年 8 月 12 日下午 18 点 30 分 00秒 | 0-9,加号,减号和半角句号 | 最多 26 个字符 |
AS - Age String 年龄字符串 | 符合以下格式的字符串:nnnD,nnnW, nnnM, nnnY;其中nnn 对于 D 来说表示天数,对于W来说表示周数,对于M 来说表示月数,对于 Y 来说表示岁数。 比如“018M”表示他的年龄是 18 个月 | 0–9, D,W,M, Y | 4 个字符 |
IS- Integer String 整型字符串 | 表示一个整型数字的字符串。比如“-1234567” | 0-9,加号(+),减号(-) | 最多 12 个字符 |
DS - Decimal String 小数字符串 | 表示定点小数和浮点小数。 比如“12345.67”,“-5.0e3” | 0-9,加号(+),减号(-), 最多 16个字符 E,e和半角句号(.) | 最多 16 个字符 |
SS - Signed Short 有符号短型 | 符号型二进制整数,长度 16 比特 | 2 个字符 | |
US - Unsigned Short 无符号短型 | 无符号二进制整数,长度 16 比特 | 2 个字符 | |
SL - Signed Long 有符号长型 | 有符号二进制整数 | 4 个字符 | |
UL - Unsigned Long 无符号长型 | 无符号二进制整数,长度 32 比特 | 4 个字符 | |
AT - Attribute Tag 属性标签 | 16 比特无符号整数的有序对,数据元素的标签 | 4 个字符 | |
FL - Floating Single 单精度浮点 | 单精度二进制浮点数字 | 4 个字符 | |
FD - Floating Point Double 双精度二进制浮点数字 | 双精度二进制浮点数字 | 8 个字符 | |
OB - Other Byte String 其他字节字符串 | 字节的字符串(“其他”表示没有在VR中定义的内容) | ||
OW- Other Word String 其他单词字符串 | 16 比特(2 字节)单词字符串 | ||
OF- Other Float String 其他浮点字符串 | 32 比特(4 个字节)浮点单词字符串 | ||
SQ - Sequence Items 条目序列 | 条目的序列 | ||
UN – Unknown 未知 | 字节的字符串,其中内容的编码方式是未知的 |
四.Dicom编码方式(即传输语法)
1.VR隐式和显示编码
- VR隐式编码(implicit VR encoding)
-
VR显式编码(explicit VR encoding)
VR = OB,OW,OF,SQ,UT,UN,VR固定2个字节,其后固定两个字节(0x0000)
VR != OB,OW,OF,SQ,UT,UN,VR固定2个字节,Value Length变成2个字节
2.BIG/LITTLE Endian(大端模式/小端模式)
- 大端模式(Big-Endian)就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
- 小端模式(Little-Endian)就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
-
影响多字节类型数据的编码
- 2-byte US, SS, OW,AT
- 4-byte OF, UL, SL, FL
- 8 byte FD
例如: 8-byte FD的数据6789ABCD,
在little endian编码下是CDAB8967, 在BIG endian编码下是6789ABCD.
- DCMTK下保存数据是可以使用枚举值来指定编码类型
OFCondition status = m_fileformat.saveFile(filePath.c_str(), EXS_LittleEndianExplicit);
if (!status.good())
{
std::cout << "Save Dimcom File Error!" << std::endl;
}
/** enumeration of all DICOM transfer syntaxes known to the toolkit
*/
typedef enum {
/// unknown transfer syntax or dataset created in-memory
EXS_Unknown = -1,
/// Implicit VR Little Endian
EXS_LittleEndianImplicit = 0,
/// Implicit VR Big Endian (pseudo transfer syntax that does not really exist)
EXS_BigEndianImplicit = 1,
/// Explicit VR Little Endian
EXS_LittleEndianExplicit = 2,
/// Explicit VR Big Endian
EXS_BigEndianExplicit = 3,
/// JPEG Baseline (lossy)
EXS_JPEGProcess1 = 4,
/// JPEG Extended Sequential (lossy, 8/12 bit)
EXS_JPEGProcess2_4 = 5,
/// JPEG Extended Sequential (lossy, 8/12 bit), arithmetic coding
EXS_JPEGProcess3_5 = 6,
/// JPEG Spectral Selection, Non-Hierarchical (lossy, 8/12 bit)
EXS_JPEGProcess6_8 = 7,
/// JPEG Spectral Selection, Non-Hierarchical (lossy, 8/12 bit), arithmetic coding
EXS_JPEGProcess7_9 = 8,
/// JPEG Full Progression, Non-Hierarchical (lossy, 8/12 bit)
EXS_JPEGProcess10_12 = 9,
/// JPEG Full Progression, Non-Hierarchical (lossy, 8/12 bit), arithmetic coding
EXS_JPEGProcess11_13 = 10,
/// JPEG Lossless with any selection value
EXS_JPEGProcess14 = 11,
/// JPEG Lossless with any selection value, arithmetic coding
EXS_JPEGProcess15 = 12,
/// JPEG Extended Sequential, Hierarchical (lossy, 8/12 bit)
EXS_JPEGProcess16_18 = 13,
/// JPEG Extended Sequential, Hierarchical (lossy, 8/12 bit), arithmetic coding
EXS_JPEGProcess17_19 = 14,
/// JPEG Spectral Selection, Hierarchical (lossy, 8/12 bit)
EXS_JPEGProcess20_22 = 15,
/// JPEG Spectral Selection, Hierarchical (lossy, 8/12 bit), arithmetic coding
EXS_JPEGProcess21_23 = 16,
/// JPEG Full Progression, Hierarchical (lossy, 8/12 bit)
EXS_JPEGProcess24_26 = 17,
/// JPEG Full Progression, Hierarchical (lossy, 8/12 bit), arithmetic coding
EXS_JPEGProcess25_27 = 18,
/// JPEG Lossless, Hierarchical
EXS_JPEGProcess28 = 19,
/// JPEG Lossless, Hierarchical, arithmetic coding
EXS_JPEGProcess29 = 20,
/// JPEG Lossless, Selection Value 1
EXS_JPEGProcess14SV1 = 21,
/// Run Length Encoding (lossless)
EXS_RLELossless = 22,
/// Deflated Explicit VR Little Endian
EXS_DeflatedLittleEndianExplicit = 23,
/// JPEG-LS (lossless)
EXS_JPEGLSLossless = 24,
/// JPEG-LS (lossless or near-lossless mode)
EXS_JPEGLSLossy = 25,
/// JPEG 2000 (lossless)
EXS_JPEG2000LosslessOnly = 26,
/// JPEG 2000 (lossless or lossy)
EXS_JPEG2000 = 27,
/// JPEG 2000 part 2 multi-component extensions (lossless)
EXS_JPEG2000MulticomponentLosslessOnly = 28,
/// JPEG 2000 part 2 multi-component extensions (lossless or lossy)
EXS_JPEG2000Multicomponent = 29,
/// JPIP Referenced
EXS_JPIPReferenced = 30,
/// JPIP Referenced Deflate
EXS_JPIPReferencedDeflate = 31,
/// MPEG2 Main Profile at Main Level
EXS_MPEG2MainProfileAtMainLevel = 32,
/// MPEG2 Main Profile at High Level
EXS_MPEG2MainProfileAtHighLevel = 33,
/// MPEG4 High Profile / Level 4.1
EXS_MPEG4HighProfileLevel4_1 = 34,
/// MPEG4 BD-compatible High Profile / Level 4.1
EXS_MPEG4BDcompatibleHighProfileLevel4_1 = 35,
/// MPEG4 High Profile / Level 4.2 For 2D Video
EXS_MPEG4HighProfileLevel4_2_For2DVideo = 36,
/// MPEG4 High Profile / Level 4.2 For 3D Video
EXS_MPEG4HighProfileLevel4_2_For3DVideo = 37,
/// MPEG4 Stereo High Profile / Level 4.2
EXS_MPEG4StereoHighProfileLevel4_2 = 38,
/// HEVC/H.265 Main Profile / Level 5.1
EXS_HEVCMainProfileLevel5_1 = 39,
/// HEVC/H.265 Main 10 Profile / Level 5.1
EXS_HEVCMain10ProfileLevel5_1 = 40,
/// Private GE Little Endian Implicit with big endian pixel data
EXS_PrivateGE_LEI_WithBigEndianPixelData = 41
} E_TransferSyntax;
3.分组长度编码
group的第一个元素可以记录该group的总长度,但该属性值是不是必须要写的,一个组的第一个元素(gggg,0000)可以记录改组的总长度,因为每个元素的长度是偶数,所以这个总长度的值也是偶数
好处:
* 如果不需要读某个Group时,可以直接根据字节数跳过;这样就可以加快DICOM文件的处理过程。它在处理奇数Group的数据时候尤其明显。因为奇数的Group数值自己不能读,可以很快地跳过。
* 它也可以作为校验数据长度。
坏处:
* 在写(gggg,0000)这个元素的时候,意味着这个group中的所有元素必须首先获取到,并且在(gggg,0000)之前已经编码好。对于DICOM开发者来说,这意味着两件事:
(1)所有的元素都必须编码完成,才能编码object
(2)修改了DICOM对象中一个元素时,就不可避免地修改了它的数值长度,就需要相应的修改它的值。这样就会带来额来的负担。
4.SQ Data Element的层数和编码规则
-
SQ Data Element最多3层,编码时要从下往上
SQ序列中的DICOM对象数据值以(FFFE, E000)开头,但数据长度可以不明确
1.DICOM对象数据值有明确的长度;如例1中的第一个和第二个数据对象;
- DICOM对象数据值没有明确的长度,标记为FFFFFFFF,需要使用(FFFE,E0DD)来识别结尾,这一项的值长度为0
整个SQ序列数据长度也可以不明确
1.有明确的长度
2.没有明确的长度,标记为FFFFFFFF,需要使用(FFFE,E0DD)来识别结尾,这一项的值长度为0