00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "mitkVolumeVisualizationImagePreprocessor.h"
00020
00021 #include <itkOrImageFilter.h>
00022 #include <itkRegionOfInterestImageFilter.h>
00023
00024 #include <mitkMemoryUtilities.h>
00025
00026 #define VVP_INFO MITK_INFO << "Mem Usage: " << mitk::MemoryUtilities::GetProcessMemoryUsage() << " "
00027
00028 namespace mitk
00029 {
00030
00031 VolumeVisualizationImagePreprocessor::VolumeVisualizationImagePreprocessor()
00032 : m_OutOfLiverValue(-512),
00033 m_surfaceValue(-256),
00034 m_realSurfaceValue(0),
00035 m_EstimatedThreshold( 150.0 ),
00036 m_MinThreshold( 0.0 ),
00037 m_MaxThreshold( 250.0 )
00038 {
00039 }
00040
00041 VolumeVisualizationImagePreprocessor::~VolumeVisualizationImagePreprocessor()
00042 {
00043 }
00044
00045
00046
00047 TransferFunction::Pointer
00048 VolumeVisualizationImagePreprocessor::GetInitialTransferFunction( )
00049 {
00050 int treshold = m_EstimatedThreshold;
00051
00052 double opacity = 0.005;
00053
00054 double maskValue = m_OutOfLiverValue;
00055 double surfaceValue = m_surfaceValue;
00056 double realSurfaceValue = m_realSurfaceValue;
00057
00058
00059
00060 VVP_INFO << "using threshold of " << treshold << " and opacity of " << opacity;
00061
00062 TransferFunction::Pointer tf = TransferFunction::New();
00063
00064
00065 {
00066 vtkPiecewiseFunction *f=tf->GetScalarOpacityFunction();
00067 f->RemoveAllPoints();
00068 f->AddPoint(maskValue,0);
00069 f->AddPoint(maskValue+1,0);
00070 f->AddPoint(surfaceValue,0.05);
00071 f->AddPoint(realSurfaceValue,opacity);
00072 f->AddPoint(treshold-1,opacity);
00073 f->AddPoint(treshold+4,0.8);
00074 f->AddPoint(m_MaxThreshold+1,0.8);
00075 f->ClampingOn();
00076 f->Modified();
00077 }
00078
00079
00080 {
00081 vtkPiecewiseFunction *f=tf->GetGradientOpacityFunction();
00082 f->RemoveAllPoints();
00083 f->AddPoint( -1000.0, 1.0 );
00084 f->AddPoint( 1000, 1.0 );
00085 f->ClampingOn();
00086 f->Modified();
00087 }
00088
00089
00090 {
00091 vtkColorTransferFunction *ctf=tf->GetColorTransferFunction();
00092 ctf->RemoveAllPoints();
00093 ctf->AddRGBPoint( maskValue, 0.5, 0.0, 0.0 );
00094 ctf->AddRGBPoint( maskValue+1, 0.5, 0.0, 0.0 );
00095 ctf->AddRGBPoint( surfaceValue, 1.0, 0.0, 0.0 );
00096 ctf->AddRGBPoint( realSurfaceValue, 0.2, 0.0, 0.0 );
00097
00098 ctf->AddRGBPoint( treshold-32, 0.2, 0.0, 0.0 );
00099 ctf->AddRGBPoint( treshold, 251/255.0, 1.0, 0.0 );
00100 ctf->AddRGBPoint( m_MaxThreshold+1, 251/255.0, 1.0, 0.0 );
00101
00102 ctf->ClampingOn();
00103 ctf->Modified();
00104 }
00105
00106 m_LastUsedTreshold = treshold;
00107
00108 return tf;
00109 }
00110
00111
00112 void VolumeVisualizationImagePreprocessor::UpdateTransferFunction( TransferFunction::Pointer tf, int treshold )
00113 {
00114 double opacity = 0.005;
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 {
00126 vtkPiecewiseFunction *f=tf->GetScalarOpacityFunction();
00127
00128 f->RemovePoint( m_LastUsedTreshold-1 );
00129 f->AddPoint(treshold-1,opacity);
00130
00131 f->RemovePoint( m_LastUsedTreshold+4 );
00132 f->AddPoint(treshold+4,0.8);
00133 }
00134
00135
00136 {
00137 vtkColorTransferFunction *ctf=tf->GetColorTransferFunction();
00138
00139 ctf->RemovePoint( m_LastUsedTreshold-32 );
00140 ctf->AddRGBPoint( treshold-32, 0.2, 0.0, 0.0 );
00141
00142 ctf->RemovePoint( m_LastUsedTreshold );
00143 ctf->AddRGBPoint( treshold, 251/255.0, 1.0, 0.0 );
00144 }
00145
00146 m_LastUsedTreshold = treshold;
00147 }
00148
00149 VolumeVisualizationImagePreprocessor::LabelImage::Pointer
00150 VolumeVisualizationImagePreprocessor::ConnectComponents(BinImage::Pointer src)
00151 {
00152 VVP_INFO << "Connect Components...";
00153
00154 LabelImage::Pointer dst = LabelImage::New();
00155
00156 typedef itk::ConnectedComponentImageFilter< BinImage, LabelImage > myFilterType;
00157
00158 myFilterType::Pointer myFilter = myFilterType::New();
00159
00160 myFilter->SetInput(src);
00161 myFilter->Update();
00162 dst = myFilter->GetOutput();
00163 dst->DisconnectPipeline();
00164
00165 return dst;
00166 }
00167
00168 VolumeVisualizationImagePreprocessor::BinImage::Pointer
00169 VolumeVisualizationImagePreprocessor::Threshold(CTImage::Pointer src, int threshold)
00170 {
00171 VVP_INFO << "thresholding...";
00172
00173 BinImage::Pointer dst = BinImage::New();
00174
00175 typedef itk::ThresholdLabelerImageFilter< CTImage, BinImage > myFilterType;
00176
00177 myFilterType::Pointer myFilter = myFilterType::New();
00178
00179 myFilter->SetInput(src);
00180
00181 myFilterType::ThresholdVector tv;
00182 tv.push_back(threshold);
00183 myFilter->SetThresholds(tv);
00184
00185 myFilter->Update();
00186 dst = myFilter->GetOutput();
00187 dst->DisconnectPipeline();
00188
00189 return dst;
00190 }
00191
00192 VolumeVisualizationImagePreprocessor::LabelImage::Pointer
00193 VolumeVisualizationImagePreprocessor::RelabelComponents(LabelImage::Pointer src)
00194 {
00195 VVP_INFO << "Relabeling Components...";
00196
00197 LabelImage::Pointer dst = LabelImage::New();
00198
00199 typedef itk::RelabelComponentImageFilter< LabelImage, LabelImage > myFilterType;
00200
00201 myFilterType::Pointer myFilter = myFilterType::New();
00202
00203 myFilter->SetInput(src);
00204 myFilter->Update();
00205 dst = myFilter->GetOutput();
00206 dst->DisconnectPipeline();
00207
00208 return dst;
00209 }
00210
00211 VolumeVisualizationImagePreprocessor::BinImage::Pointer
00212 VolumeVisualizationImagePreprocessor::Dilate(BinImage::Pointer src)
00213 {
00214 VVP_INFO << "Dilating...";
00215
00216 BinImage::Pointer dst = BinImage::New();
00217
00218 typedef itk::BinaryDilateImageFilter< BinImage, BinImage,itk::BinaryBallStructuringElement< unsigned char, 3> > BinaryDilateImageType;
00219 BinaryDilateImageType::KernelType myKernel;
00220 myKernel.SetRadius(1);
00221 myKernel.CreateStructuringElement();
00222 BinaryDilateImageType::Pointer DilateFilter = BinaryDilateImageType::New();
00223 DilateFilter->SetInput(src);
00224 DilateFilter->SetKernel(myKernel);
00225 DilateFilter->SetDilateValue(1);
00226 DilateFilter->Update();
00227 dst = DilateFilter->GetOutput();
00228 dst->DisconnectPipeline();
00229
00230 return dst;
00231 }
00232
00233 VolumeVisualizationImagePreprocessor::BinImage::Pointer
00234 VolumeVisualizationImagePreprocessor::Erode(BinImage::Pointer src)
00235 {
00236 VVP_INFO << "Eroding...";
00237
00238 BinImage::Pointer dst = BinImage::New();
00239
00240 typedef itk::BinaryErodeImageFilter< BinImage, BinImage,itk::BinaryBallStructuringElement< unsigned char, 3> > BinaryErodeImageType;
00241 BinaryErodeImageType::KernelType myKernel;
00242 myKernel.SetRadius(1);
00243 myKernel.CreateStructuringElement();
00244 BinaryErodeImageType::Pointer ErodeFilter = BinaryErodeImageType::New();
00245 ErodeFilter->SetInput(src);
00246 ErodeFilter->SetKernel(myKernel);
00247 ErodeFilter->SetErodeValue(0);
00248 ErodeFilter->Update();
00249 dst = ErodeFilter->GetOutput();
00250 dst->DisconnectPipeline();
00251
00252 return dst;
00253 }
00254
00255
00256 VolumeVisualizationImagePreprocessor::CTImage::Pointer
00257 VolumeVisualizationImagePreprocessor::Gaussian(CTImage::Pointer src)
00258 {
00259 VVP_INFO << "Gaussian...";
00260
00261 typedef itk::DiscreteGaussianImageFilter< CTImage, CTImage> GaussianFilterType;
00262
00263 GaussianFilterType::Pointer gaussianFilter = GaussianFilterType::New();
00264 gaussianFilter->SetInput( src );
00265 gaussianFilter->SetVariance( 1 );
00266
00267
00268 gaussianFilter->SetMaximumKernelWidth ( 8 );
00269 gaussianFilter->UpdateLargestPossibleRegion();
00270
00271 CTImage::Pointer dst = gaussianFilter->GetOutput();
00272 dst->DisconnectPipeline();
00273
00274 return dst;
00275
00276 }
00277
00278 VolumeVisualizationImagePreprocessor::CTImage::Pointer VolumeVisualizationImagePreprocessor::Crop(VolumeVisualizationImagePreprocessor::CTImage::Pointer src )
00279 {
00280 VVP_INFO << "Cropping 16bit...";
00281
00282 typedef itk::RegionOfInterestImageFilter<CTImage,CTImage> FilterType;
00283
00284 FilterType::Pointer cropFilter = FilterType::New();
00285
00286 cropFilter->SetInput( src );
00287
00288 CTImage::RegionType region;
00289 CTImage::SizeType size;
00290 CTImage::IndexType index;
00291
00292 index.SetElement(0,m_MinX);
00293 index.SetElement(1,m_MinY);
00294 index.SetElement(2,m_MinZ);
00295
00296 size.SetElement(0,m_MaxX-m_MinX+1);
00297 size.SetElement(1,m_MaxY-m_MinY+1);
00298 size.SetElement(2,m_MaxZ-m_MinZ+1);
00299
00300 region.SetIndex(index);
00301 region.SetSize(size);
00302
00303 cropFilter->SetRegionOfInterest(region);
00304 cropFilter->Update();
00305
00306 CTImage::Pointer dst = cropFilter->GetOutput();
00307 dst->DisconnectPipeline();
00308
00309 return dst;
00310 }
00311
00312
00313
00314 VolumeVisualizationImagePreprocessor::BinImage::Pointer VolumeVisualizationImagePreprocessor::Crop(VolumeVisualizationImagePreprocessor::BinImage::Pointer src )
00315 {
00316 VVP_INFO << "Cropping 8bit...";
00317
00318 typedef itk::RegionOfInterestImageFilter<BinImage,BinImage> FilterType;
00319
00320 FilterType::Pointer cropFilter = FilterType::New();
00321
00322 cropFilter->SetInput( src );
00323
00324 BinImage::RegionType region;
00325 BinImage::SizeType size;
00326 BinImage::IndexType index;
00327
00328 index.SetElement(0,m_MinX);
00329 index.SetElement(1,m_MinY);
00330 index.SetElement(2,m_MinZ);
00331
00332 size.SetElement(0,m_MaxX-m_MinX+1);
00333 size.SetElement(1,m_MaxY-m_MinY+1);
00334 size.SetElement(2,m_MaxZ-m_MinZ+1);
00335
00336 region.SetIndex(index);
00337 region.SetSize(size);
00338
00339 cropFilter->SetRegionOfInterest(region);
00340 cropFilter->Update();
00341
00342 BinImage::Pointer dst = cropFilter->GetOutput();
00343 dst->DisconnectPipeline();
00344
00345 return dst;
00346 }
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 int mitk::VolumeVisualizationImagePreprocessor::GetHistogrammValueFromBottom( double part )
00361 {
00362 int unteren = total * part;
00363 for( int r = -32768 ; r <= 32767 ; r++ )
00364 if( (unteren -= histogramm[32768+(int)r]) <= 0 )
00365 return r;
00366 return 0;
00367 }
00368
00369
00370 int mitk::VolumeVisualizationImagePreprocessor::GetHistogrammValueFromTop( double part )
00371 {
00372 int oberen = total * part;
00373 for( int r = 32767 ; r >= -32768 ; r-- )
00374 if( (oberen -= histogramm[32768+(int)r]) <= 0 )
00375 return r;
00376 return 0;
00377 }
00378
00379
00380 void VolumeVisualizationImagePreprocessor::DetermineBoundingBox( BinImage::Pointer mask )
00381 {
00382 VVP_INFO << "determining Bounding Box...";
00383
00384 BinIteratorIndexType maskIt( mask, mask->GetRequestedRegion() );
00385
00386 maskIt.GoToBegin();
00387
00388 int totalMinX;
00389 int totalMinY;
00390 int totalMinZ;
00391
00392 int totalMaxX;
00393 int totalMaxY;
00394 int totalMaxZ;
00395
00396
00397 {
00398 m_MinX=m_MinY=m_MinZ = 1000000;
00399 m_MaxX=m_MaxY=m_MaxZ = -1000000;
00400
00401 totalMinX=totalMinY=totalMinZ = 1000000;
00402 totalMaxX=totalMaxY=totalMaxZ = -1000000;
00403 }
00404
00405 while ( ! maskIt.IsAtEnd() )
00406 {
00407 BinIteratorIndexType::IndexType idx = maskIt.GetIndex();
00408 int x=idx.GetElement(0);
00409 int y=idx.GetElement(1);
00410 int z=idx.GetElement(2);
00411
00412 if(x<totalMinX) totalMinX=x;
00413 if(y<totalMinY) totalMinY=y;
00414 if(z<totalMinZ) totalMinZ=z;
00415
00416 if(x>totalMaxX) totalMaxX=x;
00417 if(y>totalMaxY) totalMaxY=y;
00418 if(z>totalMaxZ) totalMaxZ=z;
00419
00420 if(maskIt.Get())
00421 {
00422 if(x<m_MinX) m_MinX=x;
00423 if(y<m_MinY) m_MinY=y;
00424 if(z<m_MinZ) m_MinZ=z;
00425
00426 if(x>m_MaxX) m_MaxX=x;
00427 if(y>m_MaxY) m_MaxY=y;
00428 if(z>m_MaxZ) m_MaxZ=z;
00429 }
00430 ++maskIt;
00431 }
00432
00433 int border = 3;
00434
00435 m_MinX -= border; if(m_MinX < totalMinX ) m_MinX = totalMinX;
00436 m_MinY -= border; if(m_MinY < totalMinY ) m_MinY = totalMinY;
00437 m_MinZ -= border; if(m_MinZ < totalMinZ ) m_MinZ = totalMinZ;
00438
00439 m_MaxX += border; if(m_MaxX > totalMaxX ) m_MaxX = totalMaxX;
00440 m_MaxY += border; if(m_MaxY > totalMaxY ) m_MaxY = totalMaxY;
00441 m_MaxZ += border; if(m_MaxZ > totalMaxZ ) m_MaxZ = totalMaxZ;
00442
00443 VVP_INFO << "Bounding box" << " m_MinX: " << m_MinX << " m_MaxX: " << m_MaxX
00444 << "\n m_MinY: " << m_MinY << " m_MaxY: " << m_MaxY
00445 << "\n m_MinZ: " << m_MinZ << " m_MaxZ: " << m_MaxZ;
00446
00447
00448 }
00449
00450 mitk::VolumeVisualizationImagePreprocessor::CTImage::Pointer VolumeVisualizationImagePreprocessor::Composite( CTImage::Pointer work,
00451 BinImage::Pointer mask,
00452 BinImage::Pointer dilated,
00453 BinImage::Pointer eroded)
00454 {
00455 VVP_INFO << "Compositing...";
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465 CTIteratorIndexType workIt( work, work->GetRequestedRegion() );
00466 BinIteratorType maskIt( mask, mask->GetRequestedRegion() );
00467 BinIteratorType dilateIt( dilated, dilated->GetRequestedRegion() );
00468 BinIteratorType erodeIt( eroded, eroded->GetRequestedRegion() );
00469
00470 workIt.GoToBegin();
00471 maskIt.GoToBegin();
00472 dilateIt.GoToBegin();
00473 erodeIt.GoToBegin();
00474
00475 double sum=0;
00476 int num=0;
00477
00478 double sumIn=0;
00479 int numIn=0;
00480
00481 int _min=32767,_max=-32768;
00482
00483 total=0;
00484 memset(histogramm,0,sizeof(int)*65536);
00485
00486 while ( ! ( workIt.IsAtEnd() || maskIt.IsAtEnd() || dilateIt.IsAtEnd() || erodeIt.IsAtEnd() ) )
00487 {
00488 int value = workIt.Get();
00489 unsigned char mask = maskIt.Get();
00490 unsigned char dilate = dilateIt.Get();
00491 unsigned char erode = erodeIt.Get();
00492
00493 if(mask != 0)
00494 {
00495 sumIn+=value;
00496 numIn++;
00497 histogramm[32768+(int)value]++;
00498 total++;
00499 }
00500
00501 if(erode != 0 && mask != 0 )
00502 {
00503 sum+=value;
00504 num++;
00505 if(value>_max) _max=value;
00506 if(value<_min) _min=value;
00507 }
00508
00509
00510 if(erode == 0 && dilate != 0 )
00511 {
00512 value = -1024;
00513
00514 }
00515 else if( erode != 0 && mask != 0 )
00516 {
00517
00518 }
00519 else
00520 {
00521 value = -2048;
00522 }
00523
00524 workIt.Set(value);
00525
00526 ++workIt;
00527 ++maskIt;
00528 ++dilateIt;
00529 ++erodeIt;
00530 }
00531
00532 VVP_INFO << "liver consists of " << total << " samples.";
00533
00534 m_GreatestStructureThreshold = GetHistogrammValueFromTop(0.20);
00535 m_EstimatedThreshold = GetHistogrammValueFromTop(0.10);
00536 m_MaxThreshold=GetHistogrammValueFromTop(0.001);
00537 m_MinThreshold=GetHistogrammValueFromBottom(0.20);
00538
00539 VVP_INFO << "threshold range: (" << m_MinThreshold << ";" << m_MaxThreshold << ") estimated vessel threshold: " << m_EstimatedThreshold ;
00540 VVP_INFO << "m_GreatestStructureThreshold: " << m_GreatestStructureThreshold;
00541
00542
00543
00544
00545
00546
00547 if(num>0)
00548 m_realSurfaceValue=sum/num;
00549 else
00550 m_realSurfaceValue=0;
00551
00552 if(numIn>0)
00553 m_realInLiverValue=sumIn/numIn;
00554 else
00555 m_realInLiverValue=0;
00556
00557 m_surfaceValue = _min - 40;
00558 m_OutOfLiverValue = m_surfaceValue - 40;
00559
00560
00561
00562 workIt.GoToBegin();
00563
00564
00565
00566
00567
00568
00569 while ( ! workIt.IsAtEnd() )
00570 {
00571 int value = workIt.Get();
00572
00573
00574 if(value == -1024 )
00575 {
00576 value = m_surfaceValue;
00577 }
00578 else if( value == -2048 )
00579 {
00580 value = m_OutOfLiverValue;
00581 }
00582 else
00583 {
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596 }
00597
00598 workIt.Set(value);
00599
00600 ++workIt;
00601
00602
00603 }
00604
00605
00606
00607 VVP_INFO << "OutOfLiver value: " << m_OutOfLiverValue;
00608 VVP_INFO << "surface value: " << m_surfaceValue;
00609 VVP_INFO << "real surface value: " << m_realSurfaceValue;
00610 VVP_INFO << "real inLiver value:" << m_realInLiverValue;
00611
00612 work->DisconnectPipeline();
00613
00614 return work;
00615 }
00616
00617
00618
00619 Image::Pointer
00620 VolumeVisualizationImagePreprocessor::Process(
00621 Image::Pointer m_originalCT, Image::Pointer m_originalLiverMask)
00622 {
00623 VVP_INFO << "Processing...";
00624
00625
00626 CTImage::Pointer CTImageWork = CTImage::New();
00627 CastToItkImage( m_originalCT, CTImageWork );
00628
00629
00630 BinImage::Pointer BinImageMask = BinImage::New();
00631 CastToItkImage( m_originalLiverMask, BinImageMask );
00632
00633 DetermineBoundingBox( BinImageMask );
00634
00635 if( m_MaxX < m_MinX
00636 || m_MaxY < m_MinY
00637 || m_MaxZ < m_MinZ )
00638 return 0;
00639
00640 CTImageWork = Gaussian(Crop( CTImageWork ));
00641 BinImageMask = Crop( BinImageMask );
00642
00643 CTImage::Pointer itkResult =Composite(CTImageWork,BinImageMask,Dilate(BinImageMask),Erode(BinImageMask));
00644
00645 mitk::Image::Pointer mitkResult= mitk::Image::New();
00646 mitk::CastToMitkImage( itkResult, mitkResult );
00647
00648 VVP_INFO << "Finished...";
00649
00650 return mitkResult;
00651 }
00652
00653 }