本篇文章对应的DICOM原理部分,在专栏从零讲解DICOM协议-成像协议的文章DICOM层级关系,建议先了解原理,有助于理清代码思路。
DICOM有四个从上到下层级关系,分别是Patient(病人),Study(检查),Series(序列),Sop(图像)。
对杂乱无序的DICOM图像进行分类是一些高级应用的前提,比如阅片,三维重建。阅片要求一个Study的各个Series分开,Series的SOP按扫描顺序排序。三维重建是针对一个Series进行的,切片顺序更是要正确,否则重建后的三维图像会错位。
Patient可以有多个Study,Study可以有多个Series,Series可以有多个Sop。实际的意义为一个人可以做多次检查,一个检查的图像按照层厚、窗宽窗位、动静脉期等不同可以有不同的序列,一个序列需要多张图像才能完整显示扫描的器官。分类完成后按照层级保存,即顶层目录为PatientID命名->包含StudyInstanceUID命名的检查层级目录->包含SeriesInstanceUID命名的系列层级目录->包含SopInstanceUID命名的图像。
根据DICOM规定的每个层级所属的元素,选取部分重要的元素,构造数据结构。
分类结果示例:
- Patient层级
包含病人的基本信息,如姓名,性别,年龄等
patientPath为Patient层级的完整路径
studyinfoset为一个Patient(病人)做的多次Study(检查)
class PatientInfo
{
public:
~PatientInfo(){
}
public:
string patientID;
string name;
string sex;
public:
string patientBirthDate;
string patientBirthTime;
string patientSize;
string patientWeight;
public:
string patientPath;
vector<StudyInfo*> studyinfoset;
};
对应dicom图像中的元素
2. Study层级
包含检查的基本信息,如studyInstanceUID,studyID,modalitiesInStudy等
studyPath为Study层级的完整路径
seriesinfoset为一个Study(检查)中的多个Series(序列)
其中要注意的是modalitiesInStudy,这个元素属于检查级别。容易和序列级别的Modality弄混。
序列的Modality是单值,即CT、MR等的一种,检查的modalitiesInStudy是多值,一个Study的多个Series可能有不同的Modality,所以ModalitiesInStudy是复数,VM=1~n,是Series的Modality组合,有多个值。
Modalities in Study:All of the distinct values used for Modality (0008,0060) in the Series of the Study.
class StudyInfo
{
public:
~StudyInfo(){
}
public:
string studyInstanceUID;
string studyID;
string accessNumber;
string modalitiesInStudy;
string studyDate;
string studyTime;
public:
string referringPhysicianName;
string studyDescription;
string bodyPartExamined;
public:
string studyPath;
string callingAet;
vector<SeriesInfo*> seriesinfoset;
};
3. 序列层级
包含序列的基本信息,如seriesInstanceUID,seriesNumber等
imageinfoset为一个Series(序列)中的多个SOP(实例)
class SeriesInfo
{
public:
~SeriesInfo(){
}
public:
string seriesInstanceUID;
string seriesNumber;
string modality;
public:
string sliceThickness;
string windowWidth;
string windowCenter;
public:
string seriesFileNum;
vector<SOPInfo*> imageinfoset;
};
- 图像层级
包含图像的基本信息,如sOPInstanceUID,instanceNumber等
class SOPInfo : public ImageInfo
{
public:
string sOPInstanceUID;
string instanceNumber;
public:
string sOPClassUID;
string sliceLocation;
};
图像层级的一些同DICOM元素无关的信息较多,所以独立封装为ImageInfo类
class ImageInfo
{
public:
string fileName;
string filePath;
string classifyFolder;
};
- 封装以上的对象
class Taginfo
{
public:
PatientInfo patientinfo;
StudyInfo studyinfo;
SeriesInfo seriesinfo;
SOPInfo sopinfo;
};
- 读取文件夹中的所有文件,进行分类
void classify(string filePath)
{
vector<string> files = Tool().FindFile(filePath);
ClassifyAdapter *classify = new ClassifyAdapter();
vector<string>files_;
for (int i = 0; i < files.size(); i++)
{
classify->DcmFileClassify(files[i]);
}
vector<PatientInfo*> patientInfos = classify->GetClassifyResultFull();
}
6.1 解析每一张DICOM图像
void ClassifyAdapter::DcmFileClassify(string filepath, string basepath, string callingAet)
{
dcmParse = new DcmParse(filepath);
Taginfo taginfo;
taginfo.patientinfo = GetPatientInfo();
taginfo.studyinfo = GetStudyInfo(callingAet);
taginfo.seriesinfo = GetSeriesInfo()