1 /*=========================================================================
4 Module: $RCSfile: vtkgdcmSerieViewer.cxx,v $
6 Date: $Date: 2007/06/19 13:09:45 $
7 Version: $Revision: 1.17 $
9 Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10 l'Image). All rights reserved. See Doc/License.txt or
11 http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
13 This software is distributed WITHOUT ANY WARRANTY; without even
14 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 PURPOSE. See the above copyright notices for more information.
17 =========================================================================*/
18 // This example illustrates how the vtkGdcmReader vtk class can
19 // use the result of gdcm::SerieHelper constructor and check
20 // the various Setters :
21 // SerieHelper::SetOrderToReverse,
22 // SerieHelper::SetUserLessThanFunction
23 // SerieHelper::SetLoadMode
24 // vtkGdcmReader::SetUserFunction
25 // vtkGdcmReader::SetCoherentFileList
27 // * the Directory name that contains the Dicom images constituting the stack
28 // should be given as command line argument (keyword : dirname=),
29 // * you can navigate through the stack by hitting any character key,
30 // * the produced vtk file is named "foo.vtk" (in the invocation directory).
32 //----------------------------------------------------------------------------
33 #include <vtkRenderWindowInteractor.h>
34 #include <vtkImageViewer.h>
35 #include <vtkStructuredPoints.h>
36 #include <vtkStructuredPointsWriter.h>
37 #include <vtkCommand.h>
38 #include <vtkRenderer.h>
39 #include <vtkImageMapToColors.h>
40 #include <vtkLookupTable.h>
42 #include "vtkGdcmReader.h"
43 #include "gdcmDocument.h" // for NO_SHADOWSEQ
44 #include "gdcmSerieHelper.h"
45 #include "gdcmDebug.h"
46 #include "gdcmDataEntry.h"
48 #include "gdcmArgMgr.h" // for Argument Manager functions
49 #include <string.h> // for strcmp
50 #ifndef vtkFloatingPointType
51 #define vtkFloatingPointType float
54 void userSuppliedMirrorFunction (uint8_t *im, GDCM_NAME_SPACE::File *f);
55 void userSuppliedTopDownFunction(uint8_t *im, GDCM_NAME_SPACE::File *f);
56 bool userSuppliedLessThanFunction(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2);
57 bool userSuppliedLessThanFunction2(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2);
60 uint16_t *elemsToOrderOn;
62 //----------------------------------------------------------------------------
63 // Callback for the interaction
64 class vtkgdcmObserver : public vtkCommand
67 virtual char const *GetClassName() const
69 return "vtkgdcmObserver";
72 static vtkgdcmObserver *New()
74 return new vtkgdcmObserver;
79 this->ImageViewer = NULL;
82 virtual void Execute(vtkObject *, unsigned long event, void* )
84 if ( this->ImageViewer )
86 if ( event == vtkCommand::CharEvent )
88 int max = ImageViewer->GetWholeZMax();
89 int slice = (ImageViewer->GetZSlice() + 1 ) % ++max;
90 ImageViewer->SetZSlice( slice );
91 ImageViewer->GetRenderer()->ResetCameraClippingRange();
92 ImageViewer->Render();
96 vtkImageViewer *ImageViewer;
99 int main(int argc, char *argv[])
102 " \n vtkgdcmSerieViewer : \n",
103 " Display a 'Serie' (same Serie UID) within a Directory ",
104 " You can navigate through the stack by hitting any character key. ",
105 " usage: vtkgdcmSerieViewer dirname=sourcedirectory ",
106 " [noshadowseq][noshadow][noseq] ",
107 " [reverse] [{[mirror]|[topdown]|[rotate]}] ",
108 " [order=] [check][debug] ",
109 " sourcedirectory : name of the directory holding the images ",
110 " if it holds more than one serie, ",
111 " only the first one id displayed. ",
112 " noshadowseq: user doesn't want to load Private Sequences ",
113 " noshadow : user doesn't want to load Private groups (odd number) ",
114 " noseq : user doesn't want to load Sequences ",
115 " reverse : user wants to sort the images reverse order ",
116 " mirror : user wants to 'mirror' the images | just some simple ",
117 " topdown : user wants to 'topdown' the images| examples of user ",
118 " rotate : NOT YET MADE (useless?) | supplied functions ",
119 " check : user wants to force more coherence checking ",
120 " order= : group1-elem1,group2-elem2,... (in hexa, no space) ",
121 " if we want to use them as a sort criterium ",
122 " Right now : ValEntries only -just an example- ",
124 " order= : order=name if we want to sort on file name (why not ?) ",
125 " debug : user wants to run the program in 'debug mode' ",
129 // Initialize Arguments Manager
130 GDCM_NAME_SPACE::ArgMgr *am= new GDCM_NAME_SPACE::ArgMgr(argc, argv);
132 if (argc == 1 || am->ArgMgrDefined("usage") )
134 am->ArgMgrUsage(usage); // Display 'usage'
139 char *dirName = am->ArgMgrWantString("dirname",usage);
141 int loadMode = GDCM_NAME_SPACE::LD_ALL;
142 if ( am->ArgMgrDefined("noshadowseq") )
143 loadMode |= GDCM_NAME_SPACE::LD_NOSHADOWSEQ;
146 if ( am->ArgMgrDefined("noshadow") )
147 loadMode |= GDCM_NAME_SPACE::LD_NOSHADOW;
148 if ( am->ArgMgrDefined("noseq") )
149 loadMode |= GDCM_NAME_SPACE::LD_NOSEQ;
152 int reverse = am->ArgMgrDefined("reverse");
154 int mirror = am->ArgMgrDefined("mirror");
155 int topdown = am->ArgMgrDefined("topdown");
156 int rotate = am->ArgMgrDefined("rotate");
158 if ( mirror && topdown )
160 std::cout << "mirror *OR* topDown !"
167 std::cout << "'rotate' undealt with -> ignored !"
171 int check = am->ArgMgrDefined("check");
173 // This is so ugly, a cstring is NOT a char * (god damit!)
174 bool bname = ( strcmp(am->ArgMgrGetString("order", "not found"),"name")==0 );
176 elemsToOrderOn = am->ArgMgrGetXInt16Enum("order", &orderNb);
178 if (am->ArgMgrDefined("debug"))
179 GDCM_NAME_SPACE::Debug::DebugOn();
181 /* if unused Param we give up */
182 if ( am->ArgMgrPrintUnusedLabels() )
184 am->ArgMgrUsage(usage);
189 delete am; // we don't need Argument Manager any longer
191 // ----------------------- End Arguments Manager ----------------------
193 GDCM_NAME_SPACE::SerieHelper *sh = GDCM_NAME_SPACE::SerieHelper::New();
194 sh->SetLoadMode(loadMode);
196 sh->SetSortOrderToReverse();
197 sh->SetDirectory( dirName, true);
202 // For all the 'Single Serie UID' FileSets of the gdcm::Serie
203 GDCM_NAME_SPACE::FileList *l = sh->GetFirstSingleSerieUIDFileSet();
206 std::cout << "Oops! No 'Single Serie UID' FileSet found ?!?" << std::endl;
211 sh->SetUserLessThanFunction(userSuppliedLessThanFunction2);
212 else if (orderNb != 0)
213 sh->SetUserLessThanFunction(userSuppliedLessThanFunction);
217 nbFiles = l->size() ;
220 std::cout << "Sort list : " << nbFiles << " long" << std::endl;
221 sh->OrderFileList(l); // sort the list
222 break; // The first one is OK. user will have to check
226 std::cout << "Oops! Empty 'Single Serie UID' FileSet found ?!?"
229 l = sh->GetNextSingleSerieUIDFileSet();
234 if ( !sh->IsCoherent(l) ) // just be sure (?)
236 std::cout << "Files are not coherent. Stop everything " << std::endl;
242 vtkGdcmReader *reader = vtkGdcmReader::New();
243 reader->AllowLookupTableOff();
246 reader->SetUserFunction (userSuppliedMirrorFunction);
248 reader->SetUserFunction (userSuppliedTopDownFunction);
250 // Only the first FileList is dealt with (just an example)
251 // (The files will not be parsed twice by the reader)
253 //---------------------------------------------------------
254 reader->SetCoherentFileList(l);
255 //---------------------------------------------------------
257 // because we passed a Coherent File List from a SerieHelper,
258 // setting LoadMode is useless in this case
259 // reader->SetLoadMode(NO_SHADOWSEQ);
263 reader->GetOutput()->Print( cout );
265 vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
267 vtkImageViewer *viewer = vtkImageViewer::New();
269 if( reader->GetLookupTable() )
272 vtkImageMapToColors *map = vtkImageMapToColors::New ();
273 map->SetInput (reader->GetOutput());
274 map->SetLookupTable (reader->GetLookupTable());
275 map->SetOutputFormatToRGB();
276 viewer->SetInput ( map->GetOutput() );
281 vtkFloatingPointType *range = reader->GetOutput()->GetScalarRange();
282 viewer->SetColorLevel (0.5 * (range[1] + range[0]));
283 viewer->SetColorWindow (range[1] - range[0]);
285 viewer->SetInput ( reader->GetOutput() );
287 viewer->SetupInteractor (iren);
289 //vtkFloatingPointType *range = reader->GetOutput()->GetScalarRange();
290 //viewer->SetColorWindow (range[1] - range[0]);
291 //viewer->SetColorLevel (0.5 * (range[1] + range[0]));
293 // Here is where we setup the observer,
294 vtkgdcmObserver *obs = vtkgdcmObserver::New();
295 obs->ImageViewer = viewer;
296 iren->AddObserver(vtkCommand::CharEvent,obs);
303 //if you wish you can export dicom to a vtk file
304 vtkStructuredPointsWriter *writer = vtkStructuredPointsWriter::New();
305 writer->SetInput( reader->GetOutput());
306 writer->SetFileName( "foo.vtk" );
307 writer->SetFileTypeToBinary();
319 // --------------------------------------------------------
320 // This is just a *very* simple example of user supplied function
321 // to mirror (why not ?) the image
322 // It's *not* part of gdcm.
323 // --------------------------------------------------------
331 imj = (ty *)im +j*nx; \
332 for (i=0;i<nx/2;i++) \
335 imj[i] =imj[nx-1-i]; \
344 imj = (ty *)im +j*nx; \
346 imj[i] =imj[nx/2+1]; \
351 void userSuppliedMirrorFunction(uint8_t *im, GDCM_NAME_SPACE::File *f)
353 if (f->GetZSize() != 1)
355 std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
359 if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
361 std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
364 int nx = f->GetXSize();
365 int ny = f->GetYSize();
367 std::string pixelType = f->GetPixelType();
368 if ( pixelType == "8U" || pixelType == "8S" )
373 if ( pixelType == "16U" || pixelType == "16S")
378 std::cout << "mirror : Pixel Size (!=8, !=16) not yet dealt with"
384 // --------------------------------------------------------
385 // This is just a *very* simple example of user supplied function
386 // to topdown (why not ?) the image
387 // It's *not* part of gdcm.
388 // --------------------------------------------------------
394 for (j=0;j<ny/2;j++) \
396 imj = (ty *)im +j*nx; \
397 imJ = (ty *)im +(ny-1-j)*nx; \
406 void userSuppliedTopDownFunction(uint8_t *im, GDCM_NAME_SPACE::File *f)
408 if (f->GetZSize() != 1)
410 std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
414 if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
416 std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
419 int nx = f->GetXSize();
420 int ny = f->GetYSize();
422 std::string pixelType = f->GetPixelType();
423 if ( pixelType == "8U" || pixelType == "8S" )
428 if ( pixelType == "16U" || pixelType == "16S")
433 std::cout << "topdown : Pixel Size (!=8, !=16) not yet dealt with"
438 // --------------------------------------------------------
439 // This is just a *very* simple example of user supplied 'LessThan' function
440 // It's *not* part of gdcm.
442 // Note : orderNb and elemsToOrderOn are here global variables.
443 // Within a 'normal' function they would't be any orderNb and elemsToOrderOn var
444 // User *knows* on what field(s) he wants to compare;
445 // He just writes a decent function.
446 // Here, we want to get info from the command line Argument Manager.
448 // Warning : it's up to 'vtkgdcmSerieViewer' user to find a suitable data set !
449 // --------------------------------------------------------
452 bool userSuppliedLessThanFunction(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2)
454 // for *this* user supplied function, I supposed only ValEntries are checked.
457 GDCM_NAME_SPACE::DataEntry *e1,*e2;
458 for (int ri=0; ri<orderNb; ri++)
460 std::cout << std::hex << elemsToOrderOn[2*ri] << "|"
461 << elemsToOrderOn[2*ri+1]
464 e1= f1->GetDataEntry( elemsToOrderOn[2*ri],
465 elemsToOrderOn[2*ri+1]);
467 e2= f2->GetDataEntry( elemsToOrderOn[2*ri],
468 elemsToOrderOn[2*ri+1]);
471 std::cout << std::hex << elemsToOrderOn[2*ri] << "|"
472 << elemsToOrderOn[2*ri+1]
473 << " not found" << std::endl;
476 s1 = e1->GetString();
477 s2 = e2->GetString();
478 std::cout << "[" << s1 << "] vs [" << s2 << "]" << std::endl;
486 return false; // all fields equal
489 // --------------------------------------------------------
490 // This is just an other *very* simple example of user supplied 'LessThan'
492 // It's *not* part of gdcm.
494 // Warning : it's up to 'vtkgdcmSerieViewer' user to find a suitable data set !
495 // --------------------------------------------------------
497 bool userSuppliedLessThanFunction2(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2)
499 std::cout << "[" << f1->GetFileName() << "] vs ["
500 << f2->GetFileName() << "]" << std::endl;
501 return f1->GetFileName() < f2->GetFileName();