From 19a67186655a4a0c9404d79855ff2970faf044e4 Mon Sep 17 00:00:00 2001 From: Krad Date: Wed, 14 Sep 2022 14:17:09 +0800 Subject: [PATCH] Fix charset bug for chinese. --- src/src/IO/DICOM/DICOMHeaderHelper.cpp | 290 ++++--------------------- src/src/IO/DICOM/DICOMHeaderHelper.h | 23 +- 2 files changed, 49 insertions(+), 264 deletions(-) diff --git a/src/src/IO/DICOM/DICOMHeaderHelper.cpp b/src/src/IO/DICOM/DICOMHeaderHelper.cpp index a2e0aed..94f89a7 100644 --- a/src/src/IO/DICOM/DICOMHeaderHelper.cpp +++ b/src/src/IO/DICOM/DICOMHeaderHelper.cpp @@ -5,13 +5,13 @@ #include "DICOMHeaderHelper.h" #include "dcmtk/dcmdata/dcfilefo.h" #include "dcmtk/dcmdata/dcdatset.h" +#include "dcmtk/dcmdata/dcspchrs.h" #include "ExtendMedicalImageProperties.h" #include #include #include #include #include -#include #include struct DICOMTag{ @@ -50,153 +50,9 @@ DICOMTag dicom_tags[] = { {0x0028, 0x1052, "pixel offset"} }; -void DICOMHeaderHelper::getDirectoryProperties(const char * rootPath, SeriesMap& result){ - vtkNew dir; - dir->Open(rootPath); - vtkIdType fileCount = dir->GetNumberOfFiles(); - for (vtkIdType i = 0; i < fileCount; ++i) { - const char* file_path = dir->GetFile(i); - if (strcmp(".",file_path)==0 || strcmp("..",file_path)==0 ) continue; - std::string path(rootPath); - path.append("\\"); - path.append(file_path); - std::cout<<"file path:"<FileIsDirectory(path.c_str())) - { - getDirectoryProperties(path.c_str(), result); - } - else { - getFileProperty(path, result); - } - } -} - -void DICOMHeaderHelper::getFileProperty(const std::string &path, SeriesMap& result) { - DcmFileFormat file; - // read success! - if (file.loadFile(path).good()) { - DcmDataset *dataset = file.getDataset(); - std::string SeriesUID; - dataset->findAndGetOFString(DcmTagKey(0x0020, 0x000e), SeriesUID); - long SeriesNumber = 0; - dataset->findAndGetSint32(DcmTagKey(0x0020, 0x0011), SeriesNumber); - long AcquisitionNumber = 0; - dataset->findAndGetSint32(DcmTagKey(0x0020, 0x0012), AcquisitionNumber); - long InstanceNumber = 0; - dataset->findAndGetSint32(DcmTagKey(0x0020, 0x0013), InstanceNumber); - // series be firstly loaded - if (!result.count(SeriesUID)) { - ExtendMedicalImageProperties *seriesProperty = ExtendMedicalImageProperties::New(); - - #define ReadTAGToProperty(Name, group, element)\ - std::string Name;\ - dataset->findAndGetOFString(DcmTagKey(group, element), Name);\ - seriesProperty->Set##Name(Name.c_str()); - - ReadTAGToProperty(PatientID, 0x0010, 0x0020) - ReadTAGToProperty(PatientName, 0x0010, 0x0010) - ReadTAGToProperty(PatientBirthDate, 0x0010, 0x0030) - ReadTAGToProperty(PatientSex, 0x0010, 0x0040) - ReadTAGToProperty(PatientAge, 0x0010, 0x1010) - ReadTAGToProperty(StudyDate, 0x0008, 0x0020) - ReadTAGToProperty(AcquisitionDate, 0x0008, 0x0022) - ReadTAGToProperty(StudyTime, 0x0008, 0x0030) - ReadTAGToProperty(AcquisitionTime, 0x0008, 0x0032) - ReadTAGToProperty(Modality, 0x0008, 0x0060) - ReadTAGToProperty(InstitutionName, 0x0008, 0x0080) - ReadTAGToProperty(StudyDescription, 0x0008, 0x1030) - ReadTAGToProperty(SeriesDescription, 0x0008, 0x103E) - ReadTAGToProperty(StudyUID, 0x0020, 0x000d) - ReadTAGToProperty(StudyID, 0x0020, 0x0010) - seriesProperty->SetSeriesUID(SeriesUID.c_str()); - seriesProperty->SetSeriesNumber(SeriesNumber); - std::string uniqueID; - uniqueID.append(PatientName); - uniqueID.append("_"); - uniqueID.append(StudyUID); - uniqueID.append("_"); - uniqueID.append(SeriesUID); - seriesProperty->SetUniqueID(uniqueID); - - double WindowCenter = 0.0; - dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1050), WindowCenter); - double WindowWidth = 0.0; - dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1051), WindowWidth); - seriesProperty->AddWindowLevelPreset(WindowWidth, WindowCenter); - - double Spacing[3] = {0.0, 0.0, 1.0}; - dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x0030), Spacing[0], 0); - dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x0030), Spacing[1], 1); - seriesProperty->SetSpacing(Spacing); - - double orientation[6] = {.0, .0, .0, .0, .0, .0}; - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), orientation[0], 0); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), orientation[1], 1); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), orientation[2], 2); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), orientation[3], 3); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), orientation[4], 4); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), orientation[5], 5); - seriesProperty->SetDirectionCosine(orientation); - - double position[3] = {.0, .0, .0}; - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0032), position[0], 0); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0032), position[1], 1); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0032), position[2], 2); - seriesProperty->SetPosition(position); - - unsigned short SamplePerPixel = 0; - dataset->findAndGetUint16(DcmTagKey(0x0028, 0x0002), SamplePerPixel); - seriesProperty->SetSamplePerPixel(SamplePerPixel); - //TODO:暂时不考虑颜色空间的事(只与缩略图相关!!!) - - seriesProperties.push_back(seriesProperty); - //暂时不考虑acqnumber的影响 - //seriesProperty->SetAcquisitionNumber(AcquisitionNumber); - } - char buffer[256] = {0}; - sprintf(buffer, "%ld-%ld", AcquisitionNumber, InstanceNumber); - printf("%s\r\n", path.c_str()); - result[SeriesUID][buffer] = {path, "",SeriesNumber, AcquisitionNumber, InstanceNumber}; - } -} - void DICOMHeaderHelper::Update() { ReadHeader(); ArrangeSeriesProperty(); -// std::unordered_map> series; -// if (!this->dirName.empty()){ -// getDirectoryProperties(this->dirName.c_str(), series); -// } -// else{ -// getFileProperty(fileName, series); -// } -// //sort files -// for (auto &pair : series) { -// auto iterator = std::find_if(seriesProperties.begin(),seriesProperties.end(), -// [=](ExtendMedicalImageProperties* val){ -// return strcmp(val->GetSeriesUID(), pair.first.c_str()) == 0; -// } -// ); -// if (iterator < seriesProperties.end()){ -// std::vector files; -// std::vector vector; -// for (auto f : pair.second) { -// vector.emplace_back(std::move(f.second)); -// } -// std::sort(vector.begin(), vector.end(), [](const DICOMFileHeader &v1, const DICOMFileHeader &v2) { -// -// return v1.SeriesNumber != v2.SeriesNumber ? (v1.SeriesNumber < v2.SeriesNumber) : -// (v1.AcquisitionNumber != v2.AcquisitionNumber ? (v1.AcquisitionNumber < v2.AcquisitionNumber) : -// (v1.InstanceNumber < v2.InstanceNumber)); -// }); -// std::for_each(vector.begin(), vector.end(),[&](auto v){ -// files.emplace_back(std::move(v.FilePath)); -// }); -// (*iterator)->SetFileNames(files); -// readImageProperty(*iterator); -// } -// } SeriesCount = seriesProperties.size(); } @@ -224,96 +80,6 @@ void DICOMHeaderHelper::Clear() { SeriesCount = 0; } -void DICOMHeaderHelper::readImageProperty(ExtendMedicalImageProperties* property) { - const std::vector& files = property->GetFileNames(); - DcmFileFormat file1; - // read success! - if (file1.loadFile(files.at(0)).good()) { - DcmDataset *dataset = file1.getDataset(); - - std::string SeriesUID; - dataset->findAndGetOFString(DcmTagKey(0x0020, 0x000e), SeriesUID); - long SeriesNumber = 0; - dataset->findAndGetSint32(DcmTagKey(0x0020, 0x0011), SeriesNumber); - long AcquisitionNumber = 0; - dataset->findAndGetSint32(DcmTagKey(0x0020, 0x0012), AcquisitionNumber); - long InstanceNumber = 0; - dataset->findAndGetSint32(DcmTagKey(0x0020, 0x0013), InstanceNumber); - std::cout<<"file1:"<findAndGetFloat64(DcmTagKey(0x0028, 0x0030), Spacing[0], 0); - dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x0030), Spacing[1], 1); - property->SetSpacing(Spacing); - - double orientation[6] = {.0, .0, .0, .0, .0, .0}; - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), orientation[0], 0); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), orientation[1], 1); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), orientation[2], 2); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), orientation[3], 3); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), orientation[4], 4); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), orientation[5], 5); - property->SetDirectionCosine(orientation); - - double position[3] = {.0, .0, .0}; - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0032), position[0], 0); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0032), position[1], 1); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0032), position[2], 2); - property->SetPosition(position); - // get orientation transform matrix and MToW WToM transform matrix - property->ComputeTransformMatrix(); - } - - if (files.size()>1){ - DcmFileFormat file2; - // read success! - if (file2.loadFile(files.at(1)).good()) { - DcmDataset *dataset = file2.getDataset(); - std::string SeriesUID; - dataset->findAndGetOFString(DcmTagKey(0x0020, 0x000e), SeriesUID); - std::string SeriesDes; - dataset->findAndGetOFString(DcmTagKey(0x0008, 0x103e), SeriesDes); - long SeriesNumber = 0; - dataset->findAndGetSint32(DcmTagKey(0x0020, 0x0011), SeriesNumber); - long AcquisitionNumber = 0; - dataset->findAndGetSint32(DcmTagKey(0x0020, 0x0012), AcquisitionNumber); - long InstanceNumber = 0; - dataset->findAndGetSint32(DcmTagKey(0x0020, 0x0013), InstanceNumber); - double position[3] = {.0, .0, .0}; - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0032), position[0], 0); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0032), position[1], 1); - dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0032), position[2], 2); - double position0[3] ={property->GetPosition()[0], property->GetPosition()[1] , property->GetPosition()[2]}; - double zVector_real[3] = { - position[0] - position0[0], - position[1] - position0[1], - position[2] - position0[2] - }; - // get slice real distance as space[2] - double space2 = sqrt(vtkMath::Distance2BetweenPoints(position, property->GetPosition())); - vtkMath::Normalize(zVector_real); - double Spacing[3] = {.0, .0, .0}; - property->GetSpacing(Spacing); - double* zVector = property->GetZVector(); - // if zVector_real is same direction with zVector, the negativeFlag must be true, otherwise will be false. - bool negativeFlag = (zVector_real[0] * zVector[0]) < 0 - || (zVector_real[1] * zVector[1]) < 0 - || (zVector_real[2] * zVector[2]) < 0 ; - // the space[2] will decide the z Axis image heap up direction - Spacing[2] = negativeFlag?(-1.0*space2):space2; - property->SetSpacing(Spacing); - } - } - else{ - double Spacing[3] = {.0, .0, .0}; - property->GetSpacing(Spacing); - Spacing[2] = 1.0; - property->SetSpacing(Spacing); - } - - -} - void DICOMHeaderHelper::readHeaderFromDir(const char * rootPath){ vtkNew dir; dir->Open(rootPath); @@ -366,8 +132,20 @@ void DICOMHeaderHelper::readHeaderFromFile(const char * filePath){ dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1050), header.WindowCenter); dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1051), header.WindowWidth); - dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x0030), header.Spacing[0], 0); + auto spacingResult = + dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x0030), header.Spacing[0], 0); dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x0030), header.Spacing[1], 1); + //No Pixel spacing , try use Imager Pixel Spacing to instead + if (!spacingResult.good()){ + spacingResult = + dataset->findAndGetFloat64(DcmTagKey(0x0018, 0x1164), header.Spacing[0], 0); + dataset->findAndGetFloat64(DcmTagKey(0x0018, 0x1164), header.Spacing[1], 1); + } + //No Imager Pixel Spacing, use default 1.0 + if (!spacingResult.good()){ + header.Spacing[0] = 1.0; + header.Spacing[1] = 1.0; + } dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), header.Orientation[0], 0); dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), header.Orientation[1], 1); @@ -455,13 +233,11 @@ void DICOMHeaderHelper::ArrangeSeriesProperty() { beginOffset = splitIndex[j]; imageSetNumber++; } - printf("first file:%s",item.second[0].FilePath.c_str()); //sort the last image set std::sort(item.second.begin() + beginOffset, item.second.end(), [](auto v1, auto v2) { return v1.image_position < v2.image_position; }); -// printf("new first file:%s\r\n",item.second[0].FilePath.c_str()); auto p = createProperty(item.second, item.second.size(), beginOffset); p->SetImageSetNumber(imageSetNumber); p->GenerateUniqueID(); @@ -498,8 +274,7 @@ ExtendMedicalImageProperties* DICOMHeaderHelper::createProperty(const std::vecto dataset->findAndGetOFString(DcmTagKey(group, element), Name);\ property->Set##Name(Name.c_str()); - ReadTAGToProperty(PatientID, 0x0010, 0x0020) - ReadTAGToProperty(PatientName, 0x0010, 0x0010) + ReadTAGToProperty(PatientBirthDate, 0x0010, 0x0030) ReadTAGToProperty(PatientSex, 0x0010, 0x0040) ReadTAGToProperty(PatientAge, 0x0010, 0x1010) @@ -508,16 +283,38 @@ ExtendMedicalImageProperties* DICOMHeaderHelper::createProperty(const std::vecto ReadTAGToProperty(StudyTime, 0x0008, 0x0030) ReadTAGToProperty(AcquisitionTime, 0x0008, 0x0032) ReadTAGToProperty(Modality, 0x0008, 0x0060) - ReadTAGToProperty(InstitutionName, 0x0008, 0x0080) - ReadTAGToProperty(StudyDescription, 0x0008, 0x1030) - ReadTAGToProperty(SeriesDescription, 0x0008, 0x103E) + ReadTAGToProperty(StudyUID, 0x0020, 0x000d) ReadTAGToProperty(StudyID, 0x0020, 0x0010) + std::string charSet = ""; + auto needConvert = dataset->findAndGetOFString(DcmTagKey(0x0008, 0x0005), charSet); + if (needConvert.good()){ + DcmSpecificCharacterSet charSetConvert; + charSetConvert.selectCharacterSet(charSet); + #define ReadTAGToPropertyConvert(Name, group, element)\ + std::string Name;\ + std::string Name##Convert;\ + dataset->findAndGetOFString(DcmTagKey(group, element), Name);\ + charSetConvert.convertString(Name,Name##Convert);\ + property->Set##Name(Name##Convert.c_str()); + + ReadTAGToPropertyConvert(PatientID, 0x0010, 0x0020) + ReadTAGToPropertyConvert(PatientName, 0x0010, 0x0010) + ReadTAGToPropertyConvert(InstitutionName, 0x0008, 0x0080) + ReadTAGToPropertyConvert(StudyDescription, 0x0008, 0x1030) + ReadTAGToPropertyConvert(SeriesDescription, 0x0008, 0x103E) + } else{ + ReadTAGToProperty(PatientID, 0x0010, 0x0020) + ReadTAGToProperty(PatientName, 0x0010, 0x0010) + ReadTAGToProperty(InstitutionName, 0x0008, 0x0080) + ReadTAGToProperty(StudyDescription, 0x0008, 0x1030) + ReadTAGToProperty(SeriesDescription, 0x0008, 0x103E) + } double thickness= 1.0; dataset->findAndGetFloat64(DcmTagKey(0x0008, 0x0050), thickness); double RescaleSlope= 1.0; dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1053), RescaleSlope); - double RescaleOffset= 1.0; + double RescaleOffset= 0.0; dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1052), RescaleOffset); unsigned short bitsAllocated= 1; dataset->findAndGetUint16(DcmTagKey(0x0028, 0x0100), bitsAllocated); @@ -547,9 +344,4 @@ ExtendMedicalImageProperties* DICOMHeaderHelper::createProperty(const std::vecto return property; } -//void DICOMDirectoryHelper::GetImageData(int index, void *imgData) { -// -// -//} - diff --git a/src/src/IO/DICOM/DICOMHeaderHelper.h b/src/src/IO/DICOM/DICOMHeaderHelper.h index fa50439..b3f2373 100644 --- a/src/src/IO/DICOM/DICOMHeaderHelper.h +++ b/src/src/IO/DICOM/DICOMHeaderHelper.h @@ -75,10 +75,6 @@ public: void Update(); - void ReadHeader(); - - void ArrangeSeriesProperty(); - int GetSeriesCount() { return SeriesCount; } @@ -92,18 +88,9 @@ public: ExtendMedicalImageProperties *GetSeriesBySeriesUID(const char *seriesUID); private: - std::string dirName; - std::string fileName; - int SeriesCount = 0; - SeriesFileMap series; - std::vector seriesProperties; + void ReadHeader(); - void getDirectoryProperties(const char *rootPath, - SeriesMap &result); - - void getFileProperty(const std::string &path, SeriesMap &result); - - void readImageProperty(ExtendMedicalImageProperties *property); + void ArrangeSeriesProperty(); void readHeaderFromDir(const char *rootPath); @@ -111,6 +98,12 @@ private: ExtendMedicalImageProperties * createProperty(const std::vector &header, int splitIndex, int beginOffset); + + std::string dirName; + std::string fileName; + int SeriesCount = 0; + SeriesFileMap series; + std::vector seriesProperties; };