X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=vtk%2FvtkgdcmSerieViewer.cxx;h=f081e02bf76433b72dd9fa739cc383a5dcd59d67;hb=f2dd700472606cce1b889e6527ca7ed68a6bbde6;hp=5931f66e6901d565428f52d37f56a558253113d5;hpb=ac954771575ed03dde66e0ebb7349e32c6312379;p=gdcm.git diff --git a/vtk/vtkgdcmSerieViewer.cxx b/vtk/vtkgdcmSerieViewer.cxx index 5931f66e..f081e02b 100644 --- a/vtk/vtkgdcmSerieViewer.cxx +++ b/vtk/vtkgdcmSerieViewer.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: vtkgdcmSerieViewer.cxx,v $ Language: C++ - Date: $Date: 2005/07/19 15:28:54 $ - Version: $Revision: 1.2 $ + Date: $Date: 2007/06/21 14:47:16 $ + Version: $Revision: 1.18 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -15,16 +15,17 @@ PURPOSE. See the above copyright notices for more information. =========================================================================*/ -// This example illustrates how the vtkGdcmReader vtk class can be -// used in order to: -// * produce a simple (vtk based) Dicom image STACK VIEWER. -// * dump the stack considered as a volume in a vtkStructuredPoints -// vtk file: the vtk gdcm wrappers can be seen as a simple way to convert -// a stack of Dicom images into a native vtk volume. -// +// This example illustrates how the vtkGdcmReader vtk class can +// use the result of GDCM_NAME_SPACE::SerieHelper constructor and check +// the various Setters : +// SerieHelper::SetOrderToReverse, +// SerieHelper::SetUserLessThanFunction +// SerieHelper::SetLoadMode +// vtkGdcmReader::SetUserFunction +// vtkGdcmReader::SetCoherentFileList // Usage: -// * the filenames of the Dicom images constituting the stack should be -// given as command line arguments, +// * the Directory name that contains the Dicom images constituting the stack +// should be given as command line argument (keyword : dirname=), // * you can navigate through the stack by hitting any character key, // * the produced vtk file is named "foo.vtk" (in the invocation directory). // @@ -42,10 +43,22 @@ #include "gdcmDocument.h" // for NO_SHADOWSEQ #include "gdcmSerieHelper.h" #include "gdcmDebug.h" +#include "gdcmDataEntry.h" + +#include "gdcmArgMgr.h" // for Argument Manager functions +#include // for strcmp #ifndef vtkFloatingPointType #define vtkFloatingPointType float #endif +void userSuppliedMirrorFunction (uint8_t *im, GDCM_NAME_SPACE::File *f); +void userSuppliedTopDownFunction(uint8_t *im, GDCM_NAME_SPACE::File *f); +bool userSuppliedLessThanFunction(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2); +bool userSuppliedLessThanFunction2(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2); + +int orderNb; +uint16_t *elemsToOrderOn; + //---------------------------------------------------------------------------- // Callback for the interaction class vtkgdcmObserver : public vtkCommand @@ -55,14 +68,17 @@ public: { return "vtkgdcmObserver"; } + static vtkgdcmObserver *New() { return new vtkgdcmObserver; } + vtkgdcmObserver() { this->ImageViewer = NULL; } + virtual void Execute(vtkObject *, unsigned long event, void* ) { if ( this->ImageViewer ) @@ -80,35 +96,122 @@ public: vtkImageViewer *ImageViewer; }; - int main(int argc, char *argv[]) { - if( argc < 2 ) + START_USAGE(usage) + " \n vtkgdcmSerieViewer : \n", + " Display a 'Serie' (same Serie UID) within a Directory ", + " You can navigate through the stack by hitting any character key. ", + " usage: vtkgdcmSerieViewer dirname=sourcedirectory ", + " [noshadowseq][noshadow][noseq] ", + " [reverse] [{[mirror]|[topdown]|[rotate]}] ", + " [order=] [check][debug] ", + " sourcedirectory : name of the directory holding the images ", + " if it holds more than one serie, ", + " only the first one id displayed. ", + " noshadowseq: user doesn't want to load Private Sequences ", + " noshadow : user doesn't want to load Private groups (odd number) ", + " noseq : user doesn't want to load Sequences ", + " reverse : user wants to sort the images reverse order ", + " mirror : user wants to 'mirror' the images | just some simple ", + " topdown : user wants to 'topdown' the images| examples of user ", + " rotate : NOT YET MADE (useless?) | supplied functions ", + " check : user wants to force more coherence checking ", + " order= : group1-elem1,group2-elem2,... (in hexa, no space) ", + " if we want to use them as a sort criterium ", + " Right now : ValEntries only -just an example- ", + " or ", + " order= : order=name if we want to sort on file name (why not ?) ", + " debug : user wants to run the program in 'debug mode' ", + FINISH_USAGE + + + // Initialize Arguments Manager + GDCM_NAME_SPACE::ArgMgr *am= new GDCM_NAME_SPACE::ArgMgr(argc, argv); + + if (argc == 1 || am->ArgMgrDefined("usage") ) + { + am->ArgMgrUsage(usage); // Display 'usage' + delete am; return 0; + } + + char *dirName = am->ArgMgrWantString("dirname",usage); + + int loadMode = GDCM_NAME_SPACE::LD_ALL; + if ( am->ArgMgrDefined("noshadowseq") ) + loadMode |= GDCM_NAME_SPACE::LD_NOSHADOWSEQ; + else + { + if ( am->ArgMgrDefined("noshadow") ) + loadMode |= GDCM_NAME_SPACE::LD_NOSHADOW; + if ( am->ArgMgrDefined("noseq") ) + loadMode |= GDCM_NAME_SPACE::LD_NOSEQ; + } + + int reverse = am->ArgMgrDefined("reverse"); - if( argc > 2 ) - gdcm::Debug::DebugOn(); + int mirror = am->ArgMgrDefined("mirror"); + int topdown = am->ArgMgrDefined("topdown"); + int rotate = am->ArgMgrDefined("rotate"); + + if ( mirror && topdown ) + { + std::cout << "mirror *OR* topDown !" + << std::endl; + delete am; + return 0; + } + if ( rotate ) + { + std::cout << "'rotate' undealt with -> ignored !" + << std::endl; + } + int check = am->ArgMgrDefined("check"); - vtkGdcmReader *reader = vtkGdcmReader::New(); - reader->AllowLookupTableOff(); + // This is so ugly, a cstring is NOT a char * (god damit!) + bool bname = ( strcmp(am->ArgMgrGetString("order", "not found"),"name")==0 ); + if (bname) + elemsToOrderOn = am->ArgMgrGetXInt16Enum("order", &orderNb); + + if (am->ArgMgrDefined("debug")) + GDCM_NAME_SPACE::Debug::DebugOn(); + + /* if unused Param we give up */ + if ( am->ArgMgrPrintUnusedLabels() ) + { + am->ArgMgrUsage(usage); + delete am; + return 0; + } - // ------------ to check Coherent File List as a parameter + delete am; // we don't need Argument Manager any longer - gdcm::SerieHelper *sh = new gdcm::SerieHelper(); - sh->SetLoadMode(NO_SHADOWSEQ); - sh->SetDirectory( argv[1], true); + // ----------------------- End Arguments Manager ---------------------- + + GDCM_NAME_SPACE::SerieHelper *sh = GDCM_NAME_SPACE::SerieHelper::New(); + sh->SetLoadMode(loadMode); + if (reverse) + sh->SetSortOrderToReverse(); + sh->SetDirectory( dirName, true); // Just to see int nbFiles; - // For all the Coherent Files lists of the gdcm::Serie - gdcm::FileList *l = sh->GetFirstCoherentFileList(); + // For all the 'Single Serie UID' FileSets of the GDCM_NAME_SPACE::Serie + GDCM_NAME_SPACE::FileList *l = sh->GetFirstSingleSerieUIDFileSet(); if (l == 0 ) { - std::cout << "Oops! No CoherentFileList found ?!?" << std::endl; + std::cout << "Oops! No 'Single Serie UID' FileSet found ?!?" << std::endl; return 0; } + + if (bname) + sh->SetUserLessThanFunction(userSuppliedLessThanFunction2); + else if (orderNb != 0) + sh->SetUserLessThanFunction(userSuppliedLessThanFunction); + while (l) { nbFiles = l->size() ; @@ -120,11 +223,30 @@ int main(int argc, char *argv[]) } else { - std::cout << "Oops! Empty CoherentFileList found ?!?" << std::endl; + std::cout << "Oops! Empty 'Single Serie UID' FileSet found ?!?" + << std::endl; + } + l = sh->GetNextSingleSerieUIDFileSet(); + } + + if (check) + { + if ( !sh->IsCoherent(l) ) // just be sure (?) + { + std::cout << "Files are not coherent. Stop everything " << std::endl; + sh->Delete(); + return 0; } - l = sh->GetNextCoherentFileList(); } + vtkGdcmReader *reader = vtkGdcmReader::New(); + reader->AllowLookupTableOff(); + + if (mirror) + reader->SetUserFunction (userSuppliedMirrorFunction); + else if (topdown) + reader->SetUserFunction (userSuppliedTopDownFunction); + // Only the first FileList is dealt with (just an example) // (The files will not be parsed twice by the reader) @@ -132,10 +254,9 @@ int main(int argc, char *argv[]) reader->SetCoherentFileList(l); //--------------------------------------------------------- - -// TODO : allow user to choose Load Mode - - // reader->SetLoadMode(NO_SHADOWSEQ); + // because we passed a Coherent File List from a SerieHelper, + // setting LoadMode is useless in this case + // reader->SetLoadMode(NO_SHADOWSEQ); reader->Update(); //print debug info: @@ -193,3 +314,189 @@ int main(int argc, char *argv[]) return 0; } + + +// -------------------------------------------------------- +// This is just a *very* simple example of user supplied function +// to mirror (why not ?) the image +// It's *not* part of gdcm. +// -------------------------------------------------------- + +#define UF(ty) \ + int i, j; \ + ty *imj; \ + ty tamp; \ + for (j=0;jGetZSize() != 1) + { + std::cout << "mirror : Multiframe images not yet dealt with" << std::endl; + return; + } + + if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24) + { + std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl; + return; + } + int nx = f->GetXSize(); + int ny = f->GetYSize(); + + std::string pixelType = f->GetPixelType(); + if ( pixelType == "8U" || pixelType == "8S" ) + { + UF(uint8_t) + return; + } + if ( pixelType == "16U" || pixelType == "16S") + { + UF(uint16_t) + return; + } + std::cout << "mirror : Pixel Size (!=8, !=16) not yet dealt with" + << std::endl; + return; +} + + +// -------------------------------------------------------- +// This is just a *very* simple example of user supplied function +// to topdown (why not ?) the image +// It's *not* part of gdcm. +// -------------------------------------------------------- + +#define UF2(ty) \ + int i, j; \ + ty *imj, *imJ; \ + ty tamp; \ + for (j=0;jGetZSize() != 1) + { + std::cout << "mirror : Multiframe images not yet dealt with" << std::endl; + return; + } + + if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24) + { + std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl; + return; + } + int nx = f->GetXSize(); + int ny = f->GetYSize(); + + std::string pixelType = f->GetPixelType(); + if ( pixelType == "8U" || pixelType == "8S" ) + { + UF2(uint8_t) + return; + } + if ( pixelType == "16U" || pixelType == "16S") + { + UF2(uint16_t) + return; + } + std::cout << "topdown : Pixel Size (!=8, !=16) not yet dealt with" + << std::endl; + return; +} + +// -------------------------------------------------------- +// This is just a *very* simple example of user supplied 'LessThan' function +// It's *not* part of gdcm. +// +// Note : orderNb and elemsToOrderOn are here global variables. +// Within a 'normal' function they would't be any orderNb and elemsToOrderOn var +// User *knows* on what field(s) he wants to compare; +// He just writes a decent function. +// Here, we want to get info from the command line Argument Manager. +// +// Warning : it's up to 'vtkgdcmSerieViewer' user to find a suitable data set ! +// -------------------------------------------------------- + + +bool userSuppliedLessThanFunction(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2) +{ + // for *this* user supplied function, I supposed only ValEntries are checked. +// + std::string s1, s2; + GDCM_NAME_SPACE::DataEntry *e1,*e2; + for (int ri=0; riGetDataEntry( elemsToOrderOn[2*ri], + elemsToOrderOn[2*ri+1]); + + e2= f2->GetDataEntry( elemsToOrderOn[2*ri], + elemsToOrderOn[2*ri+1]); + if(!e2 || !e2) + { + std::cout << std::hex << elemsToOrderOn[2*ri] << "|" + << elemsToOrderOn[2*ri+1] + << " not found" << std::endl; + continue; + } + s1 = e1->GetString(); + s2 = e2->GetString(); + std::cout << "[" << s1 << "] vs [" << s2 << "]" << std::endl; + if ( s1 < s2 ) + return true; + else if (s1 == s2 ) + continue; + else + return false; + } + return false; // all fields equal +} + +// -------------------------------------------------------- +// This is just an other *very* simple example of user supplied 'LessThan' +// function +// It's *not* part of gdcm. +// +// Warning : it's up to 'vtkgdcmSerieViewer' user to find a suitable data set ! +// -------------------------------------------------------- + +bool userSuppliedLessThanFunction2(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2) +{ + std::cout << "[" << f1->GetFileName() << "] vs [" + << f2->GetFileName() << "]" << std::endl; + return f1->GetFileName() < f2->GetFileName(); +}