Data loader 2.
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
// Created by Krad on 2022/2/8.
|
// Created by Krad on 2022/2/8.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "DICOMDirectoryHelper.h"
|
#include "DICOMHeaderHelper.h"
|
||||||
#include "dcmtk/dcmdata/dcfilefo.h"
|
#include "dcmtk/dcmdata/dcfilefo.h"
|
||||||
#include "dcmtk/dcmdata/dcdatset.h"
|
#include "dcmtk/dcmdata/dcdatset.h"
|
||||||
#include "ExtendMedicalImageProperties.h"
|
#include "ExtendMedicalImageProperties.h"
|
||||||
@@ -50,7 +50,7 @@ DICOMTag dicom_tags[] = {
|
|||||||
{0x0028, 0x1052, "pixel offset"}
|
{0x0028, 0x1052, "pixel offset"}
|
||||||
};
|
};
|
||||||
|
|
||||||
void DICOMDirectoryHelper::getDirectoryProperties(const char * rootPath, SeriesMap& result){
|
void DICOMHeaderHelper::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();
|
||||||
@@ -72,7 +72,7 @@ void DICOMDirectoryHelper::getDirectoryProperties(const char * rootPath, SeriesM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DICOMDirectoryHelper::getFileProperty(const std::string &path, SeriesMap& result) {
|
void DICOMHeaderHelper::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()) {
|
||||||
@@ -157,11 +157,11 @@ void DICOMDirectoryHelper::getFileProperty(const std::string &path, SeriesMap& r
|
|||||||
char buffer[256] = {0};
|
char buffer[256] = {0};
|
||||||
sprintf(buffer, "%ld-%ld", AcquisitionNumber, InstanceNumber);
|
sprintf(buffer, "%ld-%ld", AcquisitionNumber, InstanceNumber);
|
||||||
printf("%s\r\n", path.c_str());
|
printf("%s\r\n", path.c_str());
|
||||||
result[SeriesUID][buffer] = {path, SeriesNumber, AcquisitionNumber, InstanceNumber};
|
result[SeriesUID][buffer] = {path, "",SeriesNumber, AcquisitionNumber, InstanceNumber};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DICOMDirectoryHelper::Update() {
|
void DICOMHeaderHelper::Update() {
|
||||||
ReadHeader();
|
ReadHeader();
|
||||||
ArrangeSeriesProperty();
|
ArrangeSeriesProperty();
|
||||||
// std::unordered_map<std::string, std::unordered_map<std::string,DICOMFileHeader>> series;
|
// std::unordered_map<std::string, std::unordered_map<std::string,DICOMFileHeader>> series;
|
||||||
@@ -200,12 +200,12 @@ void DICOMDirectoryHelper::Update() {
|
|||||||
SeriesCount = seriesProperties.size();
|
SeriesCount = seriesProperties.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtendMedicalImageProperties* DICOMDirectoryHelper::GetSeries(int idx) {
|
ExtendMedicalImageProperties* DICOMHeaderHelper::GetSeries(int idx) {
|
||||||
if (seriesProperties.size() <= idx) return nullptr;
|
if (seriesProperties.size() <= idx) return nullptr;
|
||||||
return seriesProperties[idx];
|
return seriesProperties[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtendMedicalImageProperties *DICOMDirectoryHelper::GetSeriesBySeriesUID(const char* seriesUID) {
|
ExtendMedicalImageProperties *DICOMHeaderHelper::GetSeriesBySeriesUID(const char* seriesUID) {
|
||||||
for (int i = 0; i < seriesProperties.size(); ++i) {
|
for (int i = 0; i < seriesProperties.size(); ++i) {
|
||||||
if (0==strcmp(seriesProperties[i]->GetSeriesUID(), seriesUID)){
|
if (0==strcmp(seriesProperties[i]->GetSeriesUID(), seriesUID)){
|
||||||
return seriesProperties[i];
|
return seriesProperties[i];
|
||||||
@@ -214,7 +214,7 @@ ExtendMedicalImageProperties *DICOMDirectoryHelper::GetSeriesBySeriesUID(const c
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DICOMDirectoryHelper::Clear() {
|
void DICOMHeaderHelper::Clear() {
|
||||||
dirName.clear();
|
dirName.clear();
|
||||||
fileName.clear();
|
fileName.clear();
|
||||||
for (auto property : seriesProperties) {
|
for (auto property : seriesProperties) {
|
||||||
@@ -224,7 +224,7 @@ void DICOMDirectoryHelper::Clear() {
|
|||||||
SeriesCount = 0;
|
SeriesCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DICOMDirectoryHelper::readImageProperty(ExtendMedicalImageProperties* property) {
|
void DICOMHeaderHelper::readImageProperty(ExtendMedicalImageProperties* property) {
|
||||||
const std::vector<std::string>& files = property->GetFileNames();
|
const std::vector<std::string>& files = property->GetFileNames();
|
||||||
DcmFileFormat file1;
|
DcmFileFormat file1;
|
||||||
// read success!
|
// read success!
|
||||||
@@ -314,7 +314,7 @@ void DICOMDirectoryHelper::readImageProperty(ExtendMedicalImageProperties* prope
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DICOMDirectoryHelper::readHeaderFromDir(const char * rootPath){
|
void DICOMHeaderHelper::readHeaderFromDir(const char * rootPath){
|
||||||
vtkNew<vtkDirectory> dir;
|
vtkNew<vtkDirectory> dir;
|
||||||
dir->Open(rootPath);
|
dir->Open(rootPath);
|
||||||
vtkIdType fileCount = dir->GetNumberOfFiles();
|
vtkIdType fileCount = dir->GetNumberOfFiles();
|
||||||
@@ -336,12 +336,13 @@ void DICOMDirectoryHelper::readHeaderFromDir(const char * rootPath){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DICOMDirectoryHelper::readHeaderFromFile(const char * filePath){
|
void DICOMHeaderHelper::readHeaderFromFile(const char * filePath){
|
||||||
DcmFileFormat file;
|
DcmFileFormat file;
|
||||||
// read success!
|
// read success!
|
||||||
if (file.loadFile(filePath).good()) {
|
if (file.loadFile(filePath).good()) {
|
||||||
DcmDataset *dataset = file.getDataset();
|
DcmDataset *dataset = file.getDataset();
|
||||||
DICOMFileHeader header;
|
DICOMFileHeader header;
|
||||||
|
header.FilePath = filePath;
|
||||||
std::string SeriesUID;
|
std::string SeriesUID;
|
||||||
dataset->findAndGetOFString(DcmTagKey(0x0020, 0x000e), SeriesUID);
|
dataset->findAndGetOFString(DcmTagKey(0x0020, 0x000e), SeriesUID);
|
||||||
|
|
||||||
@@ -359,8 +360,8 @@ void DICOMDirectoryHelper::readHeaderFromFile(const char * filePath){
|
|||||||
ReadTAGToProperty(PatientName, 0x0010, 0x0010)
|
ReadTAGToProperty(PatientName, 0x0010, 0x0010)
|
||||||
ReadTAGToProperty(StudyUID, 0x0020, 0x000d)
|
ReadTAGToProperty(StudyUID, 0x0020, 0x000d)
|
||||||
|
|
||||||
dataset->findAndGetSint32(DcmTagKey(0x0028, 0x0010), header.Rows);
|
dataset->findAndGetUint16(DcmTagKey(0x0028, 0x0010), header.Rows);
|
||||||
dataset->findAndGetSint32(DcmTagKey(0x0028, 0x0011), header.Columns);
|
dataset->findAndGetUint16(DcmTagKey(0x0028, 0x0011), header.Columns);
|
||||||
|
|
||||||
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1050), header.WindowCenter);
|
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1050), header.WindowCenter);
|
||||||
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1051), header.WindowWidth);
|
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1051), header.WindowWidth);
|
||||||
@@ -386,8 +387,9 @@ void DICOMDirectoryHelper::readHeaderFromFile(const char * filePath){
|
|||||||
uniqueID.append(StudyUID);
|
uniqueID.append(StudyUID);
|
||||||
uniqueID.append("_");
|
uniqueID.append("_");
|
||||||
uniqueID.append(SeriesUID);
|
uniqueID.append(SeriesUID);
|
||||||
|
header.SeriesUID = SeriesUID;
|
||||||
// series be firstly loaded
|
// series be firstly loaded
|
||||||
if (!series.count(SeriesUID)) {
|
if (series.count(uniqueID)==0) {
|
||||||
series.emplace(uniqueID,DICOMFileList());
|
series.emplace(uniqueID,DICOMFileList());
|
||||||
}
|
}
|
||||||
header.calculateImagePosition();
|
header.calculateImagePosition();
|
||||||
@@ -395,7 +397,7 @@ void DICOMDirectoryHelper::readHeaderFromFile(const char * filePath){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DICOMDirectoryHelper::ReadHeader() {
|
void DICOMHeaderHelper::ReadHeader() {
|
||||||
|
|
||||||
if (!this->dirName.empty()){
|
if (!this->dirName.empty()){
|
||||||
vtkNew<vtkDirectory> dir;
|
vtkNew<vtkDirectory> dir;
|
||||||
@@ -422,7 +424,7 @@ void DICOMDirectoryHelper::ReadHeader() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DICOMDirectoryHelper::ArrangeSeriesProperty() {
|
void DICOMHeaderHelper::ArrangeSeriesProperty() {
|
||||||
for (auto item : series) {
|
for (auto item : series) {
|
||||||
//sort by series, instance, AcquisitionNumber
|
//sort by series, instance, AcquisitionNumber
|
||||||
std::sort(item.second.begin(), item.second.end(), [](auto v1, auto v2) {
|
std::sort(item.second.begin(), item.second.end(), [](auto v1, auto v2) {
|
||||||
@@ -445,21 +447,22 @@ void DICOMDirectoryHelper::ArrangeSeriesProperty() {
|
|||||||
[](auto v1,auto v2){
|
[](auto v1,auto v2){
|
||||||
return v1.image_position<v2.image_position;
|
return v1.image_position<v2.image_position;
|
||||||
});
|
});
|
||||||
seriesProperties.push_back(createProperty(item.second, splitIndex[j], beginOffset));
|
auto p = createProperty(item.second, splitIndex[j], beginOffset);
|
||||||
|
if (p)seriesProperties.push_back(p);
|
||||||
beginOffset = splitIndex[j];
|
beginOffset = splitIndex[j];
|
||||||
}
|
}
|
||||||
//sort the last image set
|
//sort the last image set
|
||||||
if (splitIndex.size()>0) {
|
|
||||||
std::sort(item.second.begin() + beginOffset, item.second.end(),
|
std::sort(item.second.begin() + beginOffset, item.second.end(),
|
||||||
[](auto v1, auto v2) {
|
[](auto v1, auto v2) {
|
||||||
return v1.image_position < v2.image_position;
|
return v1.image_position < v2.image_position;
|
||||||
});
|
});
|
||||||
seriesProperties.push_back(createProperty(item.second, item.second.size()-1, beginOffset));
|
auto p = createProperty(item.second, item.second.size(), beginOffset);
|
||||||
}
|
if (p)seriesProperties.push_back(p);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtendMedicalImageProperties* DICOMDirectoryHelper::createProperty(const std::vector<DICOMFileHeader>& headerList, int splitIndex, int beginOffset) {
|
ExtendMedicalImageProperties* DICOMHeaderHelper::createProperty(const std::vector<DICOMFileHeader>& headerList, int splitIndex, int beginOffset) {
|
||||||
auto property = ExtendMedicalImageProperties::New();
|
auto property = ExtendMedicalImageProperties::New();
|
||||||
std::vector<std::string> files;
|
std::vector<std::string> files;
|
||||||
for (int i = beginOffset; i < splitIndex; ++i) {
|
for (int i = beginOffset; i < splitIndex; ++i) {
|
||||||
@@ -506,20 +509,28 @@ ExtendMedicalImageProperties* DICOMDirectoryHelper::createProperty(const std::ve
|
|||||||
double thickness= 1.0;
|
double thickness= 1.0;
|
||||||
dataset->findAndGetFloat64(DcmTagKey(0x0008, 0x0050), thickness);
|
dataset->findAndGetFloat64(DcmTagKey(0x0008, 0x0050), thickness);
|
||||||
double RescaleSlope= 1.0;
|
double RescaleSlope= 1.0;
|
||||||
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1052), RescaleSlope);
|
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1053), RescaleSlope);
|
||||||
double RescaleOffset= 1.0;
|
double RescaleOffset= 1.0;
|
||||||
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1053), RescaleOffset);
|
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1052), RescaleOffset);
|
||||||
unsigned short bitsAllocated= 1;
|
unsigned short bitsAllocated= 1;
|
||||||
dataset->findAndGetUint16(DcmTagKey(0x0028, 0x1000), bitsAllocated);
|
dataset->findAndGetUint16(DcmTagKey(0x0028, 0x0100), bitsAllocated);
|
||||||
unsigned short PixelRepresentation= 0;
|
unsigned short PixelRepresentation= 0;
|
||||||
dataset->findAndGetUint16(DcmTagKey(0x0028, 0x1000), PixelRepresentation);
|
dataset->findAndGetUint16(DcmTagKey(0x0028, 0x0103), PixelRepresentation);
|
||||||
|
property->SetSeriesUID(header.SeriesUID.c_str());
|
||||||
|
property->SetRows(header.Rows);
|
||||||
|
property->SetColumns(header.Columns);
|
||||||
property->SetSpacing(header.Spacing[0],header.Spacing[1],thickness);
|
property->SetSpacing(header.Spacing[0],header.Spacing[1],thickness);
|
||||||
property->SetRescaleSlope(RescaleSlope);
|
property->SetRescaleSlope(RescaleSlope);
|
||||||
property->SetRescaleOffset(RescaleOffset);
|
property->SetRescaleOffset(RescaleOffset);
|
||||||
property->SetBitsAllocated(bitsAllocated);
|
property->SetBitsAllocated(bitsAllocated);
|
||||||
property->SetPixelRepresentation(PixelRepresentation);
|
property->SetPixelRepresentation(PixelRepresentation);
|
||||||
}
|
}
|
||||||
if (headerList.size()>1){
|
else{
|
||||||
|
printf( " file:%s load error!\r\b", header.FilePath.c_str() );
|
||||||
|
property->Delete();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (splitIndex-beginOffset>1){
|
||||||
const DICOMFileHeader& header2 = headerList[beginOffset+1];
|
const DICOMFileHeader& header2 = headerList[beginOffset+1];
|
||||||
double spacing2 = sqrt(vtkMath::Distance2BetweenPoints(header.Position,header2.Position));
|
double spacing2 = sqrt(vtkMath::Distance2BetweenPoints(header.Position,header2.Position));
|
||||||
property->SetSpacing(property->GetSpacing()[0],property->GetSpacing()[1],spacing2);
|
property->SetSpacing(property->GetSpacing()[0],property->GetSpacing()[1],spacing2);
|
||||||
@@ -14,12 +14,13 @@ class ExtendMedicalImageProperties;
|
|||||||
|
|
||||||
struct DICOMFileHeader {
|
struct DICOMFileHeader {
|
||||||
std::string FilePath;
|
std::string FilePath;
|
||||||
|
std::string SeriesUID;
|
||||||
long SeriesNumber = 0;
|
long SeriesNumber = 0;
|
||||||
long AcquisitionNumber = 0;
|
long AcquisitionNumber = 0;
|
||||||
long InstanceNumber = 0;
|
long InstanceNumber = 0;
|
||||||
double Spacing[2] = {1., 1.};
|
double Spacing[2] = {1., 1.};
|
||||||
long Rows;
|
unsigned short Rows;
|
||||||
long Columns;
|
unsigned short Columns;
|
||||||
unsigned short SamplePerPixel;
|
unsigned short SamplePerPixel;
|
||||||
double WindowCenter = 0;
|
double WindowCenter = 0;
|
||||||
double WindowWidth = 0;
|
double WindowWidth = 0;
|
||||||
@@ -52,11 +53,11 @@ typedef std::vector<DICOMFileHeader> DICOMFileList;
|
|||||||
typedef std::unordered_map<std::string, DICOMFileMap> SeriesMap;
|
typedef std::unordered_map<std::string, DICOMFileMap> SeriesMap;
|
||||||
typedef std::unordered_map<std::string, DICOMFileList> SeriesFileMap;
|
typedef std::unordered_map<std::string, DICOMFileList> SeriesFileMap;
|
||||||
|
|
||||||
class DICOMDirectoryHelper {
|
class DICOMHeaderHelper {
|
||||||
public:
|
public:
|
||||||
DICOMDirectoryHelper() = default;
|
DICOMHeaderHelper() = default;
|
||||||
|
|
||||||
~DICOMDirectoryHelper() {
|
~DICOMHeaderHelper() {
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
166
src/src/IO/DICOM/DICOMPixelDataHelper.cpp
Normal file
166
src/src/IO/DICOM/DICOMPixelDataHelper.cpp
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
//
|
||||||
|
// Created by Krad on 2022/9/9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "DICOMPixelDataHelper.h"
|
||||||
|
#include <dcmtk/dcmdata/dcrledrg.h>
|
||||||
|
#include <dcmtk/dcmjpeg/djdecode.h>
|
||||||
|
#include <dcmtk/dcmjpls/djdecode.h>
|
||||||
|
#include <dcmtk/dcmdata/dcfilefo.h>
|
||||||
|
#include <dcmtk/dcmimgle/dcmimage.h>
|
||||||
|
#include <dcmtk/dcmimgle/dipixel.h>
|
||||||
|
#include "ExtendMedicalImageProperties.h"
|
||||||
|
#ifdef OPENJPEG
|
||||||
|
#include "openjpeg-2.3/openjpeg.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void DICOMPixelDataHelper::InitCodecs() {
|
||||||
|
DcmRLEDecoderRegistration::registerCodecs(OFFalse, OFTrue);//注册解码器
|
||||||
|
/// register JPEG decompression codecs
|
||||||
|
DJDecoderRegistration::registerCodecs();//注册解码器
|
||||||
|
DJLSDecoderRegistration::registerCodecs();
|
||||||
|
#ifdef OPENJPEG
|
||||||
|
FMJPEG2KDecoderRegistration::registerCodecs();//jpeg2000
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void DICOMPixelDataHelper::FinalizeCodecs() {
|
||||||
|
DcmRLEDecoderRegistration::cleanup();
|
||||||
|
DJDecoderRegistration::cleanup();
|
||||||
|
DJLSDecoderRegistration::cleanup();
|
||||||
|
#ifdef OPENJPEG
|
||||||
|
FMJPEG2KDecoderRegistration::cleanup();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void DICOMPixelDataHelper::GetThumbnailData(ExtendMedicalImageProperties *property, unsigned char* data,
|
||||||
|
unsigned long& length) {
|
||||||
|
double *wlww = property->GetNthWindowLevelPreset(0);
|
||||||
|
int ww = wlww ? ((int) wlww[0]) : (512);
|
||||||
|
int wl = wlww ? ((int) wlww[1]) : (256);
|
||||||
|
int sample = property->GetSamplePerPixel();
|
||||||
|
DcmFileFormat *fileFormat = new DcmFileFormat();//读取文件获取传输语法
|
||||||
|
if (fileFormat->loadFile(property->GetThumbnailFileName()).good()) {
|
||||||
|
DcmDataset *dset = fileFormat->getDataset();
|
||||||
|
DicomImage dcmImage(fileFormat, dset->getOriginalXfer(), CIF_MayDetachPixelData);
|
||||||
|
DicomImage *sdcmImage = dcmImage.createScaledImage(100.0, 0.0, 0, 1);
|
||||||
|
sdcmImage->setWindow(wl, ww);
|
||||||
|
sdcmImage->showAllOverlays();
|
||||||
|
length = sdcmImage->getOutputDataSize(8);
|
||||||
|
unsigned char *outputData = (unsigned char *) sdcmImage->getOutputData(8);//按8位的位宽取数据
|
||||||
|
data = new unsigned char[length];
|
||||||
|
memcpy(data, outputData, length);
|
||||||
|
delete sdcmImage;
|
||||||
|
}
|
||||||
|
delete fileFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void DICOMPixelDataHelper::GetPixelData(const char * path, void *data, unsigned long& length) {
|
||||||
|
DcmFileFormat *fileFormat = new DcmFileFormat();//读取文件获取传输语法
|
||||||
|
if (fileFormat->loadFile(path).good()) {
|
||||||
|
DcmDataset *dset = fileFormat->getDataset();
|
||||||
|
DicomImage* dcmImage = new DicomImage(fileFormat, dset->getOriginalXfer(),CIF_MayDetachPixelData);
|
||||||
|
const DiPixel* pixelData = dcmImage->getInterData();//rescaled
|
||||||
|
unsigned long dataBits = 1;
|
||||||
|
switch (pixelData->getRepresentation()){
|
||||||
|
case EPR_Uint8:
|
||||||
|
case EPR_Sint8:
|
||||||
|
break;
|
||||||
|
case EPR_Uint16:
|
||||||
|
case EPR_Sint16:
|
||||||
|
dataBits = 2;
|
||||||
|
break;
|
||||||
|
case EPR_Uint32:
|
||||||
|
case EPR_Sint32:
|
||||||
|
dataBits = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void * dd = pixelData->getData();
|
||||||
|
length = pixelData->getCount() ;
|
||||||
|
length = length*dataBits;
|
||||||
|
memcpy(data,dd, length);
|
||||||
|
delete dcmImage;
|
||||||
|
} else{
|
||||||
|
length=-1;
|
||||||
|
}
|
||||||
|
delete fileFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void convertAndRescale(const void* input, void* output, double slope, double intercept, unsigned long length)
|
||||||
|
{
|
||||||
|
const T* in = static_cast<const T*>(input);
|
||||||
|
float* out = static_cast<float*>(output);
|
||||||
|
for (int i = 0; i <length ; ++i) {
|
||||||
|
*(out++) = static_cast<float>(static_cast<double>(*(in++))*slope+intercept);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void* DICOMPixelDataHelper::GetPixelDataFloat(const char *path, unsigned long &length) {
|
||||||
|
void* data = nullptr;
|
||||||
|
DcmFileFormat *fileFormat = new DcmFileFormat();
|
||||||
|
if (fileFormat->loadFile(path).good()) {
|
||||||
|
DcmDataset *dataset = fileFormat->getDataset();
|
||||||
|
DicomImage dcmImage(fileFormat, dataset->getOriginalXfer(), CIF_IgnoreModalityTransformation);
|
||||||
|
const DiPixel* pixelData = dcmImage.getInterData();//no rescaled
|
||||||
|
length = pixelData->getCount();
|
||||||
|
const void* pData = pixelData->getData();
|
||||||
|
data = new float [length];
|
||||||
|
double slope= 1.0;
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1053), slope);
|
||||||
|
double intercept= 0.0;
|
||||||
|
dataset->findAndGetFloat64(DcmTagKey(0x0028, 0x1052), intercept);
|
||||||
|
switch (pixelData->getRepresentation()){
|
||||||
|
case EPR_Uint8:
|
||||||
|
convertAndRescale<Uint8>(pData,data,slope,intercept,length);
|
||||||
|
break;
|
||||||
|
case EPR_Sint8:
|
||||||
|
convertAndRescale<Sint8>(pData,data,slope,intercept,length);
|
||||||
|
break;
|
||||||
|
case EPR_Uint16:
|
||||||
|
convertAndRescale<Uint16>(pData,data,slope,intercept,length);
|
||||||
|
break;
|
||||||
|
case EPR_Sint16:
|
||||||
|
convertAndRescale<Sint16>(pData,data,slope,intercept,length);
|
||||||
|
break;
|
||||||
|
case EPR_Uint32:
|
||||||
|
convertAndRescale<Uint32>(pData,data,slope,intercept,length);
|
||||||
|
break;
|
||||||
|
case EPR_Sint32:
|
||||||
|
convertAndRescale<Sint32>(pData,data,slope,intercept,length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else{
|
||||||
|
length=-1;
|
||||||
|
}
|
||||||
|
delete fileFormat;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DICOMPixelDataHelper::GetOverlayData(const char *path, void *data,
|
||||||
|
unsigned int& width, unsigned int& height, unsigned int plane) {
|
||||||
|
DcmFileFormat *fileFormat = new DcmFileFormat();//读取文件获取传输语法
|
||||||
|
if (fileFormat->loadFile(path).good()) {
|
||||||
|
DcmDataset *dset = fileFormat->getDataset();
|
||||||
|
DicomImage dcmImage(fileFormat, dset->getOriginalXfer(), CIF_MayDetachPixelData);
|
||||||
|
if(dcmImage.getOverlayCount()>plane){
|
||||||
|
const void * overlay = dcmImage.getFullOverlayData(plane,width, height);
|
||||||
|
int dataLength = width*height;
|
||||||
|
data = new unsigned char[dataLength];
|
||||||
|
memcpy(data, overlay,dataLength);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
width=-1;
|
||||||
|
height=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
width=-1;
|
||||||
|
height=-1;
|
||||||
|
}
|
||||||
|
delete fileFormat;
|
||||||
|
}
|
||||||
29
src/src/IO/DICOM/DICOMPixelDataHelper.h
Normal file
29
src/src/IO/DICOM/DICOMPixelDataHelper.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
//
|
||||||
|
// Created by Krad on 2022/9/9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef OMEGAV_DICOMPIXELDATAHELPER_H
|
||||||
|
#define OMEGAV_DICOMPIXELDATAHELPER_H
|
||||||
|
|
||||||
|
class ExtendMedicalImageProperties;
|
||||||
|
|
||||||
|
class DICOMPixelDataHelper {
|
||||||
|
public:
|
||||||
|
DICOMPixelDataHelper() = default;
|
||||||
|
|
||||||
|
~DICOMPixelDataHelper() {
|
||||||
|
}
|
||||||
|
static void GetThumbnailData(ExtendMedicalImageProperties *property, unsigned char* data,
|
||||||
|
unsigned long& length);
|
||||||
|
static void GetPixelData(const char * path, void* data,unsigned long& length);
|
||||||
|
static void* GetPixelDataFloat(const char * path,unsigned long& length);
|
||||||
|
static void GetOverlayData(const char * path, void* data,
|
||||||
|
unsigned int& width, unsigned int& height,unsigned int plane = 0);
|
||||||
|
|
||||||
|
static void InitCodecs();
|
||||||
|
|
||||||
|
static void FinalizeCodecs();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //OMEGAV_DICOMPIXELDATAHELPER_H
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "DicomLoader.h"
|
#include "DicomLoader.h"
|
||||||
|
|
||||||
#include "Common/SeriesImageSet.h"
|
#include "Common/SeriesImageSet.h"
|
||||||
#include "DICOMDirectoryHelper.h"
|
#include "DICOMHeaderHelper.h"
|
||||||
#include "ExtendMedicalImageProperties.h"
|
#include "ExtendMedicalImageProperties.h"
|
||||||
#include "vtkDICOMImageReader2.h"
|
#include "vtkDICOMImageReader2.h"
|
||||||
#include "vtkImageData.h"
|
#include "vtkImageData.h"
|
||||||
@@ -131,7 +131,8 @@ SeriesImageSet* DicomLoader::getSeriesImageSet(const std::string& uniqueID)//, D
|
|||||||
});
|
});
|
||||||
if (iter==imageProperties.end()) return nullptr;
|
if (iter==imageProperties.end()) return nullptr;
|
||||||
|
|
||||||
reader->SetFileNames((*iter)->GetFileNames());
|
// reader->SetFileNames((*iter)->GetFileNames());
|
||||||
|
reader->SetImageProperties((*iter));
|
||||||
reader->Update();
|
reader->Update();
|
||||||
auto imageData = reader->GetOutput();
|
auto imageData = reader->GetOutput();
|
||||||
SeriesImageSet* result = new SeriesImageSet((*iter),imageData);
|
SeriesImageSet* result = new SeriesImageSet((*iter),imageData);
|
||||||
@@ -145,7 +146,7 @@ SeriesImageSet* DicomLoader::getSeriesImageSet(const std::string& uniqueID)//, D
|
|||||||
|
|
||||||
void DicomLoader::readTags(const std::string &dir, SeriesOpenMode openMode)
|
void DicomLoader::readTags(const std::string &dir, SeriesOpenMode openMode)
|
||||||
{
|
{
|
||||||
DICOMDirectoryHelper DICOMHelper;
|
DICOMHeaderHelper DICOMHelper;
|
||||||
if (openMode == FILE_OPEN_MODE)
|
if (openMode == FILE_OPEN_MODE)
|
||||||
{
|
{
|
||||||
//m_itkSeriesReader->SetFileName(m_dicomName.toStdString());
|
//m_itkSeriesReader->SetFileName(m_dicomName.toStdString());
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public:
|
|||||||
class SeriesImageSet;
|
class SeriesImageSet;
|
||||||
|
|
||||||
|
|
||||||
class DICOMDirectoryHelper;
|
class DICOMHeaderHelper;
|
||||||
class ExtendMedicalImageProperties;
|
class ExtendMedicalImageProperties;
|
||||||
class vtkDICOMImageReader2;
|
class vtkDICOMImageReader2;
|
||||||
typedef std::map<std::string, SeriesImageSet*> ImageSetStore;
|
typedef std::map<std::string, SeriesImageSet*> ImageSetStore;
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public:
|
|||||||
|
|
||||||
const char* GetThumbnailFileName(){
|
const char* GetThumbnailFileName(){
|
||||||
if (FileNames.empty()) return nullptr;
|
if (FileNames.empty()) return nullptr;
|
||||||
return FileNames[FileNames.size()/2].data();
|
return FileNames[0].data();
|
||||||
}
|
}
|
||||||
unsigned long long GetSliceCount(){
|
unsigned long long GetSliceCount(){
|
||||||
return FileNames.size();
|
return FileNames.size();
|
||||||
|
|||||||
@@ -9,13 +9,10 @@
|
|||||||
#include "vtkObjectFactory.h"
|
#include "vtkObjectFactory.h"
|
||||||
#include "vtkPointData.h"
|
#include "vtkPointData.h"
|
||||||
|
|
||||||
#include "DICOMAppHelper.h"
|
#include "IO/DICOM/DICOMPixelDataHelper.h"
|
||||||
#include "DICOMParser.h"
|
|
||||||
vtkStandardNewMacro(vtkDICOMImageReader2);
|
vtkStandardNewMacro(vtkDICOMImageReader2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vtkDICOMImageReader2::vtkDICOMImageReader2():vtkDICOMImageReader() {
|
vtkDICOMImageReader2::vtkDICOMImageReader2():vtkDICOMImageReader() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -80,124 +77,51 @@ void vtkDICOMImageReader2::ExecuteInformation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void vtkDICOMImageReader2::ExecuteDataWithInformation(vtkDataObject *output,
|
void vtkDICOMImageReader2::ExecuteDataWithInformation(vtkDataObject *output,
|
||||||
vtkInformation *outInfo)
|
vtkInformation *outInfo) {
|
||||||
{
|
|
||||||
vtkImageData *data = this->AllocateOutputData(output, outInfo);
|
vtkImageData *data = this->AllocateOutputData(output, outInfo);
|
||||||
|
if (!properties) {
|
||||||
if (!properties)
|
vtkErrorMacro(<< "No image properties set for the reader.");
|
||||||
{
|
this->SetErrorCode(vtkErrorCode::FileNotFoundError);
|
||||||
vtkErrorMacro( << "No image properties set for the reader.");
|
|
||||||
this->SetErrorCode( vtkErrorCode::FileNotFoundError );
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->GetPointData()->GetScalars()->SetName("DICOMImage");
|
data->GetPointData()->GetScalars()->SetName("DICOMImage");
|
||||||
|
|
||||||
this->ComputeDataIncrements();
|
this->ComputeDataIncrements();
|
||||||
|
void *buffer = data->GetScalarPointer();
|
||||||
if (this->FileName)
|
if (buffer == nullptr) {
|
||||||
{
|
vtkErrorMacro(<< "No memory allocated for image data!");
|
||||||
vtkDebugMacro( << "Single file : " << this->FileName);
|
return;
|
||||||
this->Parser->ClearAllDICOMTagCallbacks();
|
|
||||||
this->Parser->OpenFile(this->FileName);
|
|
||||||
this->AppHelper->Clear();
|
|
||||||
this->AppHelper->RegisterCallbacks(this->Parser);
|
|
||||||
this->AppHelper->RegisterPixelDataCallback(this->Parser);
|
|
||||||
|
|
||||||
this->Parser->ReadHeader();
|
|
||||||
|
|
||||||
void* imgData = nullptr;
|
|
||||||
DICOMParser::VRTypes dataType;
|
|
||||||
unsigned long imageDataLength;
|
|
||||||
|
|
||||||
this->AppHelper->GetImageData(imgData, dataType, imageDataLength);
|
|
||||||
if( !imageDataLength )
|
|
||||||
{
|
|
||||||
vtkErrorMacro( << "There was a problem retrieving data from: " << this->FileName );
|
|
||||||
this->SetErrorCode( vtkErrorCode::FileFormatError );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* buffer = data->GetScalarPointer();
|
|
||||||
if (buffer == nullptr)
|
|
||||||
{
|
|
||||||
vtkErrorMacro(<< "No memory allocated for image data!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// DICOM stores the upper left pixel as the first pixel in an
|
|
||||||
// image. VTK stores the lower left pixel as the first pixel in
|
|
||||||
// an image. Need to flip the data.
|
|
||||||
vtkIdType rowLength;
|
|
||||||
rowLength = this->DataIncrements[1];
|
|
||||||
unsigned char *b = (unsigned char *)buffer;
|
|
||||||
unsigned char *iData = (unsigned char *)imgData;
|
|
||||||
memcpy(b,imgData,imageDataLength);
|
|
||||||
// iData += (imageDataLength - rowLength); // beginning of last row
|
|
||||||
// for (int i=0; i < this->AppHelper->GetHeight(); ++i)
|
|
||||||
// {
|
|
||||||
// memcpy(b, iData, rowLength);
|
|
||||||
// b += rowLength;
|
|
||||||
// iData -= rowLength;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
else if (!this->DICOMFileNames->empty())
|
for (int i = 0; i < properties->GetFileNames().size(); ++i) {
|
||||||
{
|
const std::string& path = properties->GetFileNames()[i];
|
||||||
vtkDebugMacro( << "Multiple files (" << static_cast<int>(this->DICOMFileNames->size()) << ")");
|
if (this->DataScalarType == VTK_FLOAT)
|
||||||
this->Parser->ClearAllDICOMTagCallbacks();
|
|
||||||
this->AppHelper->Clear();
|
|
||||||
this->AppHelper->RegisterCallbacks(this->Parser);
|
|
||||||
this->AppHelper->RegisterPixelDataCallback(this->Parser);
|
|
||||||
|
|
||||||
void* buffer = data->GetScalarPointer();
|
|
||||||
if (buffer == nullptr)
|
|
||||||
{
|
{
|
||||||
vtkErrorMacro(<< "No memory allocated for image data!");
|
void *imgData = nullptr;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string>::iterator fiter;
|
unsigned long imageDataLength;
|
||||||
|
|
||||||
int count = 0;
|
imgData = DICOMPixelDataHelper::GetPixelDataFloat(path.c_str(),imageDataLength);
|
||||||
vtkIdType numFiles = static_cast<int>(this->DICOMFileNames->size());
|
if(imgData){
|
||||||
|
//calc size of float
|
||||||
for (fiter = this->DICOMFileNames->begin();
|
imageDataLength = imageDataLength * sizeof(float);
|
||||||
fiter != this->DICOMFileNames->end();
|
unsigned char *b = (unsigned char *) buffer;
|
||||||
++fiter)
|
unsigned char *iData = (unsigned char *) imgData;
|
||||||
{
|
memcpy(b, imgData, imageDataLength);
|
||||||
count++;
|
buffer = ((char*) buffer) + imageDataLength;
|
||||||
const char *file = fiter->c_str();
|
}
|
||||||
vtkDebugMacro( << "File : " << file );
|
else{
|
||||||
this->Parser->OpenFile( file );
|
vtkErrorMacro(<< "Can't read data from path:"<<path.c_str()<<"!");
|
||||||
this->Parser->ReadHeader();
|
|
||||||
|
|
||||||
void* imgData = nullptr;
|
|
||||||
DICOMParser::VRTypes dataType;
|
|
||||||
unsigned long imageDataLengthInBytes;
|
|
||||||
|
|
||||||
this->AppHelper->GetImageData(imgData, dataType, imageDataLengthInBytes);
|
|
||||||
if( !imageDataLengthInBytes )
|
|
||||||
{
|
|
||||||
vtkErrorMacro( << "There was a problem retrieving data from: " << file );
|
|
||||||
this->SetErrorCode( vtkErrorCode::FileFormatError );
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
void *imgData = nullptr;
|
||||||
|
|
||||||
// DICOM stores the upper left pixel as the first pixel in an
|
unsigned long imageDataLength;
|
||||||
// image. VTK stores the lower left pixel as the first pixel in
|
unsigned char *b = (unsigned char *) buffer;
|
||||||
// an image. Need to flip the data.
|
DICOMPixelDataHelper::GetPixelData(path.c_str(), buffer,imageDataLength);
|
||||||
vtkIdType rowLength;
|
buffer = ((char*) buffer) + imageDataLength;
|
||||||
rowLength = this->DataIncrements[1];
|
|
||||||
unsigned char *b = (unsigned char *)buffer;
|
|
||||||
unsigned char *iData = (unsigned char *)imgData;
|
|
||||||
memcpy(b,imgData,imageDataLengthInBytes);
|
|
||||||
buffer = ((char*) buffer) + imageDataLengthInBytes;
|
|
||||||
|
|
||||||
this->UpdateProgress(float(count)/float(numFiles));
|
|
||||||
int len = static_cast<int> (strlen((const char*) (*fiter).c_str()));
|
|
||||||
char* filename = new char[len+1];
|
|
||||||
strcpy(filename, (const char*) (*fiter).c_str());
|
|
||||||
this->SetProgressText(filename);
|
|
||||||
delete[] filename;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,10 +134,6 @@ double* vtkDICOMImageReader2::GetPixelSpacing()
|
|||||||
void vtkDICOMImageReader2::SetFileNames(const std::vector<std::string>& files) {
|
void vtkDICOMImageReader2::SetFileNames(const std::vector<std::string>& files) {
|
||||||
|
|
||||||
this->DICOMFileNames->clear();
|
this->DICOMFileNames->clear();
|
||||||
this->AppHelper->Clear();
|
|
||||||
|
|
||||||
this->DirectoryName = nullptr;
|
|
||||||
this->FileName = nullptr;
|
|
||||||
for (vtkIdType i = 0; i < files.size(); i++)
|
for (vtkIdType i = 0; i < files.size(); i++)
|
||||||
{
|
{
|
||||||
if (strcmp(files[i].c_str(), ".") == 0 ||
|
if (strcmp(files[i].c_str(), ".") == 0 ||
|
||||||
@@ -223,18 +143,7 @@ void vtkDICOMImageReader2::SetFileNames(const std::vector<std::string>& files) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string fileString = files[i];
|
std::string fileString = files[i];
|
||||||
|
vtkDebugMacro( << "Adding " << fileString.c_str() << " to DICOMFileNames.");
|
||||||
int val = this->CanReadFile(fileString.c_str());
|
this->DICOMFileNames->push_back(fileString);
|
||||||
|
|
||||||
if (val == 1)
|
|
||||||
{
|
|
||||||
vtkDebugMacro( << "Adding " << fileString.c_str() << " to DICOMFileNames.");
|
|
||||||
this->DICOMFileNames->push_back(fileString);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vtkDebugMacro( << fileString.c_str() << " - DICOMParser CanReadFile returned : " << val);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user