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 <vtkImageViewer2.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::File *f);
00055 void userSuppliedTopDownFunction(uint8_t *im, gdcm::File *f);
00056 bool userSuppliedLessThanFunction(gdcm::File *f1, gdcm::File *f2);
00057 bool userSuppliedLessThanFunction2(gdcm::File *f1, gdcm::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 vtkImageViewer2 *ImageViewer;
00097 };
00098
00099 int main(int argc, char *argv[])
00100 {
00101 START_USAGE(usage)
00102 " \n vtkgdcmSerieViewer2 : \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::ArgMgr *am= new gdcm::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::LD_ALL;
00142 if ( am->ArgMgrDefined("noshadowseq") )
00143 loadMode |= gdcm::LD_NOSHADOWSEQ;
00144 else
00145 {
00146 if ( am->ArgMgrDefined("noshadow") )
00147 loadMode |= gdcm::LD_NOSHADOW;
00148 if ( am->ArgMgrDefined("noseq") )
00149 loadMode |= gdcm::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", (char*)"not found"),"name")==0 );
00175 if (bname)
00176 elemsToOrderOn = am->ArgMgrGetXInt16Enum("order", &orderNb);
00177
00178 if (am->ArgMgrDefined("debug"))
00179 gdcm::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::SerieHelper *sh = gdcm::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::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 std::cout << "List sorted" << std::endl;
00223 break;
00224 }
00225 else
00226 {
00227 std::cout << "Oops! Empty 'Single Serie UID' FileSet found ?!?"
00228 << std::endl;
00229 }
00230 l = sh->GetNextSingleSerieUIDFileSet();
00231 }
00232
00233 if (check)
00234 {
00235 if ( !sh->IsCoherent(l) )
00236 {
00237 std::cout << "Files are not coherent. Stop everything " << std::endl;
00238 sh->Delete();
00239 return 0;
00240 }
00241 }
00242
00243 vtkGdcmReader *reader = vtkGdcmReader::New();
00244 reader->AllowLookupTableOff();
00245
00246 if (mirror)
00247 reader->SetUserFunction (userSuppliedMirrorFunction);
00248 else if (topdown)
00249 reader->SetUserFunction (userSuppliedTopDownFunction);
00250
00251
00252
00253
00254
00255 reader->SetCoherentFileList(l);
00256
00257
00258
00259
00260
00261 reader->Update();
00262
00263
00264 reader->GetOutput()->Print( cout );
00265
00266 vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
00267
00268 vtkImageViewer2 *viewer = vtkImageViewer2::New();
00269
00270 if( reader->GetLookupTable() )
00271 {
00272
00273 vtkImageMapToColors *map = vtkImageMapToColors::New ();
00274 map->SetInput (reader->GetOutput());
00275 map->SetLookupTable (reader->GetLookupTable());
00276 map->SetOutputFormatToRGB();
00277 viewer->SetInput ( map->GetOutput() );
00278 map->Delete();
00279 }
00280 else
00281 {
00282 vtkFloatingPointType *range = reader->GetOutput()->GetScalarRange();
00283 viewer->SetColorLevel (0.5 * (range[1] + range[0]));
00284 viewer->SetColorWindow (range[1] - range[0]);
00285
00286 viewer->SetInput ( reader->GetOutput() );
00287 }
00288 viewer->SetupInteractor (iren);
00289
00290
00291
00292
00293
00294
00295 vtkgdcmObserver *obs = vtkgdcmObserver::New();
00296 obs->ImageViewer = viewer;
00297 iren->AddObserver(vtkCommand::CharEvent,obs);
00298 obs->Delete();
00299
00300
00301 iren->Initialize();
00302 iren->Start();
00303
00304
00305 vtkStructuredPointsWriter *writer = vtkStructuredPointsWriter::New();
00306 writer->SetInput( reader->GetOutput());
00307 writer->SetFileName( "foo.vtk" );
00308 writer->SetFileTypeToBinary();
00309
00310
00311 reader->Delete();
00312 iren->Delete();
00313 viewer->Delete();
00314 writer->Delete();
00315
00316 return 0;
00317 }
00318
00319
00320
00321
00322
00323
00324
00325
00326 #define UF(ty) \
00327 int i, j; \
00328 ty *imj; \
00329 ty tamp; \
00330 for (j=0;j<ny;j++) \
00331 { \
00332 imj = (ty *)im +j*nx; \
00333 for (i=0;i<nx/2;i++) \
00334 { \
00335 tamp =imj[i]; \
00336 imj[i] =imj[nx-1-i]; \
00337 imj[nx-1-i]=tamp; \
00338 } \
00339 } \
00340 if (nx%2 != 0) \
00341 { \
00342 i = nx / 2; \
00343 for (j=0;j<ny;j++) \
00344 { \
00345 imj = (ty *)im +j*nx; \
00346 tamp =imj[i]; \
00347 imj[i] =imj[nx/2+1]; \
00348 imj[nx/2+1]=tamp; \
00349 } \
00350 }
00351
00352 void userSuppliedMirrorFunction(uint8_t *im, gdcm::File *f)
00353 {
00354 if (f->GetZSize() != 1)
00355 {
00356 std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
00357 return;
00358 }
00359
00360 if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
00361 {
00362 std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
00363 return;
00364 }
00365 int nx = f->GetXSize();
00366 int ny = f->GetYSize();
00367
00368 std::string pixelType = f->GetPixelType();
00369 if ( pixelType == "8U" || pixelType == "8S" )
00370 {
00371 UF(uint8_t)
00372 return;
00373 }
00374 if ( pixelType == "16U" || pixelType == "16S")
00375 {
00376 UF(uint16_t)
00377 return;
00378 }
00379 std::cout << "mirror : Pixel Size (!=8, !=16) not yet dealt with"
00380 << std::endl;
00381 return;
00382 }
00383
00384
00385
00386
00387
00388
00389
00390
00391 #define UF2(ty) \
00392 int i, j; \
00393 ty *imj, *imJ; \
00394 ty tamp; \
00395 for (j=0;j<ny/2;j++) \
00396 { \
00397 imj = (ty *)im +j*nx; \
00398 imJ = (ty *)im +(ny-1-j)*nx; \
00399 for (i=0;i<nx;i++) \
00400 { \
00401 tamp =imj[i]; \
00402 imj[i] =imJ[i]; \
00403 imJ[i] =tamp; \
00404 } \
00405 }
00406
00407 void userSuppliedTopDownFunction(uint8_t *im, gdcm::File *f)
00408 {
00409 if (f->GetZSize() != 1)
00410 {
00411 std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
00412 return;
00413 }
00414
00415 if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
00416 {
00417 std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
00418 return;
00419 }
00420 int nx = f->GetXSize();
00421 int ny = f->GetYSize();
00422
00423 std::string pixelType = f->GetPixelType();
00424 if ( pixelType == "8U" || pixelType == "8S" )
00425 {
00426 UF2(uint8_t)
00427 return;
00428 }
00429 if ( pixelType == "16U" || pixelType == "16S")
00430 {
00431 UF2(uint16_t)
00432 return;
00433 }
00434 std::cout << "topdown : Pixel Size (!=8, !=16) not yet dealt with"
00435 << std::endl;
00436 return;
00437 }
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453 bool userSuppliedLessThanFunction(gdcm::File *f1, gdcm::File *f2)
00454 {
00455
00456
00457 std::string s1, s2;
00458 gdcm::DataEntry *e1,*e2;
00459 for (int ri=0; ri<orderNb; ri++)
00460 {
00461 std::cout << std::hex << elemsToOrderOn[2*ri] << "|"
00462 << elemsToOrderOn[2*ri+1]
00463 << std::endl;
00464
00465 e1= f1->GetDataEntry( elemsToOrderOn[2*ri],
00466 elemsToOrderOn[2*ri+1]);
00467
00468 e2= f2->GetDataEntry( elemsToOrderOn[2*ri],
00469 elemsToOrderOn[2*ri+1]);
00470 if(!e2 || !e2)
00471 {
00472 std::cout << std::hex << elemsToOrderOn[2*ri] << "|"
00473 << elemsToOrderOn[2*ri+1]
00474 << " not found" << std::endl;
00475 continue;
00476 }
00477 s1 = e1->GetString();
00478 s2 = e2->GetString();
00479 std::cout << "[" << s1 << "] vs [" << s2 << "]" << std::endl;
00480 if ( s1 < s2 )
00481 return true;
00482 else if (s1 == s2 )
00483 continue;
00484 else
00485 return false;
00486 }
00487 return false;
00488 }
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498 bool userSuppliedLessThanFunction2(gdcm::File *f1, gdcm::File *f2)
00499 {
00500 std::cout << "[" << f1->GetFileName() << "] vs ["
00501 << f2->GetFileName() << "]" << std::endl;
00502 return f1->GetFileName() < f2->GetFileName();
00503 }