mirror of
https://gitlab.ethz.ch/gfattori/glocalize.git
synced 2026-05-03 13:44:26 +02:00
451 lines
16 KiB
C++
451 lines
16 KiB
C++
#include "DicomScanService.h"
|
|
|
|
|
|
/*_________________________________________________________-
|
|
|
|
Patient loader for gLocalize.
|
|
no wrkDir behaviour. just load data
|
|
____________________________________________________________*/
|
|
|
|
|
|
DicomScanService::gLoadPatient(){
|
|
patientInfos = new gPatientRTGeneralInfos;
|
|
readRT=0;
|
|
m_rtIsocenter=0;
|
|
initialized=false;
|
|
virtualIso=false;
|
|
//cout<< "DicomScanService::gLoadPatient" <<endl;
|
|
}
|
|
|
|
|
|
void DicomScanService::load(QString p_loadDir){
|
|
|
|
this->parse(p_loadDir);
|
|
|
|
if(patientInfos->CTfiles .size()!=0){
|
|
cout<< "this->load2VTK(patientInfos)" <<endl;
|
|
|
|
if(readRT!=0){
|
|
delete readRT;
|
|
readRT = 0;
|
|
}
|
|
if(m_rtIsocenter!=0){
|
|
delete m_rtIsocenter;
|
|
m_rtIsocenter = 0;
|
|
}
|
|
|
|
if(!patientInfos->rtIonPlanPath.isEmpty()){
|
|
readRT = new RTPlan;
|
|
readRT->fillRTPlan(patientInfos->rtIonPlanPath.toLatin1().data() );
|
|
m_rtIsocenter = new double[3];
|
|
if (readRT->NumberOfBeams > 0){
|
|
{
|
|
const auto& iso = readRT->Beams.at(0)->IsocenterPosition;
|
|
m_rtIsocenter[0] = iso[0];
|
|
m_rtIsocenter[1] = iso[1];
|
|
m_rtIsocenter[2] = iso[2];
|
|
}
|
|
if (readRT->PatientOrientation.rfind("HFS", 0) == 0)
|
|
m_patientOrientation = SUPINE;
|
|
else if (readRT->PatientOrientation.rfind("HFP", 0) == 0)
|
|
m_patientOrientation = PRONE;
|
|
else m_patientOrientation = NOTDEFINED;
|
|
|
|
if (callbacks.loadedRTIso) callbacks.loadedRTIso(m_rtIsocenter);
|
|
//for (int ii=0;ii<readRT->NumberOfBeams; ii++){
|
|
// cout<< readRT->Beams[ii]->IsocenterPosition[0]<<" ";
|
|
// cout<< readRT->Beams[ii]->IsocenterPosition[1]<<" ";
|
|
// cout<< readRT->Beams[ii]->IsocenterPosition[2]<<" "<<endl;
|
|
//}
|
|
//cout<< "nbeams: "<<readRT->NumberOfBeams <<endl;
|
|
//cout<< "iso0: "<<readRT->Beams.at(0)->IsocenterPosition[0] <<endl;
|
|
//cout<< "iso2: "<<readRT->Beams.at(2)->IsocenterPosition[0]<<endl;
|
|
//cout<< "iso0: "<<readRT->Beams.at(0)->IsocenterPosition[1] <<endl;
|
|
//cout<< "iso2: "<<readRT->Beams.at(2)->IsocenterPosition[1]<<endl;
|
|
//cout<< "iso0: "<<readRT->Beams.at(0)->IsocenterPosition[2] <<endl;
|
|
//cout<< "iso2: "<<readRT->Beams.at(2)->IsocenterPosition[2]<<endl;
|
|
|
|
/*check for virtual iso, adapted from GB, gOTS v04Build34*/
|
|
if(readRT->NumberOfBeams > 2 &&
|
|
(readRT->Beams.at(0)->IsocenterPosition[0] != readRT->Beams.at(2)->IsocenterPosition[0] ||
|
|
readRT->Beams.at(0)->IsocenterPosition[1] != readRT->Beams.at(2)->IsocenterPosition[1] ||
|
|
readRT->Beams.at(0)->IsocenterPosition[2] != readRT->Beams.at(2)->IsocenterPosition[2])
|
|
)
|
|
virtualIso=true;
|
|
else
|
|
virtualIso=false;
|
|
//cout << "virtual Iso: "<<virtualIso << endl;
|
|
if (callbacks.virtualIsoTested) callbacks.virtualIsoTested(virtualIso);
|
|
|
|
|
|
} else {
|
|
cout<<"Number of Beams = 0 in RTIonPlan, FAIL" <<endl;
|
|
delete m_rtIsocenter;
|
|
delete readRT;
|
|
readRT = 0;
|
|
m_rtIsocenter = 0;
|
|
}
|
|
}
|
|
|
|
cout<< "DicomScanService::load2VTK _ 2 " <<endl;
|
|
|
|
|
|
|
|
this->loadDICOM(patientInfos->CTfiles);
|
|
this->connectToVTK();
|
|
// this->changeRef(GOTSREF);
|
|
/* use DCM as default */
|
|
this->changeRef(DCMREF);
|
|
//trueOffset_rot_prev=trueOffset_rot;
|
|
|
|
|
|
//this->load2VTK(patientInfos);
|
|
} else {
|
|
//DO NOTHING. THE folderisempty signal was already emitted.
|
|
}
|
|
cout<< " DicomScanService::load _ END" <<endl;
|
|
}
|
|
|
|
void DicomScanService::changeRef(int selectedRef){
|
|
|
|
switch (selectedRef){
|
|
case DCMREF:
|
|
trueOffset=origin;
|
|
break;
|
|
case RTREF:
|
|
trueOffset=origin;
|
|
if(m_patientOrientation == SUPINE) {
|
|
cout<< " ***** Patient is SUPINE" <<endl;
|
|
trueOffset[0]-= m_rtIsocenter[0];
|
|
trueOffset[1]-= m_rtIsocenter[1];
|
|
trueOffset[2]-= m_rtIsocenter[2];
|
|
} else if (m_patientOrientation == PRONE) {
|
|
|
|
cout<< " ***** Patient is PRONE" <<endl;
|
|
/* adapted from CThandler project*/
|
|
trueOffset[0] = 0.0;
|
|
trueOffset[1] = 0.0;
|
|
trueOffset[2] = 0.0;
|
|
cout<<" ***** Reset trueOffset: "<<trueOffset[0]<<" "<<trueOffset[1]<<" "<<trueOffset[2]<<endl;
|
|
|
|
trueOffset[0] += -origin[0] ;
|
|
trueOffset[1] += -origin[1];
|
|
trueOffset[2] += origin[2] ;
|
|
cout<<" ***** Correct for CT isocenter trueOffset: "<<trueOffset[0]<<" "<<trueOffset[1]<<" "<<trueOffset[2]<<endl;
|
|
|
|
trueOffset[0] += +m_rtIsocenter[0];
|
|
trueOffset[1] += +m_rtIsocenter[1];
|
|
trueOffset[2] +=- m_rtIsocenter[2];
|
|
cout<<" ***** Correct for rtIso and volume bounds trueOffset: "<<trueOffset[0]<<" "<<trueOffset[1]<<" "<<trueOffset[2]<<endl;
|
|
|
|
} else if (m_patientOrientation == NOTDEFINED) {
|
|
cout<< "!!! Patient is NOT PRONE OR SUPINE! VERY VERY CRITICAL SITUATION !!!" <<endl;
|
|
}
|
|
break;
|
|
case GOTSREF:
|
|
trueOffset[0] = 0.0;
|
|
trueOffset[1] = 0.0;
|
|
trueOffset[2] = 0.0;
|
|
break;
|
|
|
|
}
|
|
|
|
directionToWCS.SetIdentity( );
|
|
directionToWCS[0][0]=1;
|
|
directionToWCS[1][0]=0;
|
|
directionToWCS[2][0]=0;
|
|
directionToWCS[0][1]=0;
|
|
directionToWCS[1][1]=1;
|
|
directionToWCS[2][1]=0;
|
|
directionToWCS[0][2]=0;
|
|
directionToWCS[1][2]=0;
|
|
directionToWCS[2][2]=1;
|
|
|
|
imageDir *= directionToWCS;
|
|
myImageType::PointType trueOffset_rot=trueOffset;
|
|
|
|
trueOffset_rot[0]= directionToWCS[0][0]* trueOffset[0]+directionToWCS[0][1]* trueOffset[1] + directionToWCS[0][2]* trueOffset[2];
|
|
trueOffset_rot[1]= directionToWCS[1][0]* trueOffset[0]+directionToWCS[1][1]* trueOffset[1] + directionToWCS[1][2]* trueOffset[2];
|
|
trueOffset_rot[2]= directionToWCS[2][0]* trueOffset[0]+directionToWCS[2][1]* trueOffset[1] + directionToWCS[2][2]* trueOffset[2];
|
|
|
|
/*vedi se è giusto ma prob lo è */
|
|
myImage->SetDirection( /*imageDir*/directionToWCS );
|
|
myImage->SetOrigin( trueOffset_rot );
|
|
myImage->Update();
|
|
|
|
in->SetInput(myImage);
|
|
this->connectToVTK();
|
|
this->actualizeOut();
|
|
|
|
/*calculate deltas for marker representation update*/
|
|
if(initialized){
|
|
if (callbacks.referenceChange) callbacks.referenceChange(
|
|
trueOffset_rot_prev[0]-trueOffset_rot[0],
|
|
trueOffset_rot_prev[1]-trueOffset_rot[1],
|
|
trueOffset_rot_prev[2]-trueOffset_rot[2]);
|
|
trueOffset_rot_prev=trueOffset_rot;
|
|
} else {
|
|
trueOffset_rot_prev=trueOffset_rot;
|
|
initialized=true;
|
|
}
|
|
|
|
}
|
|
|
|
void DicomScanService::loadDICOM(std::vector<std::string> CTfilenames){
|
|
|
|
myImage = myImageType::New();
|
|
rDICOM = itk::ImageSeriesReader<myImageType>::New();
|
|
iGDCMimage = itk::GDCMImageIO::New();
|
|
myDICOMseries = itk::GDCMSeriesFileNames::New();
|
|
|
|
rDICOM->SetImageIO(iGDCMimage);
|
|
rDICOM->SetFileNames(CTfilenames);
|
|
// rDICOM->SetReverseOrder(true);
|
|
try{
|
|
rDICOM->Update();
|
|
}
|
|
catch (itk::ExceptionObject &ex){
|
|
std::cout << ex << std::endl;
|
|
return; // error!
|
|
}
|
|
|
|
myImage=rDICOM->GetOutput();
|
|
imageDir = myImage->GetDirection( );
|
|
origin = myImage->GetOrigin( );
|
|
sizeOfImage = myImage->GetLargestPossibleRegion().GetSize();
|
|
|
|
}
|
|
|
|
void DicomScanService::connectToVTK(){
|
|
|
|
|
|
out = vtkSmartPointer<vtkImageImport>::New();
|
|
|
|
in = itk::VTKImageExport <myImageType>::New();
|
|
in->SetInput(myImage);
|
|
|
|
out->SetUpdateInformationCallback(in->GetUpdateInformationCallback());
|
|
out->SetPipelineModifiedCallback(in->GetPipelineModifiedCallback());
|
|
out->SetWholeExtentCallback(in->GetWholeExtentCallback());
|
|
out->SetSpacingCallback(in->GetSpacingCallback());
|
|
out->SetOriginCallback(in->GetOriginCallback());
|
|
out->SetScalarTypeCallback(in->GetScalarTypeCallback());
|
|
out->SetNumberOfComponentsCallback(in->GetNumberOfComponentsCallback());
|
|
out->SetPropagateUpdateExtentCallback(in->GetPropagateUpdateExtentCallback());
|
|
out->SetUpdateDataCallback(in->GetUpdateDataCallback());
|
|
out->SetDataExtentCallback(in->GetDataExtentCallback());
|
|
out->SetBufferPointerCallback(in->GetBufferPointerCallback());
|
|
out->SetCallbackUserData(in->GetCallbackUserData());
|
|
|
|
}
|
|
|
|
void DicomScanService::actualizeOut(){
|
|
|
|
//in->Update();
|
|
out->Update();
|
|
//vol3D = vtkSmartPointer <vtkImageData>::New();
|
|
//vol3D->DeepCopy(out->GetOutput());
|
|
//vol3D->Update();
|
|
vol3D = out->GetOutput();
|
|
cout<<vol3D->GetSpacing()[0] <<" "<<vol3D->GetSpacing()[1] <<" "<<vol3D->GetSpacing()[2] <<endl;
|
|
cout<<"fatto update" <<endl;
|
|
if (callbacks.loadEnd) callbacks.loadEnd(vol3D);
|
|
}
|
|
|
|
|
|
void DicomScanService::parse(QString p_loadDir){
|
|
loadDir=p_loadDir;
|
|
|
|
std::cout<< " ______________________________ " <<endl;
|
|
std::cout<< " __ DicomScanService::load __ " <<endl;
|
|
|
|
int result= NOERRORS;
|
|
gdcm::Reader* fileReader;
|
|
gdcm::MediaStorage msStructRTStruct;
|
|
gdcm::MediaStorage msStructRTIonPlan;
|
|
gdcm::Directory d;
|
|
gdcm::IPPSorter s;
|
|
std::cout<< " __ wrkDirParser::exec_parse __ patientInfos->clearInfo() " <<endl;
|
|
patientInfos->clearInfo();
|
|
|
|
std::cout<<"parsing dir: "<<p_loadDir.toUtf8().constData()<<std::endl;
|
|
|
|
if( gdcm::System::FileIsDirectory( p_loadDir.toUtf8().constData() ) )
|
|
{
|
|
d.Load(p_loadDir.toUtf8().constData(), false);
|
|
gdcm::Directory::FilenamesType const &files = d.GetFilenames();
|
|
for( gdcm::Directory::FilenamesType::const_iterator it = files.begin(); it != files.end(); ++it )
|
|
{
|
|
if(QFileInfo (it->c_str()).fileName().split(".").last() != QString("raw") )
|
|
patientInfos->filenames.push_back( it->c_str() );
|
|
}
|
|
patientInfos->filenames.size() == 0 ? result = PARSER_FOLDER_EMPTY : result = NOERRORS;
|
|
} else {
|
|
result=PARSER_FOLDER_NOTEXISTING;
|
|
};
|
|
|
|
cout << " patientInfos->filenames.size() "<<endl;
|
|
cout<< patientInfos->filenames.size() <<endl;
|
|
|
|
if(result == NOERRORS)
|
|
for(int i=(patientInfos->filenames.size()-1);i>-1;i--)
|
|
{
|
|
//cout << gCheckDICOMModalityToInt(patientInfos->filenames.at(i).c_str()) <<endl;
|
|
fileReader = new gdcm::Reader;
|
|
fileReader->SetFileName (patientInfos->filenames.at(i).c_str());
|
|
|
|
if( !fileReader->Read() ) {
|
|
cout<< "Error reading file: "<< patientInfos->filenames.at(i).data() <<endl;
|
|
delete fileReader;
|
|
patientInfos->filenames.erase(patientInfos->filenames.begin()+i);
|
|
continue;
|
|
}
|
|
|
|
//msStructRTIonPlan.SetFromFile( fileReader->GetFile() );
|
|
//if( msStructRTIonPlan == gdcm::MediaStorage::RTIonPlanStorage )
|
|
if( gCheckDICOMModalityToInt(patientInfos->filenames.at(i).c_str()) == RTPLAN )
|
|
{
|
|
if(!patientInfos->rtIonPlanPath.isEmpty()) {
|
|
// result=PARSER_RTPLAN_NOTUNIQUE;
|
|
continue;
|
|
} else {
|
|
const gdcm::File &file = fileReader->GetFile();
|
|
const gdcm::DataSet &ds = file.GetDataSet();
|
|
//PATIENT NAME
|
|
strcpy( patientInfos->PatientName,gGetStringValueFromTag( gdcm::Tag(0x0010,0x0010), ds));
|
|
// // // PATIENT ID For ex: DICOM (0010,0020) = 1933197
|
|
strcpy( patientInfos->PatientID , gGetStringValueFromTag( gdcm::Tag(0x0010,0x0020), ds));
|
|
// // // PATIENT AGE For ex: DICOM (0010,1010) = 031Y
|
|
strcpy( patientInfos->PatientAge , gGetStringValueFromTag( gdcm::Tag(0x0010,0x1010), ds)) ;
|
|
// // // PATIENT SEX For ex: DICOM (0010,0040) = M
|
|
strcpy( patientInfos->PatientSex, gGetStringValueFromTag( gdcm::Tag(0x0010,0x0040), ds) );
|
|
// // // PATIENT BIRTHDATE For ex: DICOM (0010,0030) = 19680427
|
|
strcpy( patientInfos->PatientBirthDate, gGetStringValueFromTag( gdcm::Tag(0x0010,0x0030), ds) );
|
|
// // // SERIES NUMBER For ex: DICOM (0020,0011) = 902
|
|
strcpy( patientInfos->SeriesNumber, gGetStringValueFromTag( gdcm::Tag(0x0020,0x0011), ds) );
|
|
// // // SERIES DESCRIPTION For ex: DICOM (0008,103e) = SCOUT
|
|
strcpy( patientInfos->SeriesDescription , gGetStringValueFromTag( gdcm::Tag(0x0008,0x103e), ds) );
|
|
// // // STUDY ID For ex: DICOM (0020,0010) = 37481
|
|
strcpy( patientInfos->StudyID, gGetStringValueFromTag( gdcm::Tag(0x0020,0x0010), ds) );
|
|
// // // STUDY DESCRIPTION For ex: DICOM (0008,1030) = BRAIN/C-SP/FACIAL
|
|
strcpy( patientInfos->StudyDescription, gGetStringValueFromTag( gdcm::Tag(0x0008,0x1030), ds) );
|
|
|
|
const gdcm::DataElement &gSetupSequence=ds.GetDataElement(gdcm::Tag(0x300a,0x0180));
|
|
//LOOK FOR PATIENT ORIENTATION
|
|
gdcm::SmartPointer<gdcm::SequenceOfItems> sqiPS = gSetupSequence.GetValueAsSQ();
|
|
const gdcm::DataSet& gPatSetupNest = sqiPS->GetItem(1).GetNestedDataSet();
|
|
//SET PATIENT ORIENTATION STRING
|
|
strcpy(patientInfos->PatientOrientation, gGetStringValueFromTag(gdcm::Tag(0x0018, 0x5100),gPatSetupNest));
|
|
|
|
|
|
|
|
patientInfos->rtIonPlanPath=QString(patientInfos->filenames.at(i).c_str());
|
|
cout<< "RTPlan import success" <<endl;
|
|
result=NOERRORS;
|
|
patientInfos->filenames.erase(patientInfos->filenames.begin()+i);
|
|
delete fileReader;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// msStructRTStruct.SetFromFile( fileReader->GetFile() );
|
|
// if( msStructRTStruct == gdcm::MediaStorage::RTStructureSetStorage ) {
|
|
if( gCheckDICOMModalityToInt(patientInfos->filenames.at(i).c_str()) == RTSTRUCT ){
|
|
if(!patientInfos->rtStructurePath.isEmpty()) {
|
|
patientInfos->rtStructurePath.clear();
|
|
// result=PARSER_RTSTRUCT_NOTUNIQUE;
|
|
continue;
|
|
} else {
|
|
patientInfos->rtStructurePath=QString(patientInfos->filenames.at(i).c_str());
|
|
cout<< "RTStruct import success" <<endl;
|
|
result=NOERRORS;
|
|
patientInfos->filenames.erase(patientInfos->filenames.begin()+i);
|
|
delete fileReader;
|
|
continue;
|
|
}
|
|
}
|
|
delete fileReader;
|
|
}
|
|
|
|
|
|
//OK
|
|
//if(result == NOERRORS && patientInfos->rtIonPlanPath.isEmpty() )
|
|
// result= PARSER_RTPLAN_MISSING;
|
|
//if(result == NOERRORS && patientInfos->rtStructurePath.isEmpty())
|
|
// result=PARSER_RTSTRUCT_MISSING;
|
|
|
|
s.SetComputeZSpacing( true );
|
|
s.SetZSpacingTolerance( 1e-2 );
|
|
|
|
if(result==NOERRORS)
|
|
if(!s.Sort( patientInfos->filenames ) ) {
|
|
result=PARSER_CT_FAILED_SORTING;
|
|
} else {
|
|
s.GetFilenames().size() == 0 ? result = PARSER_CT_FILES_MISSING : result=NOERRORS;
|
|
}
|
|
|
|
if(result == NOERRORS){
|
|
patientInfos->CTfiles=s.GetFilenames ();
|
|
//cout<< "CT files sorting succeeded" <<endl;
|
|
if (callbacks.statusInfo) callbacks.statusInfo("CT files sorting succeeded");
|
|
} else {
|
|
|
|
switch(result){
|
|
|
|
case PARSER_FOLDER_EMPTY:
|
|
cout<< "Empty folder. Parse failed" <<endl;
|
|
if (callbacks.folderIsEmpty) callbacks.folderIsEmpty();
|
|
break;
|
|
|
|
case PARSER_FOLDER_NOTEXISTING:
|
|
if (callbacks.statusInfo) callbacks.statusInfo("NonExisting folder. Parse failed");
|
|
break;
|
|
|
|
case PARSER_RTPLAN_NOTUNIQUE:
|
|
if (callbacks.statusInfo) callbacks.statusInfo("RtIonPlan not unique. Parse failed");
|
|
break;
|
|
|
|
case PARSER_RTSTRUCT_NOTUNIQUE:
|
|
if (callbacks.statusInfo) callbacks.statusInfo("RtStructure not unique. Parse failed");
|
|
break;
|
|
|
|
case PARSER_CT_FAILED_SORTING:
|
|
if (callbacks.statusInfo) callbacks.statusInfo("Failed to sort CT files");
|
|
if (callbacks.folderIsEmpty) callbacks.folderIsEmpty();
|
|
break;
|
|
|
|
case PARSER_CT_FILES_MISSING:
|
|
if (callbacks.statusInfo) callbacks.statusInfo("CT file Missing");
|
|
if (callbacks.folderIsEmpty) callbacks.folderIsEmpty();
|
|
break;
|
|
|
|
case PARSER_RTPLAN_MISSING:
|
|
if (callbacks.statusInfo) callbacks.statusInfo("RtIonPlan missing");
|
|
break;
|
|
|
|
case PARSER_RTSTRUCT_MISSING:
|
|
if (callbacks.statusInfo) callbacks.statusInfo("rtStructure missing");
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (callbacks.parse_result) callbacks.parse_result(result,patientInfos);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DicomScanService::~DicomScanService(){
|
|
delete patientInfos;
|
|
patientInfos=nullptr;
|
|
if (m_rtIsocenter) { delete [] m_rtIsocenter; m_rtIsocenter=nullptr; }
|
|
delete readRT;
|
|
readRT=nullptr;
|
|
}
|