1 /*=========================================================================
4 Module: $RCSfile: vtkgdcmSerieViewer2.cxx,v $
6 Date: $Date: 2007/06/21 14:47:16 $
7 Version: $Revision: 1.11 $
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_NAME_SPACE::SerieHelper constructor and check
20 // the various Setters :
21 // SerieHelper::SetOrderToReverse,
22 // SerieHelper::SetUserLessThanFunction
23 // SerieHelper::SetLoadMode
24 // SerieHelper::SetDropDuplicatePositions
25 // vtkGdcmReader::SetUserFunction
26 // vtkGdcmReader::SetCoherentFileList
28 // * the Directory name that contains the Dicom images constituting the stack
29 // should be given as command line argument (keyword : dirname=),
30 // * you can navigate through the stack by hitting any character key,
31 // * the produced vtk file is named "foo.vtk" (in the invocation directory).
33 //----------------------------------------------------------------------------
34 #include <vtkRenderWindowInteractor.h>
35 #include <vtkImageViewer2.h>
36 #include <vtkStructuredPoints.h>
37 #include <vtkStructuredPointsWriter.h>
38 #include <vtkCommand.h>
39 #include <vtkRenderer.h>
40 #include <vtkImageMapToColors.h>
41 #include <vtkLookupTable.h>
43 #include "vtkGdcmReader.h"
44 #include "gdcmDocument.h" // for NO_SHADOWSEQ
45 #include "gdcmSerieHelper.h"
46 #include "gdcmDebug.h"
47 #include "gdcmDataEntry.h"
49 #include "gdcmArgMgr.h" // for Argument Manager functions
50 #include <string.h> // for strcmp
51 #ifndef vtkFloatingPointType
52 #define vtkFloatingPointType float
55 void userSuppliedMirrorFunction (uint8_t *im, GDCM_NAME_SPACE::File *f);
56 void userSuppliedUpsideDownFunction(uint8_t *im, GDCM_NAME_SPACE::File *f);
57 bool userSuppliedLessThanFunction(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2);
58 bool userSuppliedLessThanFunction2(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2);
61 uint16_t *elemsToOrderOn;
63 //----------------------------------------------------------------------------
64 // Callback for the interaction
65 class vtkgdcmObserver : public vtkCommand
68 virtual char const *GetClassName() const
70 return "vtkgdcmObserver";
73 static vtkgdcmObserver *New()
75 return new vtkgdcmObserver;
80 this->ImageViewer = NULL;
83 virtual void Execute(vtkObject *, unsigned long event, void* )
85 if ( this->ImageViewer )
87 if ( event == vtkCommand::CharEvent )
89 #if (VTK_MAJOR_VERSION >= 5)
90 int max = ImageViewer->GetSliceMax();
91 int slice = (ImageViewer->GetSlice() + 1 ) % ++max;
92 ImageViewer->SetSlice( slice );
94 int max = ImageViewer->GetWholeZMax();
95 int slice = (ImageViewer->GetZSlice() + 1 ) % ++max;
96 ImageViewer->SetZSlice( slice );
98 #if !( (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION >= 5 ) )
99 // This used to be a bug in version VTK 4.4 and earlier
100 ImageViewer->GetRenderer()->ResetCameraClippingRange();
102 ImageViewer->Render();
106 vtkImageViewer2 *ImageViewer;
109 int main(int argc, char *argv[])
112 " \n vtkgdcmSerieViewer2 : \n",
113 " Display a 'Serie' (same Serie UID) within a Directory ",
114 " You can navigate through the stack by hitting any character key. ",
115 " usage: vtkgdcmSerieViewer dirname=sourcedirectory ",
116 " [noshadowseq][noshadow][noseq] ",
117 " [reverse] [{[mirror]|[topdown]|[rotate]}] ",
118 " [order=] [nodup][check][debug] ",
119 " sourcedirectory : name of the directory holding the images ",
120 " if it holds more than one serie, ",
121 " only the first one is displayed. ",
122 " noshadowseq: user doesn't want to load Private Sequences ",
123 " noshadow : user doesn't want to load Private groups (odd number) ",
124 " noseq : user doesn't want to load Sequences ",
125 " reverse : user wants to sort the images reverse order ",
126 " mirror : user wants to 'mirror' the images | just some simple",
127 " upsidedown : user wants to 'upsidedown' the images| examples of user",
128 " | suppliedfunction",
129 " check : user wants to force more coherence checking ",
130 " order= : group1-elem1,group2-elem2,... (in hexa, no space) ",
131 " if we want to use them as a sort criterium ",
132 " Right now : ValEntries only -just an example- ",
134 " order= : order=name if we want to sort on file name (why not ?) ",
135 " nodup : user wants to drop duplicate positions ",
136 " debug : developper wants to run the program in 'debug mode' ",
140 // Initialize Arguments Manager
141 GDCM_NAME_SPACE::ArgMgr *am= new GDCM_NAME_SPACE::ArgMgr(argc, argv);
143 if (argc == 1 || am->ArgMgrDefined("usage") )
145 am->ArgMgrUsage(usage); // Display 'usage'
150 char *dirName = am->ArgMgrWantString("dirname",usage);
152 int loadMode = GDCM_NAME_SPACE::LD_ALL;
153 if ( am->ArgMgrDefined("noshadowseq") )
154 loadMode |= GDCM_NAME_SPACE::LD_NOSHADOWSEQ;
157 if ( am->ArgMgrDefined("noshadow") )
158 loadMode |= GDCM_NAME_SPACE::LD_NOSHADOW;
159 if ( am->ArgMgrDefined("noseq") )
160 loadMode |= GDCM_NAME_SPACE::LD_NOSEQ;
163 int reverse = am->ArgMgrDefined("reverse");
164 int nodup = am->ArgMgrDefined("nodup");
165 int mirror = am->ArgMgrDefined("mirror");
166 int upsidedown = am->ArgMgrDefined("upsidedown");
168 if ( mirror && upsidedown )
170 std::cout << "*EITHER* mirror *OR* upsidedown !"
176 int check = am->ArgMgrDefined("check");
178 // This is so ugly, a cstring is NOT a char * (god damit!)
179 bool bname = ( strcmp(am->ArgMgrGetString("order", "not found"),"name")==0 );
181 elemsToOrderOn = am->ArgMgrGetXInt16Enum("order", &orderNb);
183 if (am->ArgMgrDefined("debug"))
184 GDCM_NAME_SPACE::Debug::DebugOn();
186 /* if unused Param we give up */
187 if ( am->ArgMgrPrintUnusedLabels() )
189 am->ArgMgrUsage(usage);
194 delete am; // we don't need Argument Manager any longer
196 // ----------------------- End Arguments Manager ----------------------
198 GDCM_NAME_SPACE::SerieHelper *sh = GDCM_NAME_SPACE::SerieHelper::New();
199 sh->SetLoadMode(loadMode);
201 sh->SetSortOrderToReverse();
202 sh->SetDirectory( dirName, true);
207 // For all the 'Single Serie UID' FileSets of the GDCM_NAME_SPACE::Serie
208 GDCM_NAME_SPACE::FileList *l = sh->GetFirstSingleSerieUIDFileSet();
211 std::cout << "Oops! No 'Single Serie UID' FileSet found ?!?" << std::endl;
216 sh->SetUserLessThanFunction(userSuppliedLessThanFunction2);
217 else if (orderNb != 0)
218 sh->SetUserLessThanFunction(userSuppliedLessThanFunction);
221 sh->SetDropDuplicatePositions(true);
225 nbFiles = l->size() ;
228 std::cout << "Sort list : " << nbFiles << " long" << std::endl;
230 //---------------------------------------------------------
231 sh->OrderFileList(l); // sort the list (and compute ZSpacing !)
232 //---------------------------------------------------------
234 double zsp = sh->GetZSpacing();
235 std::cout << "List sorted, ZSpacing = " << zsp << std::endl;
236 break; // The first one is OK. user will have to check
240 std::cout << "Oops! Empty 'Single Serie UID' FileSet found ?!?"
243 l = sh->GetNextSingleSerieUIDFileSet();
248 if ( !sh->IsCoherent(l) ) // just be sure (?)
250 std::cout << "Files are not coherent. Stop everything " << std::endl;
256 vtkGdcmReader *reader = vtkGdcmReader::New();
257 reader->AllowLookupTableOff();
260 reader->SetUserFunction (userSuppliedMirrorFunction);
262 reader->SetUserFunction (userSuppliedUpsideDownFunction);
264 // Only the first FileList is dealt with (just an example)
265 // (The files will not be parsed twice by the reader)
267 //---------------------------------------------------------
268 reader->SetCoherentFileList(l);
269 //---------------------------------------------------------
271 // because we passed a Coherent File List from a SerieHelper,
272 // setting LoadMode is useless in this case
273 // reader->SetLoadMode(NO_SHADOWSEQ);
277 reader->GetOutput()->Print( cout );
279 vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
281 vtkImageViewer2 *viewer = vtkImageViewer2::New();
283 if( reader->GetLookupTable() )
286 vtkImageMapToColors *map = vtkImageMapToColors::New ();
287 map->SetInput (reader->GetOutput());
288 map->SetLookupTable (reader->GetLookupTable());
289 map->SetOutputFormatToRGB();
290 viewer->SetInput ( map->GetOutput() );
295 vtkFloatingPointType *range = reader->GetOutput()->GetScalarRange();
296 viewer->SetColorLevel (0.5 * (range[1] + range[0]));
297 viewer->SetColorWindow (range[1] - range[0]);
299 viewer->SetInput ( reader->GetOutput() );
301 viewer->SetupInteractor (iren);
303 //vtkFloatingPointType *range = reader->GetOutput()->GetScalarRange();
304 //viewer->SetColorWindow (range[1] - range[0]);
305 //viewer->SetColorLevel (0.5 * (range[1] + range[0]));
307 // Here is where we setup the observer,
308 vtkgdcmObserver *obs = vtkgdcmObserver::New();
309 obs->ImageViewer = viewer;
310 iren->AddObserver(vtkCommand::CharEvent,obs);
317 //if you wish you can export dicom to a vtk file
318 vtkStructuredPointsWriter *writer = vtkStructuredPointsWriter::New();
319 writer->SetInput( reader->GetOutput());
320 writer->SetFileName( "foo.vtk" );
321 writer->SetFileTypeToBinary();
333 // --------------------------------------------------------
334 // This is just a *very* simple example of user supplied function
335 // to mirror (why not ?) the image
336 // It's *not* part of gdcm.
337 // --------------------------------------------------------
345 imj = (ty *)im +j*nx; \
346 for (i=0;i<nx/2;i++) \
349 imj[i] =imj[nx-1-i]; \
358 imj = (ty *)im +j*nx; \
360 imj[i] =imj[nx/2+1]; \
365 void userSuppliedMirrorFunction(uint8_t *im, GDCM_NAME_SPACE::File *f)
367 if (f->GetZSize() != 1)
369 std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
373 if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
375 std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
378 int nx = f->GetXSize();
379 int ny = f->GetYSize();
381 std::string pixelType = f->GetPixelType();
382 if ( pixelType == "8U" || pixelType == "8S" )
387 if ( pixelType == "16U" || pixelType == "16S")
392 std::cout << "mirror : Pixel Size (!=8, !=16) not yet dealt with"
398 // --------------------------------------------------------
399 // This is just a *very* simple example of user supplied function
400 // to upsidedown (why not ?) the image
401 // It's *not* part of gdcm.
402 // --------------------------------------------------------
408 for (j=0;j<ny/2;j++) \
410 imj = (ty *)im +j*nx; \
411 imJ = (ty *)im +(ny-1-j)*nx; \
420 void userSuppliedUpsideDownFunction(uint8_t *im, GDCM_NAME_SPACE::File *f)
422 if (f->GetZSize() != 1)
424 std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
428 if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
430 std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
433 int nx = f->GetXSize();
434 int ny = f->GetYSize();
436 std::string pixelType = f->GetPixelType();
437 if ( pixelType == "8U" || pixelType == "8S" )
442 if ( pixelType == "16U" || pixelType == "16S")
447 std::cout << "topdown : Pixel Size (!=8, !=16) not yet dealt with"
452 // --------------------------------------------------------
453 // This is just a *very* simple example of user supplied 'LessThan' function
454 // It's *not* part of gdcm.
456 // Note : orderNb and elemsToOrderOn are here global variables.
457 // Within a 'normal' function they would't be any orderNb and elemsToOrderOn var
458 // User *knows* on what field(s) he wants to compare;
459 // He just writes a decent function.
460 // Here, we want to get info from the command line Argument Manager.
462 // Warning : it's up to 'vtkgdcmSerieViewer' user to find a suitable data set !
463 // --------------------------------------------------------
466 bool userSuppliedLessThanFunction(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2)
468 // for *this* user supplied function, I supposed only ValEntries are checked.
471 GDCM_NAME_SPACE::DataEntry *e1,*e2;
472 for (int ri=0; ri<orderNb; ri++)
474 std::cout << std::hex << elemsToOrderOn[2*ri] << "|"
475 << elemsToOrderOn[2*ri+1]
478 e1= f1->GetDataEntry( elemsToOrderOn[2*ri],
479 elemsToOrderOn[2*ri+1]);
481 e2= f2->GetDataEntry( elemsToOrderOn[2*ri],
482 elemsToOrderOn[2*ri+1]);
485 std::cout << std::hex << elemsToOrderOn[2*ri] << "|"
486 << elemsToOrderOn[2*ri+1]
487 << " not found" << std::endl;
490 s1 = e1->GetString();
491 s2 = e2->GetString();
492 std::cout << "[" << s1 << "] vs [" << s2 << "]" << std::endl;
500 return false; // all fields equal
503 // --------------------------------------------------------
504 // This is just an other *very* simple example of user supplied 'LessThan'
506 // It's *not* part of gdcm.
508 // Warning : it's up to 'vtkgdcmSerieViewer' user to find a suitable data set !
509 // --------------------------------------------------------
511 bool userSuppliedLessThanFunction2(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2)
513 std::cout << "[" << f1->GetFileName() << "] vs ["
514 << f2->GetFileName() << "]" << std::endl;
515 return f1->GetFileName() < f2->GetFileName();