1 /*=========================================================================
4 Module: $RCSfile: vtkgdcmSerieViewer.cxx,v $
6 Date: $Date: 2005/07/30 18:37:48 $
7 Version: $Revision: 1.4 $
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 be
20 // * produce a simple (vtk based) Dicom image STACK VIEWER.
21 // * dump the stack considered as a volume in a vtkStructuredPoints
22 // vtk file: the vtk gdcm wrappers can be seen as a simple way to convert
23 // a stack of Dicom images into a native vtk volume.
26 // * the Directory name that contains the Dicom images constituting the stack
27 // should be given as command line argument,
28 // * you can navigate through the stack by hitting any character key,
29 // * the produced vtk file is named "foo.vtk" (in the invocation directory).
31 //----------------------------------------------------------------------------
32 #include <vtkRenderWindowInteractor.h>
33 #include <vtkImageViewer.h>
34 #include <vtkStructuredPoints.h>
35 #include <vtkStructuredPointsWriter.h>
36 #include <vtkCommand.h>
37 #include <vtkRenderer.h>
38 #include <vtkImageMapToColors.h>
39 #include <vtkLookupTable.h>
41 #include "vtkGdcmReader.h"
42 #include "gdcmDocument.h" // for NO_SHADOWSEQ
43 #include "gdcmSerieHelper.h"
44 #include "gdcmDebug.h"
45 #include "gdcmArgMgr.h" // for Argument Manager functions
46 #ifndef vtkFloatingPointType
47 #define vtkFloatingPointType float
50 void userSuppliedMirrorFunction (uint8_t *im, gdcm::File *f);
51 void userSuppliedTopDownFunction(uint8_t *im, gdcm::File *f);
53 //----------------------------------------------------------------------------
54 // Callback for the interaction
55 class vtkgdcmObserver : public vtkCommand
58 virtual char const *GetClassName() const
60 return "vtkgdcmObserver";
63 static vtkgdcmObserver *New()
65 return new vtkgdcmObserver;
70 this->ImageViewer = NULL;
73 virtual void Execute(vtkObject *, unsigned long event, void* )
75 if ( this->ImageViewer )
77 if ( event == vtkCommand::CharEvent )
79 int max = ImageViewer->GetWholeZMax();
80 int slice = (ImageViewer->GetZSlice() + 1 ) % ++max;
81 ImageViewer->SetZSlice( slice );
82 ImageViewer->GetRenderer()->ResetCameraClippingRange();
83 ImageViewer->Render();
87 vtkImageViewer *ImageViewer;
90 int main(int argc, char *argv[])
93 " \n vtkgdcmSerieViewer : \n",
94 " Display a Serie within a Directory ",
95 " You can navigate through the stack by hitting any character key. ",
96 " usage: vtkgdcmSerieViewer filein=fileName [noshadowseq][noshadow][noseq] ",
97 " [reverse] [{[mirror]|[topdown]|[rotate]}] ",
99 " noshadowseq: user doesn't want to load Private Sequences ",
100 " noshadow : user doesn't want to load Private groups (odd number) ",
101 " noseq : user doesn't want to load Sequences ",
102 " mirror : user wants to 'mirror' the images | just some simple ",
103 " topdown : user wants to 'topdown' the images| examples of user ",
104 " rotate : user wants NOT YET MADE | supplied functions ",
105 " debug : user wants to run the program in 'debug mode' ",
109 // Initialize Arguments Manager
110 gdcm::ArgMgr *am= new gdcm::ArgMgr(argc, argv);
112 if (argc == 1 || am->ArgMgrDefined("usage") )
114 am->ArgMgrUsage(usage); // Display 'usage'
119 char *dirName = am->ArgMgrWantString("dirname",usage);
121 int loadMode = 0x00000000;
122 if ( am->ArgMgrDefined("noshadowseq") )
123 loadMode |= NO_SHADOWSEQ;
126 if ( am->ArgMgrDefined("noshadow") )
127 loadMode |= NO_SHADOW;
128 if ( am->ArgMgrDefined("noseq") )
132 bool reverse = am->ArgMgrDefined("reverse");
134 bool mirror = am->ArgMgrDefined("mirror");
135 bool topdown = am->ArgMgrDefined("topdown");
136 bool rotate = am->ArgMgrDefined("rotate");
138 bool check = am->ArgMgrDefined("check");
140 if ( (int)mirror + (int)topdown + (int)rotate > 1)
142 std::cout << "mirror *OR* topDown *OR* rotate !"
148 if (am->ArgMgrDefined("debug"))
149 gdcm::Debug::DebugOn();
151 /* if unused Param we give up */
152 if ( am->ArgMgrPrintUnusedLabels() )
154 am->ArgMgrUsage(usage);
159 delete am; // we don't need Argument Manager any longer
161 // ----------------------- End Arguments Manager ----------------------
163 // ------------ to check Coherent File List as a parameter
165 gdcm::SerieHelper *sh = new gdcm::SerieHelper();
166 sh->SetLoadMode(loadMode);
168 sh->SetSortOrderToReverse();
169 sh->SetDirectory( dirName, true);
174 // For all the Coherent Files lists of the gdcm::Serie
175 gdcm::FileList *l = sh->GetFirstCoherentFileList();
178 std::cout << "Oops! No CoherentFileList found ?!?" << std::endl;
183 nbFiles = l->size() ;
186 std::cout << "Sort list : " << nbFiles << " long" << std::endl;
187 sh->OrderFileList(l); // sort the list
188 break; // The first one is OK. user will have to check
192 std::cout << "Oops! Empty CoherentFileList found ?!?" << std::endl;
194 l = sh->GetNextCoherentFileList();
199 if ( !sh->IsCoherent(l) ) // just be sure (?)
201 std::cout << "Files are not coherent. Stop everything " << std::endl;
207 vtkGdcmReader *reader = vtkGdcmReader::New();
208 reader->AllowLookupTableOff();
211 reader->SetUserFunction (userSuppliedMirrorFunction);
213 reader->SetUserFunction (userSuppliedTopDownFunction);
215 // Only the first FileList is dealt with (just an example)
216 // (The files will not be parsed twice by the reader)
218 //---------------------------------------------------------
219 reader->SetCoherentFileList(l);
220 //---------------------------------------------------------
222 // because we passed a Coherent File List from a SerieHelper,
223 // setting LoadMode is useless in this case
224 // reader->SetLoadMode(NO_SHADOWSEQ);
228 reader->GetOutput()->Print( cout );
230 vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
232 vtkImageViewer *viewer = vtkImageViewer::New();
234 if( reader->GetLookupTable() )
237 vtkImageMapToColors *map = vtkImageMapToColors::New ();
238 map->SetInput (reader->GetOutput());
239 map->SetLookupTable (reader->GetLookupTable());
240 map->SetOutputFormatToRGB();
241 viewer->SetInput ( map->GetOutput() );
246 vtkFloatingPointType *range = reader->GetOutput()->GetScalarRange();
247 viewer->SetColorLevel (0.5 * (range[1] + range[0]));
248 viewer->SetColorWindow (range[1] - range[0]);
250 viewer->SetInput ( reader->GetOutput() );
252 viewer->SetupInteractor (iren);
254 //vtkFloatingPointType *range = reader->GetOutput()->GetScalarRange();
255 //viewer->SetColorWindow (range[1] - range[0]);
256 //viewer->SetColorLevel (0.5 * (range[1] + range[0]));
258 // Here is where we setup the observer,
259 vtkgdcmObserver *obs = vtkgdcmObserver::New();
260 obs->ImageViewer = viewer;
261 iren->AddObserver(vtkCommand::CharEvent,obs);
268 //if you wish you can export dicom to a vtk file
269 vtkStructuredPointsWriter *writer = vtkStructuredPointsWriter::New();
270 writer->SetInput( reader->GetOutput());
271 writer->SetFileName( "foo.vtk" );
272 writer->SetFileTypeToBinary();
284 // --------------------------------------------------------
285 // This is just a *very* simple example of user supplied function
286 // to mirror (why not ?) the image
287 // It's *not* part of gdcm.
288 // --------------------------------------------------------
296 imj = (ty *)im +j*nx; \
297 for (i=0;i<nx/2;i++) \
300 imj[i] =imj[nx-1-i]; \
308 imj = (ty *)im +j*nx; \
310 imj[i] =imj[nx/2+1]; \
315 void userSuppliedMirrorFunction(uint8_t *im, gdcm::File *f)
317 if (f->GetZSize() != 1)
319 std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
323 if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
325 std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
328 int nx = f->GetXSize();
329 int ny = f->GetYSize();
331 std::string pixelType = f->GetPixelType();
332 if ( pixelType == "8U" || pixelType == "8S" )
337 if ( pixelType == "16U" || pixelType == "16S")
342 std::cout << "mirror : Pixel Size (!=8, !=16) not yet dealt with"
348 // --------------------------------------------------------
349 // This is just a *very* simple example of user supplied function
350 // to topdown (why not ?) the image
351 // It's *not* part of gdcm.
352 // --------------------------------------------------------
358 for (j=0;j<ny/2;j++) \
360 imj = (ty *)im +j*nx; \
361 imJ = (ty *)im +(ny-1-j)*nx; \
370 void userSuppliedTopDownFunction(uint8_t *im, gdcm::File *f)
372 if (f->GetZSize() != 1)
374 std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
378 if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
380 std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
383 int nx = f->GetXSize();
384 int ny = f->GetYSize();
386 std::string pixelType = f->GetPixelType();
387 if ( pixelType == "8U" || pixelType == "8S" )
392 if ( pixelType == "16U" || pixelType == "16S")
397 std::cout << "topdown : Pixel Size (!=8, !=16) not yet dealt with"