00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <vtkRenderWindowInteractor.h>
00034 #include <vtkImageViewer.h>
00035 #include <vtkStructuredPoints.h>
00036 #include <vtkStructuredPointsWriter.h>
00037 #include <vtkCommand.h>
00038 #include <vtkRenderer.h>
00039 #include <vtkImageMapToColors.h>
00040 #include <vtkLookupTable.h>
00041
00042 #include "vtkGdcmReader.h"
00043 #include "gdcmDocument.h"
00044 #include "gdcmSerieHelper.h"
00045 #include "gdcmDebug.h"
00046 #include "gdcmDataEntry.h"
00047
00048 #include "gdcmArgMgr.h"
00049 #include <string.h>
00050 #ifndef vtkFloatingPointType
00051 #define vtkFloatingPointType float
00052 #endif
00053
00054 void userSuppliedMirrorFunction (uint8_t *im, GDCM_NAME_SPACE::File *f);
00055 void userSuppliedTopDownFunction(uint8_t *im, GDCM_NAME_SPACE::File *f);
00056 bool userSuppliedLessThanFunction(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2);
00057 bool userSuppliedLessThanFunction2(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2);
00058
00059 int orderNb;
00060 uint16_t *elemsToOrderOn;
00061
00062
00063
00064 class vtkgdcmObserver : public vtkCommand
00065 {
00066 public:
00067 virtual char const *GetClassName() const
00068 {
00069 return "vtkgdcmObserver";
00070 }
00071
00072 static vtkgdcmObserver *New()
00073 {
00074 return new vtkgdcmObserver;
00075 }
00076
00077 vtkgdcmObserver()
00078 {
00079 this->ImageViewer = NULL;
00080 }
00081
00082 virtual void Execute(vtkObject *, unsigned long event, void* )
00083 {
00084 if ( this->ImageViewer )
00085 {
00086 if ( event == vtkCommand::CharEvent )
00087 {
00088 int max = ImageViewer->GetWholeZMax();
00089 int slice = (ImageViewer->GetZSlice() + 1 ) % ++max;
00090 ImageViewer->SetZSlice( slice );
00091 ImageViewer->GetRenderer()->ResetCameraClippingRange();
00092 ImageViewer->Render();
00093 }
00094 }
00095 }
00096 vtkImageViewer *ImageViewer;
00097 };
00098
00099 int main(int argc, char *argv[])
00100 {
00101 START_USAGE(usage)
00102 " \n vtkgdcmSerieViewer : \n",
00103 " Display a 'Serie' (same Serie UID) within a Directory ",
00104 " You can navigate through the stack by hitting any character key. ",
00105 " usage: vtkgdcmSerieViewer dirname=sourcedirectory ",
00106 " [noshadowseq][noshadow][noseq] ",
00107 " [reverse] [{[mirror]|[topdown]|[rotate]}] ",
00108 " [order=] [check][debug] ",
00109 " sourcedirectory : name of the directory holding the images ",
00110 " if it holds more than one serie, ",
00111 " only the first one id displayed. ",
00112 " noshadowseq: user doesn't want to load Private Sequences ",
00113 " noshadow : user doesn't want to load Private groups (odd number) ",
00114 " noseq : user doesn't want to load Sequences ",
00115 " reverse : user wants to sort the images reverse order ",
00116 " mirror : user wants to 'mirror' the images | just some simple ",
00117 " topdown : user wants to 'topdown' the images| examples of user ",
00118 " rotate : NOT YET MADE (useless?) | supplied functions ",
00119 " check : user wants to force more coherence checking ",
00120 " order= : group1-elem1,group2-elem2,... (in hexa, no space) ",
00121 " if we want to use them as a sort criterium ",
00122 " Right now : ValEntries only -just an example- ",
00123 " or ",
00124 " order= : order=name if we want to sort on file name (why not ?) ",
00125 " debug : user wants to run the program in 'debug mode' ",
00126 FINISH_USAGE
00127
00128
00129
00130 GDCM_NAME_SPACE::ArgMgr *am= new GDCM_NAME_SPACE::ArgMgr(argc, argv);
00131
00132 if (argc == 1 || am->ArgMgrDefined("usage") )
00133 {
00134 am->ArgMgrUsage(usage);
00135 delete am;
00136 return 0;
00137 }
00138
00139 char *dirName = am->ArgMgrWantString("dirname",usage);
00140
00141 int loadMode = GDCM_NAME_SPACE::LD_ALL;
00142 if ( am->ArgMgrDefined("noshadowseq") )
00143 loadMode |= GDCM_NAME_SPACE::LD_NOSHADOWSEQ;
00144 else
00145 {
00146 if ( am->ArgMgrDefined("noshadow") )
00147 loadMode |= GDCM_NAME_SPACE::LD_NOSHADOW;
00148 if ( am->ArgMgrDefined("noseq") )
00149 loadMode |= GDCM_NAME_SPACE::LD_NOSEQ;
00150 }
00151
00152 int reverse = am->ArgMgrDefined("reverse");
00153
00154 int mirror = am->ArgMgrDefined("mirror");
00155 int topdown = am->ArgMgrDefined("topdown");
00156 int rotate = am->ArgMgrDefined("rotate");
00157
00158 if ( mirror && topdown )
00159 {
00160 std::cout << "mirror *OR* topDown !"
00161 << std::endl;
00162 delete am;
00163 return 0;
00164 }
00165 if ( rotate )
00166 {
00167 std::cout << "'rotate' undealt with -> ignored !"
00168 << std::endl;
00169 }
00170
00171 int check = am->ArgMgrDefined("check");
00172
00173
00174 bool bname = ( strcmp(am->ArgMgrGetString("order", "not found"),"name")==0 );
00175 if (bname)
00176 elemsToOrderOn = am->ArgMgrGetXInt16Enum("order", &orderNb);
00177
00178 if (am->ArgMgrDefined("debug"))
00179 GDCM_NAME_SPACE::Debug::DebugOn();
00180
00181
00182 if ( am->ArgMgrPrintUnusedLabels() )
00183 {
00184 am->ArgMgrUsage(usage);
00185 delete am;
00186 return 0;
00187 }
00188
00189 delete am;
00190
00191
00192
00193 GDCM_NAME_SPACE::SerieHelper *sh = GDCM_NAME_SPACE::SerieHelper::New();
00194 sh->SetLoadMode(loadMode);
00195 if (reverse)
00196 sh->SetSortOrderToReverse();
00197 sh->SetDirectory( dirName, true);
00198
00199
00200
00201 int nbFiles;
00202
00203 GDCM_NAME_SPACE::FileList *l = sh->GetFirstSingleSerieUIDFileSet();
00204 if (l == 0 )
00205 {
00206 std::cout << "Oops! No 'Single Serie UID' FileSet found ?!?" << std::endl;
00207 return 0;
00208 }
00209
00210 if (bname)
00211 sh->SetUserLessThanFunction(userSuppliedLessThanFunction2);
00212 else if (orderNb != 0)
00213 sh->SetUserLessThanFunction(userSuppliedLessThanFunction);
00214
00215 while (l)
00216 {
00217 nbFiles = l->size() ;
00218 if ( l->size() > 1 )
00219 {
00220 std::cout << "Sort list : " << nbFiles << " long" << std::endl;
00221 sh->OrderFileList(l);
00222 break;
00223 }
00224 else
00225 {
00226 std::cout << "Oops! Empty 'Single Serie UID' FileSet found ?!?"
00227 << std::endl;
00228 }
00229 l = sh->GetNextSingleSerieUIDFileSet();
00230 }
00231
00232 if (check)
00233 {
00234 if ( !sh->IsCoherent(l) )
00235 {
00236 std::cout << "Files are not coherent. Stop everything " << std::endl;
00237 sh->Delete();
00238 return 0;
00239 }
00240 }
00241
00242 vtkGdcmReader *reader = vtkGdcmReader::New();
00243 reader->AllowLookupTableOff();
00244
00245 if (mirror)
00246 reader->SetUserFunction (userSuppliedMirrorFunction);
00247 else if (topdown)
00248 reader->SetUserFunction (userSuppliedTopDownFunction);
00249
00250
00251
00252
00253
00254 reader->SetCoherentFileList(l);
00255
00256
00257
00258
00259
00260 reader->Update();
00261
00262
00263 reader->GetOutput()->Print( cout );
00264
00265 vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
00266
00267 vtkImageViewer *viewer = vtkImageViewer::New();
00268
00269 if( reader->GetLookupTable() )
00270 {
00271
00272 vtkImageMapToColors *map = vtkImageMapToColors::New ();
00273 map->SetInput (reader->GetOutput());
00274 map->SetLookupTable (reader->GetLookupTable());
00275 map->SetOutputFormatToRGB();
00276 viewer->SetInput ( map->GetOutput() );
00277 map->Delete();
00278 }
00279 else
00280 {
00281 vtkFloatingPointType *range = reader->GetOutput()->GetScalarRange();
00282 viewer->SetColorLevel (0.5 * (range[1] + range[0]));
00283 viewer->SetColorWindow (range[1] - range[0]);
00284
00285 viewer->SetInput ( reader->GetOutput() );
00286 }
00287 viewer->SetupInteractor (iren);
00288
00289
00290
00291
00292
00293
00294 vtkgdcmObserver *obs = vtkgdcmObserver::New();
00295 obs->ImageViewer = viewer;
00296 iren->AddObserver(vtkCommand::CharEvent,obs);
00297 obs->Delete();
00298
00299
00300 iren->Initialize();
00301 iren->Start();
00302
00303
00304 vtkStructuredPointsWriter *writer = vtkStructuredPointsWriter::New();
00305 writer->SetInput( reader->GetOutput());
00306 writer->SetFileName( "foo.vtk" );
00307 writer->SetFileTypeToBinary();
00308
00309
00310 reader->Delete();
00311 iren->Delete();
00312 viewer->Delete();
00313 writer->Delete();
00314
00315 return 0;
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325 #define UF(ty) \
00326 int i, j; \
00327 ty *imj; \
00328 ty tamp; \
00329 for (j=0;j<ny;j++) \
00330 { \
00331 imj = (ty *)im +j*nx; \
00332 for (i=0;i<nx/2;i++) \
00333 { \
00334 tamp =imj[i]; \
00335 imj[i] =imj[nx-1-i]; \
00336 imj[nx-1-i]=tamp; \
00337 } \
00338 } \
00339 if (nx%2 != 0) \
00340 { \
00341 i = nx / 2; \
00342 for (j=0;j<ny;j++) \
00343 { \
00344 imj = (ty *)im +j*nx; \
00345 tamp =imj[i]; \
00346 imj[i] =imj[nx/2+1]; \
00347 imj[nx/2+1]=tamp; \
00348 } \
00349 }
00350
00351 void userSuppliedMirrorFunction(uint8_t *im, GDCM_NAME_SPACE::File *f)
00352 {
00353 if (f->GetZSize() != 1)
00354 {
00355 std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
00356 return;
00357 }
00358
00359 if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
00360 {
00361 std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
00362 return;
00363 }
00364 int nx = f->GetXSize();
00365 int ny = f->GetYSize();
00366
00367 std::string pixelType = f->GetPixelType();
00368 if ( pixelType == "8U" || pixelType == "8S" )
00369 {
00370 UF(uint8_t)
00371 return;
00372 }
00373 if ( pixelType == "16U" || pixelType == "16S")
00374 {
00375 UF(uint16_t)
00376 return;
00377 }
00378 std::cout << "mirror : Pixel Size (!=8, !=16) not yet dealt with"
00379 << std::endl;
00380 return;
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390 #define UF2(ty) \
00391 int i, j; \
00392 ty *imj, *imJ; \
00393 ty tamp; \
00394 for (j=0;j<ny/2;j++) \
00395 { \
00396 imj = (ty *)im +j*nx; \
00397 imJ = (ty *)im +(ny-1-j)*nx; \
00398 for (i=0;i<nx;i++) \
00399 { \
00400 tamp =imj[i]; \
00401 imj[i] =imJ[i]; \
00402 imJ[i] =tamp; \
00403 } \
00404 }
00405
00406 void userSuppliedTopDownFunction(uint8_t *im, GDCM_NAME_SPACE::File *f)
00407 {
00408 if (f->GetZSize() != 1)
00409 {
00410 std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
00411 return;
00412 }
00413
00414 if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
00415 {
00416 std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
00417 return;
00418 }
00419 int nx = f->GetXSize();
00420 int ny = f->GetYSize();
00421
00422 std::string pixelType = f->GetPixelType();
00423 if ( pixelType == "8U" || pixelType == "8S" )
00424 {
00425 UF2(uint8_t)
00426 return;
00427 }
00428 if ( pixelType == "16U" || pixelType == "16S")
00429 {
00430 UF2(uint16_t)
00431 return;
00432 }
00433 std::cout << "topdown : Pixel Size (!=8, !=16) not yet dealt with"
00434 << std::endl;
00435 return;
00436 }
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452 bool userSuppliedLessThanFunction(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2)
00453 {
00454
00455
00456 std::string s1, s2;
00457 GDCM_NAME_SPACE::DataEntry *e1,*e2;
00458 for (int ri=0; ri<orderNb; ri++)
00459 {
00460 std::cout << std::hex << elemsToOrderOn[2*ri] << "|"
00461 << elemsToOrderOn[2*ri+1]
00462 << std::endl;
00463
00464 e1= f1->GetDataEntry( elemsToOrderOn[2*ri],
00465 elemsToOrderOn[2*ri+1]);
00466
00467 e2= f2->GetDataEntry( elemsToOrderOn[2*ri],
00468 elemsToOrderOn[2*ri+1]);
00469 if(!e2 || !e2)
00470 {
00471 std::cout << std::hex << elemsToOrderOn[2*ri] << "|"
00472 << elemsToOrderOn[2*ri+1]
00473 << " not found" << std::endl;
00474 continue;
00475 }
00476 s1 = e1->GetString();
00477 s2 = e2->GetString();
00478 std::cout << "[" << s1 << "] vs [" << s2 << "]" << std::endl;
00479 if ( s1 < s2 )
00480 return true;
00481 else if (s1 == s2 )
00482 continue;
00483 else
00484 return false;
00485 }
00486 return false;
00487 }
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497 bool userSuppliedLessThanFunction2(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2)
00498 {
00499 std::cout << "[" << f1->GetFileName() << "] vs ["
00500 << f2->GetFileName() << "]" << std::endl;
00501 return f1->GetFileName() < f2->GetFileName();
00502 }