Data loader 1.
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vtkMath.h>
|
#include <vtkMath.h>
|
||||||
#include <vtkMatrix4x4.h>
|
#include <vtkMatrix4x4.h>
|
||||||
|
#include <QtCore/qvarlengtharray.h>
|
||||||
|
|
||||||
struct DICOMTag{
|
struct DICOMTag{
|
||||||
Uint16 group;
|
Uint16 group;
|
||||||
@@ -49,7 +50,7 @@ DICOMTag dicom_tags[] = {
|
|||||||
{0x0028, 0x1052, "pixel offset"}
|
{0x0028, 0x1052, "pixel offset"}
|
||||||
};
|
};
|
||||||
|
|
||||||
void DICOMDirectoryHelper::getDirectoryProperties(const char * rootPath, DICOMFileMap& result){
|
void DICOMDirectoryHelper::getDirectoryProperties(const char * rootPath, SeriesMap& result){
|
||||||
vtkNew<vtkDirectory> dir;
|
vtkNew<vtkDirectory> dir;
|
||||||
dir->Open(rootPath);
|
dir->Open(rootPath);
|
||||||
vtkIdType fileCount = dir->GetNumberOfFiles();
|
vtkIdType fileCount = dir->GetNumberOfFiles();
|
||||||
@@ -71,7 +72,7 @@ void DICOMDirectoryHelper::getDirectoryProperties(const char * rootPath, DICOMFi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DICOMDirectoryHelper::getFileProperty(const std::string &path, DICOMFileMap& result) {
|
void DICOMDirectoryHelper::getFileProperty(const std::string &path, SeriesMap& result) {
|
||||||
DcmFileFormat file;
|
DcmFileFormat file;
|
||||||
// read success!
|
// read success!
|
||||||
if (file.loadFile(path).good()) {
|
if (file.loadFile(path).good()) {
|
||||||
@@ -161,40 +162,41 @@ void DICOMDirectoryHelper::getFileProperty(const std::string &path, DICOMFileMap
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DICOMDirectoryHelper::Update() {
|
void DICOMDirectoryHelper::Update() {
|
||||||
|
ReadHeader();
|
||||||
std::unordered_map<std::string, std::unordered_map<std::string,DICOMFileRefValue>> series;
|
ArrangeSeriesProperty();
|
||||||
if (!this->dirName.empty()){
|
// std::unordered_map<std::string, std::unordered_map<std::string,DICOMFileHeader>> series;
|
||||||
getDirectoryProperties(this->dirName.c_str(), series);
|
// if (!this->dirName.empty()){
|
||||||
}
|
// getDirectoryProperties(this->dirName.c_str(), series);
|
||||||
else{
|
// }
|
||||||
getFileProperty(fileName, series);
|
// else{
|
||||||
}
|
// getFileProperty(fileName, series);
|
||||||
//sort files
|
// }
|
||||||
for (auto &pair : series) {
|
// //sort files
|
||||||
auto iterator = std::find_if(seriesProperties.begin(),seriesProperties.end(),
|
// for (auto &pair : series) {
|
||||||
[=](ExtendMedicalImageProperties* val){
|
// auto iterator = std::find_if(seriesProperties.begin(),seriesProperties.end(),
|
||||||
return strcmp(val->GetSeriesUID(), pair.first.c_str()) == 0;
|
// [=](ExtendMedicalImageProperties* val){
|
||||||
}
|
// return strcmp(val->GetSeriesUID(), pair.first.c_str()) == 0;
|
||||||
);
|
// }
|
||||||
if (iterator < seriesProperties.end()){
|
// );
|
||||||
std::vector<std::string> files;
|
// if (iterator < seriesProperties.end()){
|
||||||
std::vector<DICOMFileRefValue> vector;
|
// std::vector<std::string> files;
|
||||||
for (auto f : pair.second) {
|
// std::vector<DICOMFileHeader> vector;
|
||||||
vector.emplace_back(std::move(f.second));
|
// for (auto f : pair.second) {
|
||||||
}
|
// vector.emplace_back(std::move(f.second));
|
||||||
std::sort(vector.begin(), vector.end(), [](const DICOMFileRefValue &v1, const DICOMFileRefValue &v2) {
|
// }
|
||||||
|
// 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) :
|
// return v1.SeriesNumber != v2.SeriesNumber ? (v1.SeriesNumber < v2.SeriesNumber) :
|
||||||
(v1.InstanceNumber < v2.InstanceNumber));
|
// (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));
|
// std::for_each(vector.begin(), vector.end(),[&](auto v){
|
||||||
});
|
// files.emplace_back(std::move(v.FilePath));
|
||||||
(*iterator)->SetFileNames(files);
|
// });
|
||||||
readImageProperty(*iterator);
|
// (*iterator)->SetFileNames(files);
|
||||||
}
|
// readImageProperty(*iterator);
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
SeriesCount = seriesProperties.size();
|
SeriesCount = seriesProperties.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,4 +314,222 @@ void DICOMDirectoryHelper::readImageProperty(ExtendMedicalImageProperties* prope
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DICOMDirectoryHelper::readHeaderFromDir(const char * rootPath){
|
||||||
|
vtkNew<vtkDirectory> 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:"<<path<<std::endl;
|
||||||
|
|
||||||
|
if (dir->FileIsDirectory(path.c_str()))
|
||||||
|
{
|
||||||
|
readHeaderFromDir(path.c_str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
readHeaderFromFile(path.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DICOMDirectoryHelper::readHeaderFromFile(const char * filePath){
|
||||||
|
DcmFileFormat file;
|
||||||
|
// read success!
|
||||||
|
if (file.loadFile(filePath).good()) {
|
||||||
|
DcmDataset *dataset = file.getDataset();
|
||||||
|
DICOMFileHeader header;
|
||||||
|
std::string SeriesUID;
|
||||||
|
dataset->findAndGetOFString(DcmTagKey(0x0020, 0x000e), SeriesUID);
|
||||||
|
|
||||||
|
long SeriesNumber = 0;
|
||||||
|
dataset->findAndGetSint32(DcmTagKey(0x0020, 0x0011), header.SeriesNumber);
|
||||||
|
long AcquisitionNumber = 0;
|
||||||
|
dataset->findAndGetSint32(DcmTagKey(0x0020, 0x0012), header.AcquisitionNumber);
|
||||||
|
long InstanceNumber = 0;
|
||||||
|
dataset->findAndGetSint32(DcmTagKey(0x0020, 0x0013), header.InstanceNumber);
|
||||||
|
|
||||||
|
#define ReadTAGToProperty(Name, group, element)\
|
||||||
|
std::string Name;\
|
||||||
|
dataset->findAndGetOFString(DcmTagKey(group, element), Name);
|
||||||
|
|
||||||
|
ReadTAGToProperty(PatientName, 0x0010, 0x0010)
|
||||||
|
ReadTAGToProperty(StudyUID, 0x0020, 0x000d)
|
||||||
|
|
||||||
|
dataset->findAndGetSint32(DcmTagKey(0x0028, 0x0010), header.Rows);
|
||||||
|
dataset->findAndGetSint32(DcmTagKey(0x0028, 0x0011), header.Columns);
|
||||||
|
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1050), header.WindowCenter);
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1051), header.WindowWidth);
|
||||||
|
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x0030), header.Spacing[0], 0);
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x0030), header.Spacing[1], 1);
|
||||||
|
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), header.Orientation[0], 0);
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), header.Orientation[1], 1);
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), header.Orientation[2], 2);
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), header.Orientation[3], 3);
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), header.Orientation[4], 4);
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0037), header.Orientation[5], 5);
|
||||||
|
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0032), header.Position[0], 0);
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0032), header.Position[1], 1);
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0020, 0x0032), header.Position[2], 2);
|
||||||
|
|
||||||
|
dataset->findAndGetUint16(DcmTagKey(0x0028, 0x0002), header.SamplePerPixel);
|
||||||
|
std::string uniqueID;
|
||||||
|
uniqueID.append(PatientName);
|
||||||
|
uniqueID.append("_");
|
||||||
|
uniqueID.append(StudyUID);
|
||||||
|
uniqueID.append("_");
|
||||||
|
uniqueID.append(SeriesUID);
|
||||||
|
// series be firstly loaded
|
||||||
|
if (!series.count(SeriesUID)) {
|
||||||
|
series.emplace(uniqueID,DICOMFileList());
|
||||||
|
}
|
||||||
|
header.calculateImagePosition();
|
||||||
|
series[uniqueID].push_back(std::move(header));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DICOMDirectoryHelper::ReadHeader() {
|
||||||
|
|
||||||
|
if (!this->dirName.empty()){
|
||||||
|
vtkNew<vtkDirectory> dir;
|
||||||
|
dir->Open(this->dirName.c_str());
|
||||||
|
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(dirName);
|
||||||
|
path.append("\\");
|
||||||
|
path.append(file_path);
|
||||||
|
|
||||||
|
if (dir->FileIsDirectory(path.c_str()))
|
||||||
|
{
|
||||||
|
readHeaderFromDir(path.c_str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
readHeaderFromFile(path.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
readHeaderFromFile(this->fileName.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DICOMDirectoryHelper::ArrangeSeriesProperty() {
|
||||||
|
for (auto item : series) {
|
||||||
|
//sort by series, instance, AcquisitionNumber
|
||||||
|
std::sort(item.second.begin(), item.second.end(), [](auto v1, auto v2) {
|
||||||
|
return v1.SeriesNumber != v2.SeriesNumber ? (v1.SeriesNumber < v2.SeriesNumber) :
|
||||||
|
(v1.AcquisitionNumber != v2.AcquisitionNumber ? (v1.AcquisitionNumber < v2.AcquisitionNumber) :
|
||||||
|
(v1.InstanceNumber < v2.InstanceNumber));
|
||||||
|
});
|
||||||
|
auto currentValue = &(item.second[0]);
|
||||||
|
std::vector<int> splitIndex;
|
||||||
|
for (int i = 1; i < item.second.size(); ++i) {
|
||||||
|
if (!currentValue->equalImageSet(item.second[i])) {
|
||||||
|
currentValue = &(item.second[i]);
|
||||||
|
splitIndex.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//sort every image set
|
||||||
|
int beginOffset = 0;
|
||||||
|
for (int j = 0; j < splitIndex.size(); ++j) {
|
||||||
|
std::sort(item.second.begin()+beginOffset,item.second.begin()+splitIndex[j],
|
||||||
|
[](auto v1,auto v2){
|
||||||
|
return v1.image_position<v2.image_position;
|
||||||
|
});
|
||||||
|
seriesProperties.push_back(createProperty(item.second, splitIndex[j], beginOffset));
|
||||||
|
beginOffset = splitIndex[j];
|
||||||
|
}
|
||||||
|
//sort the last image set
|
||||||
|
if (splitIndex.size()>0) {
|
||||||
|
std::sort(item.second.begin() + beginOffset, item.second.end(),
|
||||||
|
[](auto v1, auto v2) {
|
||||||
|
return v1.image_position < v2.image_position;
|
||||||
|
});
|
||||||
|
seriesProperties.push_back(createProperty(item.second, item.second.size()-1, beginOffset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtendMedicalImageProperties* DICOMDirectoryHelper::createProperty(const std::vector<DICOMFileHeader>& headerList, int splitIndex, int beginOffset) {
|
||||||
|
auto property = ExtendMedicalImageProperties::New();
|
||||||
|
std::vector<std::string> files;
|
||||||
|
for (int i = beginOffset; i < splitIndex; ++i) {
|
||||||
|
files.push_back(headerList[i].FilePath.c_str());
|
||||||
|
}
|
||||||
|
const DICOMFileHeader& header = headerList[beginOffset];
|
||||||
|
property->SetFileNames(files);
|
||||||
|
property->SetRows(header.Rows);
|
||||||
|
property->SetColumns(header.Columns);
|
||||||
|
property->SetSamplePerPixel(header.SamplePerPixel);
|
||||||
|
property->SetSeriesNumber(header.SeriesNumber);
|
||||||
|
// property->SetImageNumber(item.second[beginOffset].InstanceNumber);
|
||||||
|
property->SetAcquisitionNumber(header.AcquisitionNumber);
|
||||||
|
property->AddWindowLevelPreset(header.WindowWidth,
|
||||||
|
header.WindowCenter);
|
||||||
|
property->SetPosition(header.Position[0],header.Position[1], header.Position[2]);
|
||||||
|
|
||||||
|
property->SetDirectionCosine(header.Orientation[0],header.Orientation[1],header.Orientation[2],
|
||||||
|
header.Orientation[3],header.Orientation[4],header.Orientation[5]);
|
||||||
|
DcmFileFormat file;
|
||||||
|
// read success!
|
||||||
|
if (file.loadFile(header.FilePath).good()) {
|
||||||
|
DcmDataset *dataset = file.getDataset();
|
||||||
|
#define ReadTAGToProperty(Name, group, element)\
|
||||||
|
std::string Name;\
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
double thickness= 1.0;
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0008, 0x0050), thickness);
|
||||||
|
double RescaleSlope= 1.0;
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1052), RescaleSlope);
|
||||||
|
double RescaleOffset= 1.0;
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1053), RescaleOffset);
|
||||||
|
unsigned short bitsAllocated= 1;
|
||||||
|
dataset->findAndGetUint16(DcmTagKey(0x0028, 0x1000), bitsAllocated);
|
||||||
|
unsigned short PixelRepresentation= 0;
|
||||||
|
dataset->findAndGetUint16(DcmTagKey(0x0028, 0x1000), PixelRepresentation);
|
||||||
|
property->SetSpacing(header.Spacing[0],header.Spacing[1],thickness);
|
||||||
|
property->SetRescaleSlope(RescaleSlope);
|
||||||
|
property->SetRescaleOffset(RescaleOffset);
|
||||||
|
property->SetBitsAllocated(bitsAllocated);
|
||||||
|
property->SetPixelRepresentation(PixelRepresentation);
|
||||||
|
}
|
||||||
|
if (headerList.size()>1){
|
||||||
|
const DICOMFileHeader& header2 = headerList[beginOffset+1];
|
||||||
|
double spacing2 = sqrt(vtkMath::Distance2BetweenPoints(header.Position,header2.Position));
|
||||||
|
property->SetSpacing(property->GetSpacing()[0],property->GetSpacing()[1],spacing2);
|
||||||
|
}
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
|
||||||
|
//void DICOMDirectoryHelper::GetImageData(int index, void *imgData) {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,51 +11,105 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
class ExtendMedicalImageProperties;
|
class ExtendMedicalImageProperties;
|
||||||
struct DICOMFileRefValue{
|
|
||||||
|
struct DICOMFileHeader {
|
||||||
std::string FilePath;
|
std::string FilePath;
|
||||||
long SeriesNumber = 0;
|
long SeriesNumber = 0;
|
||||||
long AcquisitionNumber = 0;
|
long AcquisitionNumber = 0;
|
||||||
long InstanceNumber = 0;
|
long InstanceNumber = 0;
|
||||||
|
double Spacing[2] = {1., 1.};
|
||||||
|
long Rows;
|
||||||
|
long Columns;
|
||||||
|
unsigned short SamplePerPixel;
|
||||||
|
double WindowCenter = 0;
|
||||||
|
double WindowWidth = 0;
|
||||||
|
double Position[3] = {.0, .0, .0};
|
||||||
|
double Orientation[6] = {.0, .0, .0, .0, .0, .0};
|
||||||
|
double image_position = 0.0;
|
||||||
|
|
||||||
|
bool equalImageSet(const DICOMFileHeader &v) {
|
||||||
|
return Rows == v.Rows && Columns == v.Columns &&
|
||||||
|
SamplePerPixel == v.SamplePerPixel && Spacing[0] == v.Spacing[0] &&
|
||||||
|
Spacing[1] == v.Spacing[1] &&
|
||||||
|
1.0 > (fabs(Orientation[0] - v.Orientation[0]) + fabs(Orientation[1] - v.Orientation[1]) +
|
||||||
|
fabs(Orientation[2] - v.Orientation[2]) + fabs(Orientation[3] - v.Orientation[3]) +
|
||||||
|
abs(Orientation[4] - v.Orientation[4]) + fabs(Orientation[5] - v.Orientation[5]));
|
||||||
|
}
|
||||||
|
|
||||||
|
void calculateImagePosition() {
|
||||||
|
double normal[3];
|
||||||
|
normal[0] = (Orientation[1] * Orientation[5]) - (Orientation[2] * Orientation[4]);
|
||||||
|
normal[1] = (Orientation[2] * Orientation[3]) - (Orientation[0] * Orientation[5]);
|
||||||
|
normal[2] = (Orientation[0] * Orientation[4]) - (Orientation[1] * Orientation[3]);
|
||||||
|
image_position = (normal[0] * Orientation[0])
|
||||||
|
+ (normal[1] * Orientation[1])
|
||||||
|
+ (normal[2] * Orientation[2]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::unordered_map<std::string, std::unordered_map<std::string, DICOMFileRefValue>> DICOMFileMap;
|
typedef std::unordered_map<std::string, DICOMFileHeader> DICOMFileMap;
|
||||||
|
typedef std::vector<DICOMFileHeader> DICOMFileList;
|
||||||
|
typedef std::unordered_map<std::string, DICOMFileMap> SeriesMap;
|
||||||
|
typedef std::unordered_map<std::string, DICOMFileList> SeriesFileMap;
|
||||||
|
|
||||||
class DICOMDirectoryHelper {
|
class DICOMDirectoryHelper {
|
||||||
public:
|
public:
|
||||||
DICOMDirectoryHelper() = default;
|
DICOMDirectoryHelper() = default;
|
||||||
|
|
||||||
~DICOMDirectoryHelper() {
|
~DICOMDirectoryHelper() {
|
||||||
Clear();
|
Clear();
|
||||||
} ;
|
}
|
||||||
|
|
||||||
void SetDirName(const char *dir) {
|
void SetDirName(const char *dir) {
|
||||||
Clear();
|
Clear();
|
||||||
dirName = dir;
|
dirName = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetFileName(const char *file) {
|
void SetFileName(const char *file) {
|
||||||
Clear();
|
Clear();
|
||||||
fileName = file;
|
fileName = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
|
void ReadHeader();
|
||||||
|
|
||||||
|
void ArrangeSeriesProperty();
|
||||||
|
|
||||||
int GetSeriesCount() {
|
int GetSeriesCount() {
|
||||||
return SeriesCount;
|
return SeriesCount;
|
||||||
}
|
}
|
||||||
const std::vector<ExtendMedicalImageProperties*>& GetSeriesProperties()
|
|
||||||
{
|
const std::vector<ExtendMedicalImageProperties *> &GetSeriesProperties() {
|
||||||
return seriesProperties;
|
return seriesProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtendMedicalImageProperties *GetSeries(int idx);
|
ExtendMedicalImageProperties *GetSeries(int idx);
|
||||||
|
|
||||||
ExtendMedicalImageProperties *GetSeriesBySeriesUID(const char *seriesUID);
|
ExtendMedicalImageProperties *GetSeriesBySeriesUID(const char *seriesUID);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string dirName;
|
std::string dirName;
|
||||||
std::string fileName;
|
std::string fileName;
|
||||||
int SeriesCount = 0;
|
int SeriesCount = 0;
|
||||||
|
SeriesFileMap series;
|
||||||
std::vector<ExtendMedicalImageProperties *> seriesProperties;
|
std::vector<ExtendMedicalImageProperties *> seriesProperties;
|
||||||
|
|
||||||
void getDirectoryProperties(const char *rootPath,
|
void getDirectoryProperties(const char *rootPath,
|
||||||
DICOMFileMap &result);
|
SeriesMap &result);
|
||||||
|
|
||||||
|
void getFileProperty(const std::string &path, SeriesMap &result);
|
||||||
|
|
||||||
void getFileProperty(const std::string &path, DICOMFileMap &result);
|
|
||||||
void readImageProperty(ExtendMedicalImageProperties *property);
|
void readImageProperty(ExtendMedicalImageProperties *property);
|
||||||
|
|
||||||
|
void readHeaderFromDir(const char *rootPath);
|
||||||
|
|
||||||
|
void readHeaderFromFile(const char *filePath);
|
||||||
|
|
||||||
|
ExtendMedicalImageProperties *
|
||||||
|
createProperty(const std::vector<DICOMFileHeader> &header, int splitIndex, int beginOffset);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -54,3 +54,33 @@ void ExtendMedicalImageProperties::ComputeTransformMatrix() {
|
|||||||
WorldToModelMatrix->Invert();
|
WorldToModelMatrix->Invert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ExtendMedicalImageProperties::RescaledImageDataIsFloat()
|
||||||
|
{
|
||||||
|
int s = int(this->RescaleSlope);
|
||||||
|
int o = int(this->RescaleOffset);
|
||||||
|
|
||||||
|
float sf = float(s);
|
||||||
|
float of = float(o);
|
||||||
|
|
||||||
|
double d1 = fabs(sf - this->RescaleSlope);
|
||||||
|
double d2 = fabs(of - this->RescaleOffset);
|
||||||
|
|
||||||
|
if (d1 > 0.0 || d2 > 0.0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExtendMedicalImageProperties::RescaledImageDataIsSigned()
|
||||||
|
{
|
||||||
|
bool rescaleSigned = (this->RescaleSlope < 0.0);
|
||||||
|
bool pixelRepSigned = (this->PixelRepresentation == 1);
|
||||||
|
bool offsetSigned = (this->RescaleOffset < 0.0);
|
||||||
|
|
||||||
|
return (rescaleSigned || pixelRepSigned || offsetSigned);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,27 @@ public:
|
|||||||
vtkGetMacro(AcquisitionNumber, long)
|
vtkGetMacro(AcquisitionNumber, long)
|
||||||
vtkSetMacro(AcquisitionNumber, long)
|
vtkSetMacro(AcquisitionNumber, long)
|
||||||
|
|
||||||
|
vtkGetMacro(Rows, long)
|
||||||
|
vtkSetMacro(Rows, long)
|
||||||
|
|
||||||
|
vtkGetMacro(Columns, long)
|
||||||
|
vtkSetMacro(Columns, long)
|
||||||
|
|
||||||
|
vtkGetMacro(RescaleSlope, double)
|
||||||
|
vtkSetMacro(RescaleSlope, double)
|
||||||
|
|
||||||
|
vtkGetMacro(RescaleOffset, double)
|
||||||
|
vtkSetMacro(RescaleOffset, double)
|
||||||
|
|
||||||
vtkGetMacro(SamplePerPixel, unsigned short)
|
vtkGetMacro(SamplePerPixel, unsigned short)
|
||||||
vtkSetMacro(SamplePerPixel, unsigned short)
|
vtkSetMacro(SamplePerPixel, unsigned short)
|
||||||
|
|
||||||
|
vtkGetMacro(BitsAllocated, unsigned short)
|
||||||
|
vtkSetMacro(BitsAllocated, unsigned short)
|
||||||
|
|
||||||
|
vtkGetMacro(PixelRepresentation, unsigned short)
|
||||||
|
vtkSetMacro(PixelRepresentation, unsigned short)
|
||||||
|
|
||||||
vtkSetVector3Macro(Spacing,double);
|
vtkSetVector3Macro(Spacing,double);
|
||||||
vtkGetVector3Macro(Spacing,double);
|
vtkGetVector3Macro(Spacing,double);
|
||||||
|
|
||||||
@@ -48,6 +66,9 @@ public:
|
|||||||
void SetFileNames(std::vector<std::string>& files){
|
void SetFileNames(std::vector<std::string>& files){
|
||||||
FileNames = std::move(files);
|
FileNames = std::move(files);
|
||||||
}
|
}
|
||||||
|
void SetSplitIndex(std::vector<int>& index){
|
||||||
|
SplitIndex = std::move(index);
|
||||||
|
}
|
||||||
|
|
||||||
long GetSeriesNumberAsLong(){
|
long GetSeriesNumberAsLong(){
|
||||||
if (this->SeriesNumber){
|
if (this->SeriesNumber){
|
||||||
@@ -87,6 +108,10 @@ public:
|
|||||||
}
|
}
|
||||||
void ComputeTransformMatrix();
|
void ComputeTransformMatrix();
|
||||||
|
|
||||||
|
bool RescaledImageDataIsFloat();
|
||||||
|
|
||||||
|
bool RescaledImageDataIsSigned();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ExtendMedicalImageProperties();
|
ExtendMedicalImageProperties();
|
||||||
~ExtendMedicalImageProperties() override;
|
~ExtendMedicalImageProperties() override;
|
||||||
@@ -95,9 +120,16 @@ protected:
|
|||||||
double Spacing[3] = {1.0,1.0,1.0};
|
double Spacing[3] = {1.0,1.0,1.0};
|
||||||
double Position[3] = {.0,.0,.0};
|
double Position[3] = {.0,.0,.0};
|
||||||
double ZVector[3] = {.0,.0,.0};
|
double ZVector[3] = {.0,.0,.0};
|
||||||
|
double RescaleSlope = .0;
|
||||||
|
double RescaleOffset = .0;
|
||||||
long AcquisitionNumber = 0;
|
long AcquisitionNumber = 0;
|
||||||
|
long Rows = 0;
|
||||||
|
long Columns = 0;
|
||||||
unsigned short SamplePerPixel;
|
unsigned short SamplePerPixel;
|
||||||
|
unsigned short BitsAllocated;
|
||||||
|
unsigned short PixelRepresentation;
|
||||||
std::vector<std::string> FileNames;
|
std::vector<std::string> FileNames;
|
||||||
|
std::vector<int> SplitIndex;
|
||||||
std::string uniqueID;
|
std::string uniqueID;
|
||||||
vtkNew<vtkMatrix4x4> OrientationMatrix;
|
vtkNew<vtkMatrix4x4> OrientationMatrix;
|
||||||
vtkNew<vtkMatrix4x4> WorldToModelMatrix;
|
vtkNew<vtkMatrix4x4> WorldToModelMatrix;
|
||||||
|
|||||||
@@ -27,10 +27,11 @@ vtkDICOMImageReader2::~vtkDICOMImageReader2() {
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void vtkDICOMImageReader2::SetupOutputInformation(int num_slices)
|
void vtkDICOMImageReader2::SetupOutputInformation(int num_slices)
|
||||||
{
|
{
|
||||||
int width = this->AppHelper->GetWidth();
|
|
||||||
int height = this->AppHelper->GetHeight();
|
int width = this->properties->GetColumns();
|
||||||
int bit_depth = this->AppHelper->GetBitsAllocated();
|
int height = this->properties->GetRows();
|
||||||
int num_comp = this->AppHelper->GetNumberOfComponents();
|
int bit_depth = this->properties->GetBitsAllocated();
|
||||||
|
int num_comp = this->properties->GetSamplePerPixel();
|
||||||
|
|
||||||
this->DataExtent[0] = 0;
|
this->DataExtent[0] = 0;
|
||||||
this->DataExtent[1] = width - 1;
|
this->DataExtent[1] = width - 1;
|
||||||
@@ -39,9 +40,9 @@ void vtkDICOMImageReader2::SetupOutputInformation(int num_slices)
|
|||||||
this->DataExtent[4] = 0;
|
this->DataExtent[4] = 0;
|
||||||
this->DataExtent[5] = num_slices - 1;
|
this->DataExtent[5] = num_slices - 1;
|
||||||
|
|
||||||
bool isFloat = this->AppHelper->RescaledImageDataIsFloat();
|
bool isFloat = this->properties->RescaledImageDataIsFloat();
|
||||||
|
|
||||||
bool sign = this->AppHelper->RescaledImageDataIsSigned();
|
bool sign = this->properties->RescaledImageDataIsSigned();
|
||||||
|
|
||||||
if (isFloat)
|
if (isFloat)
|
||||||
{
|
{
|
||||||
@@ -64,65 +65,18 @@ void vtkDICOMImageReader2::SetupOutputInformation(int num_slices)
|
|||||||
}
|
}
|
||||||
this->SetNumberOfScalarComponents(num_comp);
|
this->SetNumberOfScalarComponents(num_comp);
|
||||||
|
|
||||||
this->GetPixelSpacing();
|
this->properties->GetSpacing(this->DataSpacing);
|
||||||
|
|
||||||
this->vtkImageReader2::ExecuteInformation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vtkDICOMImageReader2::ExecuteInformation() {
|
void vtkDICOMImageReader2::ExecuteInformation() {
|
||||||
vtkDICOMImageReader::ExecuteInformation();
|
if (!properties)
|
||||||
if (!this->DirectoryName && !this->FileName && !DICOMFileNames->empty()){
|
|
||||||
//Sort files
|
|
||||||
std::vector<std::string>::iterator iter;
|
|
||||||
for (iter = this->DICOMFileNames->begin();
|
|
||||||
iter != this->DICOMFileNames->end();
|
|
||||||
++iter)
|
|
||||||
{
|
|
||||||
const char* fn = iter->c_str();
|
|
||||||
vtkDebugMacro( << "Trying : " << fn);
|
|
||||||
|
|
||||||
bool couldOpen = this->Parser->OpenFile(fn);
|
|
||||||
if (!couldOpen)
|
|
||||||
{
|
{
|
||||||
|
vtkErrorMacro( << "No image properties set for the reader.");
|
||||||
|
this->SetErrorCode( vtkErrorCode::FileNotFoundError );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this->SetupOutputInformation(static_cast<int>(properties->GetFileNames().size()));
|
||||||
//
|
|
||||||
this->Parser->ClearAllDICOMTagCallbacks();
|
|
||||||
this->AppHelper->RegisterCallbacks(this->Parser);
|
|
||||||
|
|
||||||
this->Parser->ReadHeader();
|
|
||||||
this->Parser->CloseFile();
|
|
||||||
|
|
||||||
vtkDebugMacro( << "File name : " << fn );
|
|
||||||
vtkDebugMacro( << "Slice number : " << this->AppHelper->GetSliceNumber());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::pair<float, std::string> > sortedFiles;
|
|
||||||
|
|
||||||
this->AppHelper->GetImagePositionPatientFilenamePairs(sortedFiles, false);
|
|
||||||
this->SetupOutputInformation(static_cast<int>(sortedFiles.size()));
|
|
||||||
|
|
||||||
//this->AppHelper->OutputSeries();
|
|
||||||
|
|
||||||
if (!sortedFiles.empty())
|
|
||||||
{
|
|
||||||
this->DICOMFileNames->clear();
|
|
||||||
std::vector<std::pair<float, std::string> >::iterator siter;
|
|
||||||
for (siter = sortedFiles.begin();
|
|
||||||
siter != sortedFiles.end();
|
|
||||||
++siter)
|
|
||||||
{
|
|
||||||
vtkDebugMacro(<< "Sorted filename : " << (*siter).second.c_str());
|
|
||||||
vtkDebugMacro(<< "Adding file " << (*siter).second.c_str() << " at slice : " << (*siter).first);
|
|
||||||
this->DICOMFileNames->push_back((*siter).second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vtkErrorMacro( << "Couldn't get sorted files. Slices may be in wrong order!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vtkDICOMImageReader2::ExecuteDataWithInformation(vtkDataObject *output,
|
void vtkDICOMImageReader2::ExecuteDataWithInformation(vtkDataObject *output,
|
||||||
@@ -130,10 +84,10 @@ void vtkDICOMImageReader2::ExecuteDataWithInformation(vtkDataObject *output,
|
|||||||
{
|
{
|
||||||
vtkImageData *data = this->AllocateOutputData(output, outInfo);
|
vtkImageData *data = this->AllocateOutputData(output, outInfo);
|
||||||
|
|
||||||
if (!this->FileName && this->DICOMFileNames->empty())
|
if (!properties)
|
||||||
{
|
{
|
||||||
vtkErrorMacro( << "Either a filename was not specified or the specified directory does not contain any DICOM images.");
|
vtkErrorMacro( << "No image properties set for the reader.");
|
||||||
this->SetErrorCode( vtkErrorCode::NoFileNameError );
|
this->SetErrorCode( vtkErrorCode::FileNotFoundError );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,30 +202,9 @@ void vtkDICOMImageReader2::ExecuteDataWithInformation(vtkDataObject *output,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//避免z轴被强行设置成正增长
|
|
||||||
double* vtkDICOMImageReader2::GetPixelSpacing()
|
double* vtkDICOMImageReader2::GetPixelSpacing()
|
||||||
{
|
{
|
||||||
std::vector<std::pair<float, std::string> > sortedFiles;
|
return this->properties->GetSpacing();
|
||||||
|
|
||||||
this->AppHelper->GetImagePositionPatientFilenamePairs(sortedFiles, false);
|
|
||||||
|
|
||||||
float* spacing = this->AppHelper->GetPixelSpacing();
|
|
||||||
this->DataSpacing[0] = spacing[0];
|
|
||||||
this->DataSpacing[1] = spacing[1];
|
|
||||||
|
|
||||||
if (sortedFiles.size() > 1)
|
|
||||||
{
|
|
||||||
std::pair<float, std::string> p1 = sortedFiles[0];
|
|
||||||
std::pair<float, std::string> p2 = sortedFiles[1];
|
|
||||||
this->DataSpacing[2] = (p1.first - p2.first);
|
|
||||||
// this->DataSpacing[2] = fabs(p1.first - p2.first);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->DataSpacing[2] = spacing[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->DataSpacing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vtkDICOMImageReader2::SetFileNames(const std::vector<std::string>& files) {
|
void vtkDICOMImageReader2::SetFileNames(const std::vector<std::string>& files) {
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include <vtkDICOMImageReader.h>
|
#include <vtkDICOMImageReader.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "ExtendMedicalImageProperties.h"
|
||||||
class vtkDICOMImageReaderVector : public std::vector<std::string>
|
class vtkDICOMImageReaderVector : public std::vector<std::string>
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -25,6 +27,9 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
void SetFileNames(const std::vector<std::string>& files);
|
void SetFileNames(const std::vector<std::string>& files);
|
||||||
|
void SetImageProperties(ExtendMedicalImageProperties* p){
|
||||||
|
this->properties = p;
|
||||||
|
}
|
||||||
vtkDICOMImageReaderVector* GetDICOMFileNames(){
|
vtkDICOMImageReaderVector* GetDICOMFileNames(){
|
||||||
return DICOMFileNames;
|
return DICOMFileNames;
|
||||||
}
|
}
|
||||||
@@ -33,7 +38,7 @@ protected:
|
|||||||
|
|
||||||
void SetupOutputInformation(int num_slices);
|
void SetupOutputInformation(int num_slices);
|
||||||
void ExecuteInformation() override;
|
void ExecuteInformation() override;
|
||||||
void vtkDICOMImageReader2::ExecuteDataWithInformation(vtkDataObject *output,
|
void ExecuteDataWithInformation(vtkDataObject *output,
|
||||||
vtkInformation *outInfo) override ;
|
vtkInformation *outInfo) override ;
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -48,6 +53,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
vtkDICOMImageReader2(const vtkDICOMImageReader2&) = delete;
|
vtkDICOMImageReader2(const vtkDICOMImageReader2&) = delete;
|
||||||
void operator=(const vtkDICOMImageReader2&) = delete;
|
void operator=(const vtkDICOMImageReader2&) = delete;
|
||||||
|
ExtendMedicalImageProperties* properties;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user