]> Creatis software - gdcm.git/blob - vtk/vtkgdcmSerieViewer.cxx
* Rename the NO_SEQ, NO_SHADOW, NO_SHADOWSEQ to
[gdcm.git] / vtk / vtkgdcmSerieViewer.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: vtkgdcmSerieViewer.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/08/30 14:40:35 $
7   Version:   $Revision: 1.6 $
8                                                                                 
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.
12                                                                                 
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.
16                                                                                 
17 =========================================================================*/
18 // This example illustrates how the vtkGdcmReader vtk class can be
19 // used in order to:
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.
24 //
25 // Usage:
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).
30 // 
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>
40
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
48 #endif
49
50 void userSuppliedMirrorFunction (uint8_t *im, gdcm::File *f);
51 void userSuppliedTopDownFunction(uint8_t *im, gdcm::File *f);
52
53 //----------------------------------------------------------------------------
54 // Callback for the interaction
55 class vtkgdcmObserver : public vtkCommand
56 {
57 public:
58    virtual char const *GetClassName() const 
59    { 
60       return "vtkgdcmObserver";
61    }
62
63    static vtkgdcmObserver *New() 
64    { 
65       return new vtkgdcmObserver; 
66    }
67
68    vtkgdcmObserver()
69    {
70       this->ImageViewer = NULL;
71    }
72
73    virtual void Execute(vtkObject *, unsigned long event, void* )
74    {
75       if ( this->ImageViewer )
76       {
77          if ( event == vtkCommand::CharEvent )
78          {
79             int max = ImageViewer->GetWholeZMax();
80             int slice = (ImageViewer->GetZSlice() + 1 ) % ++max;
81             ImageViewer->SetZSlice( slice );
82             ImageViewer->GetRenderer()->ResetCameraClippingRange();
83             ImageViewer->Render();
84          }
85       }
86    }
87    vtkImageViewer *ImageViewer;
88 };
89
90 int main(int argc, char *argv[])
91 {
92    START_USAGE(usage)
93    " \n vtkgdcmSerieViewer : \n",
94    " Display a 'Serie' (same Serie UID) within a Directory                    ",
95    " You can navigate through the stack by hitting any character key.         ",
96    " usage: vtkgdcmSerieViewer dirname=sourcedirectory                        ",
97    "                           [noshadowseq][noshadow][noseq]                 ",
98    "                           [reverse] [{[mirror]|[topdown]|[rotate]}]      ",
99    "                           [check][debug]                                 ",
100    "      sourcedirectory : name of the directory holding the images          ",
101    "                        if it holds more than one serie,                  ",
102    "                        only the first one id displayed.                  ",
103    "      noshadowseq: user doesn't want to load Private Sequences            ",
104    "      noshadow   : user doesn't want to load Private groups (odd number)  ",
105    "      noseq      : user doesn't want to load Sequences                    ",
106    "      reverse    : user wants to sort the images reverse order            ",
107    "      mirror     : user wants to 'mirror' the images | just some simple   ",
108    "      topdown    : user wants to 'topdown' the images| examples of user   ",
109    "      rotate     : user wants NOT YET MADE           | supplied functions ",
110    "      check      : user wants to force more coherence checking            ",
111    "      debug      : user wants to run the program in 'debug mode'          ",
112    FINISH_USAGE
113
114
115    // Initialize Arguments Manager   
116    gdcm::ArgMgr *am= new gdcm::ArgMgr(argc, argv);
117   
118    if (argc == 1 || am->ArgMgrDefined("usage") )
119    {
120       am->ArgMgrUsage(usage); // Display 'usage'
121       delete am;
122       return 0;
123    }
124
125    char *dirName = am->ArgMgrWantString("dirname",usage);
126
127    int loadMode = GDCM_LD_ALL;
128    if ( am->ArgMgrDefined("noshadowseq") )
129       loadMode |= GDCM_LD_NOSHADOWSEQ;
130    else 
131    {
132       if ( am->ArgMgrDefined("noshadow") )
133          loadMode |= GDCM_LD_NOSHADOW;
134       if ( am->ArgMgrDefined("noseq") )
135          loadMode |= GDCM_LD_NOSEQ;
136    }
137
138    int reverse = am->ArgMgrDefined("reverse");
139
140    int mirror  = am->ArgMgrDefined("mirror");
141    int topdown = am->ArgMgrDefined("topdown");
142    int rotate  = am->ArgMgrDefined("rotate");
143
144    int check   = am->ArgMgrDefined("check");
145
146    if ( (int)mirror + (int)topdown + (int)rotate > 1)
147    {
148       std::cout << "mirror *OR* topDown *OR* rotate !"
149                 << std::endl;
150       delete am;
151       return 0;
152    }
153
154    if (am->ArgMgrDefined("debug"))
155       gdcm::Debug::DebugOn();
156
157    /* if unused Param we give up */
158    if ( am->ArgMgrPrintUnusedLabels() )
159    {
160       am->ArgMgrUsage(usage);
161       delete am;
162       return 0;
163    } 
164
165    delete am;  // we don't need Argument Manager any longer
166
167    // ----------------------- End Arguments Manager ----------------------
168   
169    // ------------ to check Coherent File List as a parameter
170
171    gdcm::SerieHelper *sh = new gdcm::SerieHelper();
172    sh->SetLoadMode(loadMode);
173    if (reverse)
174       sh->SetSortOrderToReverse();
175    sh->SetDirectory( dirName, true);
176     
177    // Just to see
178
179    int nbFiles;
180    // For all the Coherent Files lists of the gdcm::Serie
181    gdcm::FileList *l = sh->GetFirstCoherentFileList();
182    if (l == 0 )
183    {
184       std::cout << "Oops! No CoherentFileList found ?!?" << std::endl;
185       return 0;
186    }
187    while (l)
188    { 
189       nbFiles = l->size() ;
190       if ( l->size() > 1 )
191       {
192          std::cout << "Sort list : " << nbFiles << " long" << std::endl;
193          sh->OrderFileList(l);  // sort the list
194          break;  // The first one is OK. user will have to check
195       }
196       else
197       {
198          std::cout << "Oops! Empty CoherentFileList found ?!?" << std::endl;
199       }
200       l = sh->GetNextCoherentFileList();
201    }
202
203    if (check)
204    {
205       if ( !sh->IsCoherent(l) ) // just be sure (?)
206       {
207          std::cout << "Files are not coherent. Stop everything " << std::endl;
208          delete sh;
209          return 0;
210       }
211    }
212
213    vtkGdcmReader *reader = vtkGdcmReader::New();
214    reader->AllowLookupTableOff();
215
216    if (mirror)
217       reader->SetUserFunction (userSuppliedMirrorFunction);
218    else if (topdown)
219       reader->SetUserFunction (userSuppliedTopDownFunction);
220
221    // Only the first FileList is dealt with (just an example)
222    // (The files will not be parsed twice by the reader)
223
224    //---------------------------------------------------------
225    reader->SetCoherentFileList(l);
226    //---------------------------------------------------------
227
228    // because we passed a Coherent File List from a SerieHelper,
229    // setting LoadMode is useless in this case
230    //  reader->SetLoadMode(NO_SHADOWSEQ);  
231    reader->Update();
232
233    //print debug info:
234    reader->GetOutput()->Print( cout );
235
236    vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
237
238    vtkImageViewer *viewer = vtkImageViewer::New();
239
240    if( reader->GetLookupTable() )
241    {
242       //convert to color:
243       vtkImageMapToColors *map = vtkImageMapToColors::New ();
244       map->SetInput (reader->GetOutput());
245       map->SetLookupTable (reader->GetLookupTable());
246       map->SetOutputFormatToRGB();
247       viewer->SetInput ( map->GetOutput() );
248       map->Delete();
249    }
250    else
251    {
252       vtkFloatingPointType *range = reader->GetOutput()->GetScalarRange();
253       viewer->SetColorLevel (0.5 * (range[1] + range[0]));
254       viewer->SetColorWindow (range[1] - range[0]);
255
256       viewer->SetInput ( reader->GetOutput() );
257    }
258    viewer->SetupInteractor (iren);
259   
260    //vtkFloatingPointType *range = reader->GetOutput()->GetScalarRange();
261    //viewer->SetColorWindow (range[1] - range[0]);
262    //viewer->SetColorLevel (0.5 * (range[1] + range[0]));
263
264    // Here is where we setup the observer, 
265    vtkgdcmObserver *obs = vtkgdcmObserver::New();
266    obs->ImageViewer = viewer;
267    iren->AddObserver(vtkCommand::CharEvent,obs);
268    obs->Delete();
269
270    //viewer->Render();
271    iren->Initialize();
272    iren->Start();
273
274    //if you wish you can export dicom to a vtk file  
275    vtkStructuredPointsWriter *writer = vtkStructuredPointsWriter::New();
276    writer->SetInput( reader->GetOutput());
277    writer->SetFileName( "foo.vtk" );
278    writer->SetFileTypeToBinary();
279    //writer->Write();
280
281    reader->Delete();
282    iren->Delete();
283    viewer->Delete();
284    writer->Delete();
285
286    return 0;
287 }
288
289
290 // --------------------------------------------------------
291 // This is just a *very* simple example of user supplied function
292 //      to mirror (why not ?) the image
293 // It's *not* part of gdcm.
294 // --------------------------------------------------------
295
296 #define UF(ty)                          \
297    int i, j;                            \
298    ty *imj;                             \
299    ty tamp;                             \
300    for (j=0;j<ny;j++)                   \
301    {                                    \
302       imj = (ty *)im +j*nx;             \
303       for (i=0;i<nx/2;i++)              \
304       {                                 \
305         tamp       =imj[i];             \
306         imj[i]     =imj[nx-1-i];        \
307         imj[nx-1-i]=tamp;               \
308       }                                 \
309    }                                    \
310    if (nx%2 != 0)                       \
311    {                                    \
312       for (j=0;j<ny;j++)                \
313       {                                 \
314         imj = (ty *)im  +j*nx;          \
315         tamp       =imj[i];             \
316         imj[i]     =imj[nx/2+1];        \
317         imj[nx/2+1]=tamp;               \
318       }                                 \
319    }
320
321 void userSuppliedMirrorFunction(uint8_t *im, gdcm::File *f)
322 {
323    if (f->GetZSize() != 1)
324    {
325       std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
326       return;
327    }
328
329    if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
330    {
331       std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
332       return;
333    }
334    int nx = f->GetXSize();
335    int ny = f->GetYSize();
336
337    std::string pixelType = f->GetPixelType();
338    if ( pixelType ==  "8U" || pixelType == "8S" )
339    {
340       UF(uint8_t)
341       return;
342    }
343    if ( pixelType == "16U" || pixelType == "16S")
344    {
345       UF(uint16_t)
346       return;
347    }
348    std::cout << "mirror : Pixel Size (!=8, !=16) not yet dealt with" 
349              << std::endl;
350    return;
351 }
352
353
354 // --------------------------------------------------------
355 // This is just a *very* simple example of user supplied function
356 //      to topdown (why not ?) the image
357 // It's *not* part of gdcm.
358 // --------------------------------------------------------
359
360 #define UF2(ty)                         \
361    int i, j;                            \
362    ty *imj, *imJ;                       \
363    ty tamp;                             \
364    for (j=0;j<ny/2;j++)                 \
365    {                                    \
366       imj = (ty *)im +j*nx;             \
367       imJ = (ty *)im +(ny-1-j)*nx;      \
368       for (i=0;i<nx;i++)                \
369       {                                 \
370         tamp       =imj[i];             \
371         imj[i]     =imJ[i];             \
372         imJ[i]     =tamp;               \
373       }                                 \
374    }
375
376 void userSuppliedTopDownFunction(uint8_t *im, gdcm::File *f)
377 {
378    if (f->GetZSize() != 1)
379    {
380       std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
381       return;
382    }
383
384    if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
385    {
386       std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
387       return;
388    }
389    int nx = f->GetXSize();
390    int ny = f->GetYSize();
391
392    std::string pixelType = f->GetPixelType();
393    if ( pixelType ==  "8U" || pixelType == "8S" )
394    {
395       UF2(uint8_t)
396       return;
397    }
398    if ( pixelType == "16U" || pixelType == "16S")
399    {
400       UF2(uint16_t)
401       return;
402    }
403    std::cout << "topdown : Pixel Size (!=8, !=16) not yet dealt with" 
404              << std::endl;
405    return;
406 }
407
408
409
410