From d13d4750be5a4c4bb97e91c6a14fcbdcf92334fd Mon Sep 17 00:00:00 2001 From: jpr Date: Mon, 18 Jun 2007 12:02:54 +0000 Subject: [PATCH] First (dirty) version of a Dicom RT checker Don't use right now! --- Example/exDicomRTStructSetFile.cxx | 360 +++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100755 Example/exDicomRTStructSetFile.cxx diff --git a/Example/exDicomRTStructSetFile.cxx b/Example/exDicomRTStructSetFile.cxx new file mode 100755 index 00000000..edd10d7d --- /dev/null +++ b/Example/exDicomRTStructSetFile.cxx @@ -0,0 +1,360 @@ + + /*========================================================================= + + Program: gdcm + Module: $RCSfile: exDicomRTStructSetFile.cxx,v $ + Language: C++ + Date: $Date: 2007/06/18 12:02:54 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + /* ================================================= + * freely inspired from : clitkDicomRTIOCommon.cxx + * written by : Laurent ZAGNI + * on : 18 August 2006 + * + =================================================*/ + + +#include "gdcmFile.h" +// ---------- +//#include "gdcmValEntry.h" +#include "gdcmDataEntry.h" +// ---------- +#include "gdcmSeqEntry.h" +#include "gdcmSQItem.h" +#include "gdcmDocEntrySet.h" +#include "gdcmSerieHelper.h" +#include "gdcmDirList.h" +#include "gdcmUtil.h" + +// ---------- +#define GetEntryValue(g,e) GetEntryString(g,e) +#define GetValEntry(g,e) GetDataEntry(g,e) +#define GetValue() GetString() +#define ValEntry DataEntry +#define InsertValEntry(a,b,c) InsertEntryString(a,b,c) // warning mind the VR! +// ---------- + +#define itkGenericExceptionMacro(a) std::cout<<"===========================Exception "a<GetFirstSQItem(); + gdcm::ValEntry* valEntry; + while (curItem != NULL) { + valEntry = curItem->GetValEntry(group,elem); + std::istringstream(valEntry->GetValue())>>foundValue; + if (foundValue == value) { + return curItem; + } + curItem = seqEntry->GetNextSQItem(); + } + if (writeItem == true) { + unsigned int newItemNumber = seqEntry->GetNumberOfSQItems (); +// ---------- + //gdcm::SQItem* newItem = new gdcm::SQItem(seqEntry->GetDepthLevel()+1); + gdcm::SQItem* newItem = gdcm::SQItem::New(seqEntry->GetDepthLevel()+1); +// ---------- + seqEntry->AddSQItem(newItem,(int)newItemNumber); + newItem->InsertValEntry(strValue, group, elem); /// \TODO : si VR absent, le chercher dans le dict! + return newItem; + } else { + return NULL; + } + } + + + /* ================================================= + * freely inspired from : clitkDicomRTIOCommon.cxx + * written by : Laurent ZAGNI + * on : 18 August 2006 + * + =================================================*/ + // Test if a file list is a valid CT serie + + bool TestDicomCTSerie(const gdcm::FileList serie) { + + if (serie.size() < 2) { + itkGenericExceptionMacro(<<"Serie must contain at least 2 files !"); + } + + float firstSliceImagePosition[3]; + float currentSliceImagePosition[3]; + + gdcm::FileList::const_iterator first = serie.begin(); + gdcm::FileList::const_iterator it = first ++; + + bool res = (*first)->GetImageOrientationPatient(firstSliceImagePosition); + if (!res) { + itkGenericExceptionMacro(<<"No ImagePositionPatient found;"); + } + + while (it != serie.end()) { + if (!gdcm::Util::DicomStringEqual((*it)->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.2")) { + itkGenericExceptionMacro(); + //CT Dicom slices must have a SOP Class UID [0008|0016] = [1.2.840.10008.5.1.4.1.1.2] ==> [CT Image Storage] + } + + if (!gdcm::Util::DicomStringEqual((*it)->GetEntryValue(0x0008,0x0060),"CT")) { + itkGenericExceptionMacro(); + //CT Dicom slices must have a Modality [0008|0060] = [CT] + } + + if (!gdcm::Util::DicomStringEqual((*it)->GetEntryValue(0x0020,0x0037),"1.0000\\0.0000\\0.0000\\0.0000\\1.0000\\0.0000")) { + itkGenericExceptionMacro("CT Dicom slices must an Image Orientation [0020|0037]" + <<" = [1.0000\0.0000\0.0000\0.0000\1.0000\0.0000]"); + } + + res =(*it)->GetImageOrientationPatient(currentSliceImagePosition); + if (!res) { + itkGenericExceptionMacro(<<"No ImagePositionPatient found;"); + } + if ((firstSliceImagePosition[0] != currentSliceImagePosition[0])||(firstSliceImagePosition[1] != currentSliceImagePosition[1])){ + itkGenericExceptionMacro("All CT Dicom slices must have same image position on x and y [0020|0032]"); + } + + if ((*it)->GetEntryValue(0x0028,0x0030) != (*first)->GetEntryValue(0x0028,0x0030).c_str()) { + itkGenericExceptionMacro("All CT Dicom slices must have same Pixel Spacing [0028|0030]"); + } + + if ((*it)->GetEntryValue(0x0028,0x0010) != (*first)->GetEntryValue(0x0028,0x0010).c_str()) { + itkGenericExceptionMacro("All CT Dicom slices must have same Rows number [0028|0010]"); + } + + if ((*it)->GetEntryValue(0x0028,0x0011) != (*first)->GetEntryValue(0x0028,0x0011).c_str()) { + itkGenericExceptionMacro("All CT Dicom slices must have same Columns number [0028|0011]"); + } + + if ((*it)->GetEntryValue(0x0018,0x0050) != (*first)->GetEntryValue(0x0018,0x0050).c_str()) { + itkGenericExceptionMacro("All CT Dicom slices must have same slice thickness [0018|0050]"); + } + it++; + } + //it = serie.begin(); + // while (it != serie.end()) { + // fileName = (*it)->GetFileName(); + // std::cout << fileName << std::endl; + // it++; + // } + } + + + + +// ----------------------------------------------------------------------------------------------------------------- + /* ================================================= + * freely inspired from : clitkDicomRTIOCommon.cxx + * written by : Laurent ZAGNI + * on : 18 August 2006 + * + =================================================*/ + + // Test if a file is a valid Dicom-RT Structure-Set file (readable by us) + bool TestDicomRTStructSetFile(gdcm::File* file) { +// ---------- + //gdcm::ValEntry* valEntry; + gdcm::DataEntry* valEntry; +// ---------- + + std::string exception0 = "Not a [RT Structure Set Storage]"; + std::string exception1 = "2 or more different 'Roi Referenced Frame UID'!"; + std::string exception2 = "No 'Series Instance UID'!"; + std::string exception3 = "Modality not= RTSTRUCT"; + + //Verify if the file is a RT-Structure-Set dicom file + if (!gdcm::Util::DicomStringEqual(file->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.481.3")) { //SOP clas UID + itkGenericExceptionMacro(< [RT Structure Set Storage] ! + } + + if (!gdcm::Util::DicomStringEqual(file->GetEntryValue(0x0008,0x0060),"RTSTRUCT")) { //SOP clas UID + itkGenericExceptionMacro(<GetSeqEntry(0x3006,0x0020); //Structure Set ROI sequence + if (seqEntry->GetNumberOfSQItems() > 1) { + currentItem = seqEntry->GetFirstSQItem(); + valEntry = currentItem->GetValEntry(0x3006,0x0024); //Roi Frame of Reference UID + currentFrameRefUID = valEntry->GetValue(); + currentItem = seqEntry->GetNextSQItem(); + while (currentItem != NULL) { + valEntry = currentItem->GetValEntry(0x3006,0x0024); //Roi Frame of Reference UID + if (valEntry->GetValue() != currentFrameRefUID) { + // std::cout<<"..ref UID"<GetValue().c_str()<GetNextSQItem(); + } + } + + seqEntry = file->GetSeqEntry(0x3006,0x0010); //Referenced Frame of Reference Sequence + currentItem = seqEntry->GetFirstSQItem(); + while (currentItem != NULL) { + valEntry = currentItem->GetValEntry(0x0020,0x0052); //Frame of Reference UID + if (valEntry->GetValue() == currentFrameRefUID) { //search for the ROI Frame of Reference UID + break; + }else { + currentItem = seqEntry->GetNextSQItem(); + } + } + if (currentItem == NULL) { + itkGenericExceptionMacro(<GetSeqEntry(0x3006,0x0012); //Referenced Study sequence + if (seqEntry2->GetNumberOfSQItems() < 1) { + itkGenericExceptionMacro(<GetValEntry(0x0020,0x0010); //study ID + if ((valEntry == 0) || (valEntry->GetValue() == "")) { //(type 1 : mandatory attribute) + itkGenericExceptionMacro("RT-Structure-Set file must contain Study ID [0020|0010] !"); + } + + valEntry = file->GetValEntry(0x3006,0x002); //structure set label + if ((valEntry == 0) || (valEntry->GetValue() == "")) { //(type 1 : mandatory attribute) + itkGenericExceptionMacro("RT-Structure-Set file must contain Structure Set Label [0006|0002] !"); + } + + seqEntry = file->GetSeqEntry(0x3006,0x0020); //Structure Set ROI sequence + if (seqEntry != 0) { + currentItem = seqEntry->GetFirstSQItem(); + while (currentItem != NULL) { + valEntry = currentItem->GetValEntry(0x3006,0x0022); //Roi number + if ((valEntry == 0) || (valEntry->GetValue() == "")) { //(type 1 : mandatory attribute) + itkGenericExceptionMacro("All ROI in Structure Set Roi Sequence must contain Roi Number [3006|0022] !"); + } + currentItem = seqEntry->GetNextSQItem(); + } + } + + seqEntry = file->GetSeqEntry(0x3006,0x0080); //ROI Observation sequence + if (seqEntry == 0) { //(type 1 : mandatory attribute) + itkGenericExceptionMacro("RT-Structure-Set file must contain ROI Observations Sequence [3006|0080] !"); + } + + seqEntry = file->GetSeqEntry(0x3006,0x0039); //ROI Contour sequence + if (seqEntry == 0) { //(type 1 : mandatory attribute) + itkGenericExceptionMacro("RT-Structure-Set file must contain ROI Contour Sequence [3006|0039] !"); + } + std::cout<<"..."<GetFileName()<<" is a valid DICOM RT-Structure-Set file"<ArgMgrDefined("usage") || argc == 1) + { + am->ArgMgrUsage(usage); // Display 'usage' + delete am; + return 0; + } + + if (am->ArgMgrDefined("debug")) + GDCM_NAME_SPACE::Debug::DebugOn(); + + bool verbose = am->ArgMgrDefined("verbose"); + + const char *fileName = am->ArgMgrGetString("filein"); + + /* if unused Param we give up */ + if ( am->ArgMgrPrintUnusedLabels() ) + { + am->ArgMgrUsage(usage); + delete am; + return 0; + } + delete am; // ------ we don't need Arguments Manager any longer ------ + +// ============================================================ +// Read the input image. +// ============================================================ + + gdcm::File *f = gdcm::File::New( ); + + //f->SetLoadMode(gdcm::LD_NOSEQ | gdcm::LD_NOSHADOW); + f->SetFileName( fileName ); + f->SetMaxSizeLoadEntry(0xffff); + bool res = f->Load(); + + if( gdcm::Debug::GetDebugFlag()) + { + std::cout << "---------------------------------------------" << std::endl; + f->Print(); + std::cout << "---------------------------------------------" << std::endl; + } + if (!res) { + std::cerr << "Sorry, " << fileName << " not a gdcm-readable " + << "DICOM / ACR File" + << std::endl; + f->Delete(); + return 1; + } + std::cout << " ... is readable " << std::endl; + + + TestDicomRTStructSetFile(f); + std::cout << " ... is readable " << std::endl; + + + + f->Delete(); +return 0; +} + -- 2.48.1