cmtkScalarImage.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2009 Torsten Rohlfing
00004 //
00005 //  Copyright 2004-2011 SRI International
00006 //
00007 //  This file is part of the Computational Morphometry Toolkit.
00008 //
00009 //  http://www.nitrc.org/projects/cmtk/
00010 //
00011 //  The Computational Morphometry Toolkit is free software: you can
00012 //  redistribute it and/or modify it under the terms of the GNU General Public
00013 //  License as published by the Free Software Foundation, either version 3 of
00014 //  the License, or (at your option) any later version.
00015 //
00016 //  The Computational Morphometry Toolkit is distributed in the hope that it
00017 //  will be useful, but WITHOUT ANY WARRANTY; without even the implied
00018 //  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 //  GNU General Public License for more details.
00020 //
00021 //  You should have received a copy of the GNU General Public License along
00022 //  with the Computational Morphometry Toolkit.  If not, see
00023 //  <http://www.gnu.org/licenses/>.
00024 //
00025 //  $Revision: 2741 $
00026 //
00027 //  $LastChangedDate: 2011-01-14 11:42:17 -0800 (Fri, 14 Jan 2011) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkScalarImage.h"
00034 
00035 #include <Base/cmtkMatrix.h>
00036 #include <Base/cmtkCubicSpline.h>
00037 #include <Base/cmtkSurfaceNormal.h>
00038 
00039 #include <System/cmtkException.h>
00040 
00041 #include <stdlib.h>
00042 #include <cassert>
00043 #include <math.h>
00044 
00045 namespace
00046 cmtk
00047 {
00048 
00051 
00052 ScalarImage::ScalarImage() :
00053   m_PixelData( NULL ),
00054   HasROI( false )
00055 {
00056   this->m_Dims[0] = this->m_Dims[1] = 0;
00057   this->m_NumberOfFrames = 1;
00058   this->m_ImageSlicePosition = this->m_ImageTiltAngle = 0;
00059   this->m_FrameToFrameSpacing = 0;
00060 }
00061 
00062 ScalarImage::ScalarImage
00063 ( const int dimsx, const int dimsy, const int numberOfFrames ) :
00064   HasROI( false )
00065 {
00066   this->m_Dims[0] = dimsx;
00067   this->m_Dims[1] = dimsy;
00068   this->m_NumberOfFrames = numberOfFrames;
00069   this->m_FrameToFrameSpacing = 0;
00070 
00071   this->m_PixelSize[0] = this->m_PixelSize[1] = 1;
00072 
00073   this->m_ImageSlicePosition = this->m_ImageTiltAngle = 0;
00074 }
00075 
00076 ScalarImage::ScalarImage
00077 ( const ScalarImage& source, 
00078   const int* roiFrom, const int* roiTo ) :
00079   HasROI( false )
00080 {
00081   this->SetDims( source.m_Dims );
00082   this->SetPixelSize( source.GetPixelSize() );
00083 
00084   this->SetNumberOfFrames( source.GetNumberOfFrames() );
00085   this->SetFrameToFrameSpacing( source.GetFrameToFrameSpacing() );
00086 
00087   this->SetImageOrigin( source.GetImageOrigin() );
00088   this->SetImageDirectionX( source.GetImageDirectionX() );
00089   this->SetImageDirectionY( source.GetImageDirectionY() );
00090   this->SetImageSlicePosition( source.GetImageSlicePosition() );
00091 
00092   if ( roiFrom && roiTo ) 
00093     {
00094     const Self::IndexType::ValueType dims[2] = { roiTo[0] - roiFrom[0], roiTo[1] - roiFrom[1] };
00095     this->SetDims( Self::IndexType( dims ) );
00096     
00097     this->m_ImageOrigin += ( roiFrom[0] * source.GetPixelSize( AXIS_X ) * source.GetImageDirectionX() );
00098     this->m_ImageOrigin += ( roiFrom[1] * source.GetPixelSize( AXIS_Y ) * source.GetImageDirectionY() );
00099     
00100     const TypedArray* sourceData = source.GetPixelData();
00101     if ( sourceData ) 
00102       {
00103       this->CreatePixelData( sourceData->GetType() );
00104       if ( sourceData->GetPaddingFlag() )
00105         this->m_PixelData->SetPaddingPtr( sourceData->GetPaddingPtr() );
00106       
00107       size_t offset = 0;
00108       for ( int y = roiFrom[1]; y < roiTo[1]; ++y ) 
00109         {
00110         sourceData->ConvertSubArray( this->m_PixelData->GetDataPtr( offset ), this->m_PixelData->GetType(), roiFrom[0] + y * source.m_Dims[AXIS_X], this->m_Dims[AXIS_X] );
00111         offset += this->m_Dims[AXIS_X];
00112         }
00113       }
00114     } 
00115   else
00116     { // if we're not cropping, preserve ROI.
00117     HasROI = source.HasROI;
00118     ROI = source.ROI;
00119     if ( source.GetPixelData() )
00120       this->SetPixelData( TypedArray::SmartPtr( source.GetPixelData()->Clone() ) );
00121     }
00122 }
00123 
00124 ScalarImage::ScalarImage
00125 ( const ScalarImage& source, const Self::RegionType& roi ) :
00126   HasROI( false )
00127 {
00128   this->SetDims( roi.To() - roi.From() );
00129   this->SetPixelSize( source.GetPixelSize() );
00130 
00131   this->SetNumberOfFrames( source.GetNumberOfFrames() );
00132   this->SetFrameToFrameSpacing( source.GetFrameToFrameSpacing() );
00133 
00134   this->SetImageOrigin( source.GetImageOrigin() );
00135   this->SetImageDirectionX( source.GetImageDirectionX() );
00136   this->SetImageDirectionY( source.GetImageDirectionY() );
00137   this->SetImageSlicePosition( source.GetImageSlicePosition() );
00138 
00139   this->m_ImageOrigin += ( roi.From()[0] * source.GetPixelSize( AXIS_X ) * source.GetImageDirectionX() );
00140   this->m_ImageOrigin += ( roi.From()[1] * source.GetPixelSize( AXIS_Y ) * source.GetImageDirectionY() );
00141   
00142   const TypedArray* sourceData = source.GetPixelData();
00143   if ( sourceData ) 
00144     {
00145     this->CreatePixelData( sourceData->GetType() );
00146     if ( sourceData->GetPaddingFlag() )
00147       this->m_PixelData->SetPaddingPtr( sourceData->GetPaddingPtr() );
00148     
00149     size_t offset = 0;
00150     for ( int y = roi.From()[1]; y < roi.To()[1]; ++y ) 
00151       {
00152       sourceData->ConvertSubArray( this->m_PixelData->GetDataPtr( offset ), this->m_PixelData->GetType(), roi.From()[0] + y * source.m_Dims[AXIS_X], this->m_Dims[0] );
00153       offset += this->m_Dims[0];
00154       }
00155     }
00156 }
00157 
00158 ScalarImage*
00159 ScalarImage::InterpolateFrom
00160 ( const ScalarImage* grid, const CoordinateMatrix3x3* matrix, const cmtk::Interpolators::InterpolationEnum interpolation ) const
00161 {
00162   int dimsX = grid->m_Dims[0], dimsY = grid->m_Dims[1];
00163   ScalarImage* result = new ScalarImage( dimsX, dimsY );
00164 
00165   // if we don;t have pixel data, don't interpolate
00166   if ( !this->GetPixelData() ) return result;
00167 
00168   // create pixel data of same type as ours
00169   result->CreatePixelData( this->GetPixelData()->GetType() );
00170   TypedArray* data = result->GetPixelData().GetPtr();
00171 
00172   // compute transformed region origin and pixel directions
00173   FixedVector<2,Types::Coordinate> origin;
00174   origin[0] = origin[1] = 0;
00175 
00176   FixedVector<2,Types::Coordinate> deltax;
00177   deltax[0] = grid->m_PixelSize[0];
00178   deltax[1] = 0;
00179 
00180   FixedVector<2,Types::Coordinate> deltay;
00181   deltay[0] = 0;
00182   deltay[1] = grid->m_PixelSize[1];
00183 
00184   matrix->Multiply( origin );
00185   origin[0] /= this->m_PixelSize[0];
00186   origin[1] /= this->m_PixelSize[1];
00187 
00188   matrix->Multiply( deltax );
00189   deltax[0] /= this->m_PixelSize[0];
00190   deltax[1] /= this->m_PixelSize[1];
00191   deltax[0] -= origin[0];
00192   deltax[1] -= origin[1];
00193 
00194   matrix->Multiply( deltay );
00195   deltay[0] /= this->m_PixelSize[0];
00196   deltay[1] /= this->m_PixelSize[1];
00197   deltay[0] -= origin[0];
00198   deltay[1] -= origin[1];
00199   
00200   Types::DataItem value;
00201   size_t offset = 0;
00202 
00203   switch ( interpolation )
00204     {
00205     default:
00206     case cmtk::Interpolators::LINEAR:
00207       for ( int y = 0; y < dimsY; ++y ) 
00208         {
00209         Types::Coordinate row[2] = { origin[0], origin[1] };
00210         for ( int x = 0; x < dimsX; ++x, ++offset ) 
00211           {
00212           if ( this->GetPixelAt( value, row[0], row[1] ) )
00213             data->Set( value, offset );
00214           else
00215             data->SetPaddingAt( offset );
00216           row[0] += deltax[0];
00217           row[1] += deltax[1];
00218           }
00219         origin[0] += deltay[0];
00220         origin[1] += deltay[1];
00221         }
00222       break;
00223     case cmtk::Interpolators::CUBIC:
00224       for ( int y = 0; y < dimsY; ++y ) 
00225         {
00226         Types::Coordinate row[2] = { origin[0], origin[1] };
00227         for ( int x = 0; x < dimsX; ++x, ++offset ) 
00228           {
00229           if ( this->GetPixelAtCubic( value, row[0], row[1] ) )
00230             data->Set( value, offset );
00231           else
00232             data->SetPaddingAt( offset );
00233           row[0] += deltax[0];
00234           row[1] += deltax[1];
00235           }
00236         origin[0] += deltay[0];
00237         origin[1] += deltay[1];
00238         }
00239       break;
00240     }
00241 
00242   return result;
00243 }
00244 
00245 void
00246 ScalarImage::ApplyBinaryMask
00247 ( const ScalarImage* maskImage, const bool invert )
00248 {
00249   const TypedArray* maskData = maskImage->GetPixelData();
00250   if ( ! maskData ) return;
00251   if ( ! this->m_PixelData ) return;
00252 
00253   const size_t numberOfPixels = this->m_PixelData->GetDataSize();
00254   for ( size_t idx = 0; idx < numberOfPixels; ++idx ) 
00255     {
00256     Types::DataItem maskValue;
00257     if ( maskData->Get( maskValue, idx ) ) 
00258       {
00259       if ( (maskValue == 0) ^ invert )
00260         this->m_PixelData->SetPaddingAt( idx );
00261       }
00262     }
00263 }
00264 
00265 bool 
00266 ScalarImage::GetPixelAt
00267 ( Types::DataItem& value, const Types::Coordinate i, const Types::Coordinate j ) const
00268 {
00269   // check if inside valid pixel index range
00270   if ( (i < 0) || (i >= this->m_Dims[0]-1) ) return false;
00271   if ( (j < 0) || (j >= this->m_Dims[1]-1) ) return false;
00272 
00273   // compute index
00274   const Types::Coordinate I = floor( i );
00275   const Types::Coordinate J = floor( j );
00276 
00277   size_t ofs = static_cast<size_t>( I + this->m_Dims[0] * J );
00278 
00279   Types::DataItem v00, v01, v10, v11;
00280   const bool success = 
00281     this->m_PixelData->Get( v00, ofs ) &&
00282     this->m_PixelData->Get( v10, ofs + 1 ) &&
00283     this->m_PixelData->Get( v01, ofs + this->m_Dims[0] ) &&
00284     this->m_PixelData->Get( v11, ofs + this->m_Dims[0] + 1 );
00285 
00286   const Types::Coordinate ii = i - I;
00287   const Types::Coordinate jj = j - J;
00288 
00289   // if any of the four lookups hit "Padding Data", return.
00290   if ( ! success ) return false;
00291 
00292   // compute final value by bilinear interpolation
00293   value = 
00294     (1.0 - jj) * ( (1.0 - ii) * v00 + ii * v10 ) + 
00295     jj * ( (1.0 - ii) * v01 + ii * v11 );
00296   
00297   return true;
00298 }
00299 
00300 bool 
00301 ScalarImage::GetPixelAtCubic
00302 ( Types::DataItem& value, const Types::Coordinate i, const Types::Coordinate j ) const
00303 {
00304   // check if inside valid pixel index range
00305   if ( (i < 1) || (i >= this->m_Dims[0]-2) ) return false;
00306   if ( (j < 1) || (j >= this->m_Dims[1]-2) ) return false;
00307 
00308   // compute index
00309   const Types::Coordinate I = floor( i );
00310   const Types::Coordinate J = floor( j );
00311 
00312   size_t ofs = static_cast<size_t>( (I-1) + this->m_Dims[0] * (J-1) );
00313 
00314   const Types::Coordinate ii = (i - I);
00315   const Types::Coordinate jj = (j - J);
00316 
00317   const Types::Coordinate spI[4] = 
00318     { CubicSpline::InterpSpline( 0, ii ),
00319       CubicSpline::InterpSpline( 1, ii ),
00320       CubicSpline::InterpSpline( 2, ii ),
00321       CubicSpline::InterpSpline( 3, ii ) };
00322 
00323   const Types::Coordinate spJ[4] = 
00324     { CubicSpline::InterpSpline( 0, jj ),
00325       CubicSpline::InterpSpline( 1, jj ),
00326       CubicSpline::InterpSpline( 2, jj ),
00327       CubicSpline::InterpSpline( 3, jj ) };
00328 
00329   const TypedArray* data = this->GetPixelData();
00330 
00331   value = 0;
00332   Types::DataItem item;
00333   for ( int j=0; j<4; ++j )
00334     {
00335     Types::DataItem value_j = 0;
00336     for ( int i=0; i<4; ++i ) 
00337       {
00338       if ( data->Get( item, ofs + i + j * this->m_Dims[0] ) )
00339         value_j += static_cast<Types::DataItem>( item * spI[i] );
00340       else
00341         return false;
00342       }
00343     value += static_cast<Types::DataItem>( value_j * spJ[j] );
00344     }
00345   
00346   return true;
00347 }
00348 
00349 ScalarImage::SpaceVectorType 
00350 ScalarImage::GetImageOrigin( const int frame ) const 
00351 {
00352   Self::SpaceVectorType origin;
00353   if ( this->m_NumberOfFrames > 1 ) 
00354     {
00355     origin = SurfaceNormal( this->m_ImageDirectionX, this->m_ImageDirectionY ).Get();
00356     origin *= (frame * this->m_FrameToFrameSpacing) / origin.RootSumOfSquares();
00357     origin += this->m_ImageOrigin;
00358     } 
00359   else
00360     {
00361     origin = this->m_ImageOrigin;
00362     }
00363   return origin;
00364 }
00365 
00366 ScalarImage* 
00367 ScalarImage::Clone() const
00368 {
00369   ScalarImage *newScalarImage = new ScalarImage( this->m_Dims[0], this->m_Dims[1] );
00370 
00371   newScalarImage->SetPixelSize( this->m_PixelSize );
00372   newScalarImage->SetImageOrigin( this->m_ImageOrigin );
00373   newScalarImage->SetImageDirectionX( this->m_ImageDirectionX );
00374   newScalarImage->SetImageDirectionY( this->m_ImageDirectionY );
00375   newScalarImage->SetImageSlicePosition( this->m_ImageSlicePosition );
00376 
00377   newScalarImage->SetPixelData( TypedArray::SmartPtr( this->m_PixelData->Clone() ) );
00378   
00379   return newScalarImage;
00380 }
00381 
00382 ScalarImage* 
00383 ScalarImage::Clone( const bool clonePixelData )
00384 {
00385   ScalarImage *newScalarImage = new ScalarImage( this->m_Dims[0], this->m_Dims[1] );
00386 
00387   newScalarImage->SetPixelSize( this->m_PixelSize );
00388   newScalarImage->SetImageOrigin( this->m_ImageOrigin );
00389   newScalarImage->SetImageDirectionX( this->m_ImageDirectionX );
00390   newScalarImage->SetImageDirectionY( this->m_ImageDirectionY );
00391   newScalarImage->SetImageSlicePosition( this->m_ImageSlicePosition );
00392   
00393   if ( clonePixelData )
00394     newScalarImage->SetPixelData( TypedArray::SmartPtr( this->m_PixelData->Clone() ) );
00395   else
00396     newScalarImage->SetPixelData( this->m_PixelData );
00397 
00398   return newScalarImage;
00399 }
00400 
00401 ScalarImage* 
00402 ScalarImage::Downsample
00403 ( const int factorX, int factorY, ScalarImage *const target ) const
00404 {
00405   if ( ! factorY ) factorY = factorX;
00406 
00407   assert( this->m_NumberOfFrames == 1 );
00408 
00409   ScalarImage *newScalarImage = target;
00410   if ( ! newScalarImage )
00411     newScalarImage = new ScalarImage( this->m_Dims[0] / factorX, this->m_Dims[1] / factorY );
00412   
00413   newScalarImage->SetPixelSize( this->m_PixelSize[0] * factorX, this->m_PixelSize[1] * factorY );
00414   
00415   Self::SpaceVectorType imageOrigin( this->m_ImageOrigin );
00416   imageOrigin += (0.5 * this->m_PixelSize[0] / this->m_ImageDirectionX.RootSumOfSquares()) * this->m_ImageDirectionX;
00417   imageOrigin += (0.5 * this->m_PixelSize[1] / this->m_ImageDirectionY.RootSumOfSquares()) * this->m_ImageDirectionY;
00418 
00419   newScalarImage->SetImageOrigin( imageOrigin );
00420   newScalarImage->SetImageDirectionX( this->m_ImageDirectionX );
00421   newScalarImage->SetImageDirectionY( this->m_ImageDirectionY );
00422   newScalarImage->SetImageSlicePosition( this->m_ImageSlicePosition );
00423   
00424   newScalarImage->CreatePixelData( this->m_PixelData->GetType() );
00425 
00426   // compensate for dimensions that connot be evenly divided by downsampling 
00427   // factor.
00428   const int dimsY = (this->m_Dims[1] / factorY) * factorY;
00429   const int dimsX = (this->m_Dims[0] / factorX) * factorX;
00430   const Types::DataItem factorXY = 1.0 / (factorX * factorY);
00431 
00432   int j = 0;
00433   for ( int y = 0; y < dimsY; y += factorY, ++j ) 
00434     {
00435     int i = 0;
00436     for ( int x = 0; x < dimsX; x += factorX, ++i ) 
00437       {
00438       Types::DataItem pixel = 0;
00439       for ( int yy = 0; yy < factorY; ++yy )
00440         for ( int xx = 0; xx < factorX; ++xx )
00441           pixel += this->GetPixelAt( x + xx, y + yy );
00442       
00443       newScalarImage->SetPixelAt( i, j, pixel * factorXY );
00444       }
00445     }
00446   return newScalarImage;  
00447 }
00448 
00449 TypedArray::SmartPtr
00450 ScalarImage::GetMedianFiltered( const byte range ) const
00451 {
00452   if ( !this->m_PixelData )
00453     throw( Exception( "No image data in ScalarImage::GetMedianFiltered()" ) );
00454 
00455   TypedArray::SmartPtr result = TypedArray::Create( this->m_PixelData->GetType(), this->m_PixelData->GetDataSize() );
00456 
00457   Types::DataItem *sort = Memory::AllocateArray<Types::DataItem>( range * range * range );
00458 
00459   int delta = (range-1) / 2;
00460   int offset = 0;
00461   for ( int y = 0; y < this->m_Dims[1]; ++y )
00462     for ( int x = 0; x < this->m_Dims[0]; ++x, ++offset ) 
00463       {
00464       const int xFrom = ( x > delta ) ? ( x - delta ) : 0;
00465       const int yFrom = ( y > delta ) ? ( y - delta ) : 0;
00466       const int xTo = std::min<int>( x+delta+1, this->m_Dims[0] );
00467       const int yTo = std::min<int>( y+delta+1, this->m_Dims[1] );
00468       
00469       int source = 0;
00470       for ( int yy = yFrom; yy < yTo; ++yy )
00471         for ( int xx = xFrom; xx < xTo; ++xx, ++source ) 
00472           {
00473           this->m_PixelData->Get( sort[source], xx + this->m_Dims[0] * yy );
00474           }
00475       
00476 #ifdef CMTK_DATA_FLOAT  
00477       qsort( sort, source, sizeof( *sort ), MathUtil::CompareFloat );
00478 #else
00479       qsort( sort, source, sizeof( *sort ), MathUtil::CompareDouble );
00480 #endif
00481 
00482       if ( source % 2 )
00483         result->Set( sort[source/2], offset );
00484       else
00485         result->Set( static_cast<Types::DataItem>( ( 0.5 * (sort[source/2] + sort[source/2-1]) ) ), offset );
00486     }
00487 
00488   Memory::DeleteArray( sort );
00489 
00490   return result;
00491 }
00492 
00493 TypedArray::SmartPtr
00494 ScalarImage::GetGaussFiltered( const Types::Coordinate stdDev ) const
00495 {
00496   const Types::Coordinate stdDevPixelX = stdDev / this->m_PixelSize[0];
00497   const Types::Coordinate stdDevPixelY = stdDev / this->m_PixelSize[1];
00498 
00499   const size_t stdDevDiscreteX = static_cast<size_t>( ceil( stdDevPixelX ) );
00500   const size_t stdDevDiscreteY = static_cast<size_t>( ceil( stdDevPixelY ) );
00501 
00502   const size_t filterLengthX = std::min<size_t>( this->m_Dims[0], 3 * stdDevDiscreteX + 1 );
00503   const size_t filterLengthY = std::min<size_t>( this->m_Dims[1], 3 * stdDevDiscreteY + 1 );
00504 
00505   std::vector<Types::DataItem> filterX( filterLengthX );
00506   for ( size_t x=0; x < filterLengthX; ++x ) 
00507     {
00508     filterX[x] = 1.0/(sqrt(2*M_PI) * stdDevPixelX) * exp( -MathUtil::Square( 1.0 * x / stdDevPixelX ) / 2 );
00509     }
00510   
00511   std::vector<Types::DataItem> filterY( filterLengthY );
00512   for ( size_t y=0; y < filterLengthY; ++y ) 
00513     {
00514     filterY[y] = 1.0/(sqrt(2*M_PI) * stdDevPixelY) * exp( -MathUtil::Square( 1.0 * y / stdDevPixelY ) / 2);
00515     }
00516   
00517   return this->GetFilteredData( filterX, filterY );
00518 }
00519 
00520 TypedArray::SmartPtr
00521 ScalarImage::GetFilteredData
00522 ( const std::vector<Types::DataItem>& filterX, const std::vector<Types::DataItem>& filterY ) const
00523 {
00524   if ( !this->m_PixelData )
00525     throw( Exception( "No image data in ScalarImage::GetFilteredData()" ) );
00526 
00527   const int filterXsize = filterX.size();
00528   const int filterYsize = filterY.size();
00529 
00530   TypedArray::SmartPtr result = TypedArray::Create( this->m_PixelData->GetType(), this->m_PixelData->GetDataSize() );
00531   
00532   size_t maxDim = std::max( this->m_Dims[0], this->m_Dims[1] );
00533   std::vector<Types::DataItem> pixelBufferFrom( maxDim );
00534   std::vector<Types::DataItem> pixelBufferTo( maxDim );
00535 
00536   for ( int y=0; y < this->m_Dims[1]; ++y ) 
00537     {
00538     // copy row data to buffer
00539     for ( int x=0; x < this->m_Dims[0]; ++x )
00540       if ( !this->m_PixelData->Get( pixelBufferFrom[x], x+y*this->m_Dims[0] ) ) 
00541         pixelBufferFrom[x] = 0;
00542     
00543     // convolve row with filter
00544     for ( int x=0; x < this->m_Dims[0]; ++x ) 
00545       {
00546       // this keeps track of outside FOV data
00547       Types::DataItem correctOverlap = 0;
00548       // central element first to initialize target value
00549       pixelBufferTo[x] = pixelBufferFrom[x] * filterX[0];
00550       // now convolve side elements
00551       for ( int t=1; t < filterXsize; ++t ) 
00552         {
00553         // is x-t still inside the image?
00554         if ( x >= t )
00555           // yes: convolve
00556           pixelBufferTo[x] += pixelBufferFrom[x-t] * filterX[t];
00557         else
00558           // no: save missing contribution for later
00559           correctOverlap += filterX[t];
00560 
00561         // same for x+t:
00562         if ( x+t < this->m_Dims[0] )
00563           pixelBufferTo[x] += pixelBufferFrom[x+t] * filterX[t];
00564         else
00565           correctOverlap += filterX[t];
00566       }
00567       // correct value scaling for all missing (outside) elements
00568       pixelBufferTo[x] /= (1-correctOverlap);
00569     }
00570     
00571     for ( int x=0; x < this->m_Dims[0]; ++x )
00572       result->Set( pixelBufferTo[x], x+y*this->m_Dims[0] );
00573   }
00574 
00575   for ( int x=0; x < this->m_Dims[0]; ++x ) 
00576     {
00577     for ( int y=0; y < this->m_Dims[1]; ++y )
00578       if ( !result->Get( pixelBufferFrom[y], x+this->m_Dims[0]*y ) ) 
00579         pixelBufferFrom[y] = 0;
00580 
00581     for ( int y=0; y < this->m_Dims[1]; ++y ) 
00582       {
00583       Types::DataItem correctOverlap = 0;
00584       pixelBufferTo[y] = pixelBufferFrom[y] * filterY[0];
00585       for ( int t=1; t < filterYsize; ++t ) 
00586         {
00587         if ( y >= t )
00588           pixelBufferTo[y] += pixelBufferFrom[y-t] * filterY[t];
00589         else
00590           correctOverlap += filterY[t];
00591         
00592         if ( y+t < this->m_Dims[1] )
00593           pixelBufferTo[y] += pixelBufferFrom[y+t] * filterY[t];
00594         else
00595           correctOverlap += filterY[t];
00596       }
00597       // correct value scaling for all missing (outside) elements
00598       pixelBufferTo[y] /= (1-correctOverlap);
00599     }
00600     
00601     // write back convolved data
00602     for ( int y=0; y < this->m_Dims[1]; ++y )
00603       result->Set( pixelBufferTo[y], x+this->m_Dims[0]*y );
00604   }
00605 
00606   return result;
00607 }
00608 
00609 TypedArray::SmartPtr
00610 ScalarImage::GetSobel2DFiltered() const
00611 {
00612   if ( !this->m_PixelData )
00613     throw( Exception( "No image data in ScalarImage::GetSobel2DFiltered()" ) );
00614 
00615   TypedArray::SmartPtr result = TypedArray::Create( this->m_PixelData->GetType(), this->m_PixelData->GetDataSize() );
00616   
00617   Types::DataItem fov[3][3];
00618   size_t offset = 0;
00619 
00620   for ( int y = 0; y < this->m_Dims[1]; ++y )
00621     for ( int x = 0; x < this->m_Dims[0]; ++x, ++offset ) 
00622       {
00623       Types::DataItem value = 0;
00624       if ( x && y && (x<this->m_Dims[0]-1) && (y<this->m_Dims[1]-1) ) 
00625         {
00626         for ( int dy=0; dy<3; ++dy )
00627           for ( int dx=0; dx<3; ++dx )
00628             this->m_PixelData->Get( fov[dx][dy], x-1+dx+ this->m_Dims[0] * ( y-1+dy ) );
00629         
00630         value = 
00631           sqrt( MathUtil::Square( fov[0][0] - fov[2][0] + 2 * ( fov[0][1] - fov[2][1] ) + fov[0][2] - fov[2][2] ) +
00632                 MathUtil::Square( fov[0][0] - fov[0][2] + 2 * ( fov[1][0] - fov[1][2] ) + fov[2][0] - fov[2][2] ) );
00633         }
00634       result->Set( value, offset );
00635       }
00636   
00637   return result;
00638 }
00639 
00640 TypedArray::SmartPtr
00641 ScalarImage::GetSobelFiltered( const bool horizontal, const bool absolute ) 
00642   const
00643 {
00644   if ( !this->m_PixelData )
00645     throw( Exception( "No image data in ScalarImage::GetSobelFiltered()" ) );
00646 
00647   TypedArray::SmartPtr result = ( absolute ) ?
00648     TypedArray::Create( GetUnsignedDataType( this->m_PixelData->GetType() ), this->m_PixelData->GetDataSize() ) :
00649     TypedArray::Create( GetSignedDataType( this->m_PixelData->GetType() ), this->m_PixelData->GetDataSize() );
00650   
00651   Types::DataItem fov[3][3];
00652   size_t offset = 0;
00653 
00654   if ( horizontal )
00655     for ( int y = 0; y < this->m_Dims[1]; ++y )
00656       for ( int x = 0; x < this->m_Dims[0]; ++x, ++offset ) 
00657         {
00658         Types::DataItem value = 0;
00659         if ( x && y && (x<this->m_Dims[0]-1) && (y<this->m_Dims[1]-1) ) 
00660           {
00661           for ( byte dy=0; dy<3; ++dy )
00662             for ( byte dx=0; dx<3; ++dx )
00663               this->m_PixelData->Get( fov[dx][dy], x-1+dx+ this->m_Dims[0] * ( y-1+dy ) );
00664           
00665           value = fov[2][0] - fov[0][0] + 2 * ( fov[2][1] - fov[0][1] ) + fov[2][2] - fov[0][2];
00666           
00667           if ( absolute ) value = fabs( value );
00668           }
00669         result->Set( value, offset );
00670         }
00671   else
00672     for ( int y = 0; y < this->m_Dims[1]; ++y )
00673       for ( int x = 0; x < this->m_Dims[0]; ++x, ++offset ) 
00674         {
00675         Types::DataItem value = 0;
00676         if ( x && y && (x<this->m_Dims[0]-1) && (y<this->m_Dims[1]-1) ) 
00677           {
00678           for ( byte dy=0; dy<3; ++dy )
00679             for ( byte dx=0; dx<3; ++dx )
00680               this->m_PixelData->Get( fov[dx][dy], x-1+dx+ this->m_Dims[0] * ( y-1+dy ) );
00681           
00682           value = fov[0][0] - fov[0][2] + 2 * ( fov[1][0] - fov[1][2] ) + fov[2][0] - fov[2][2];
00683           
00684           if ( absolute ) value = fabs( value );
00685           }
00686         result->Set( value, offset );
00687         }
00688   
00689   return result;
00690 }
00691 
00692 TypedArray::SmartPtr
00693 ScalarImage::GetLaplace2DFiltered() const
00694 {
00695   if ( !this->m_PixelData )
00696     throw( Exception( "No image data in ScalarImage::GetLaplace2DFiltered()" ) );
00697 
00698   TypedArray::SmartPtr result = TypedArray::Create( this->m_PixelData->GetType(), this->m_PixelData->GetDataSize() );
00699   
00700   Types::DataItem fov[3][3];
00701   size_t offset = 0;
00702 
00703   for ( int y = 0; y < this->m_Dims[1]; ++y )
00704     for ( int x = 0; x < this->m_Dims[0]; ++x, ++offset ) 
00705       {
00706       Types::DataItem value = 0;
00707       if ( x && y && (x<this->m_Dims[0]-1) && (y<this->m_Dims[1]-1) ) 
00708         {
00709         for ( int dy=0; dy<3; ++dy )
00710           for ( int dx=0; dx<3; ++dx )
00711             this->m_PixelData->Get( fov[dx][dy], x-1+dx+ this->m_Dims[0] * ( y-1+dy ) );
00712         
00713         value = fov[0][1] + fov[2][1] + fov[1][0] + fov[1][2] + fov[0][0] + fov[0][2] + fov[2][0] + fov[2][2] - 8 * fov[1][1];
00714         }
00715       result->Set( value, offset );
00716       }
00717   
00718   return result;
00719 }
00720 
00721 ScalarImage* operator- 
00722 ( const ScalarImage& image0, const ScalarImage& image1 )
00723 {
00724   ScalarImage *result = new ScalarImage( image0.m_Dims[0], image0.m_Dims[1] );
00725 
00726   const TypedArray *data0 = image0.GetPixelData();
00727   const TypedArray *data1 = image1.GetPixelData();
00728 
00729   size_t numberOfPixels = image0.GetNumberOfPixels();
00730 
00731   TypedArray::SmartPtr pixelData( TypedArray::Create( GetSignedDataType( data0->GetType() ), numberOfPixels ) );
00732 
00733   Types::DataItem pixel0, pixel1;
00734   for ( size_t idx = 0; idx < numberOfPixels; ++idx ) 
00735     {
00736     if ( data0->Get( pixel0, idx ) && data1->Get( pixel1, idx ) ) 
00737       {
00738       pixelData->Set( pixel0 - pixel1, idx );
00739       } 
00740     else
00741       {
00742       pixelData->SetPaddingAt( idx );
00743       }
00744     }
00745   
00746   result->SetPixelData( pixelData );
00747   
00748   return result;
00749 }
00750 
00751 ScalarImage&
00752 ScalarImage::operator-=
00753 ( const ScalarImage& source )
00754 {
00755   TypedArray *data0 = this->GetPixelData().GetPtr();
00756   const TypedArray *data1 = source.GetPixelData();
00757 
00758   size_t numberOfPixels = this->GetNumberOfPixels();
00759   Types::DataItem pixel0, pixel1;
00760   for ( size_t idx = 0; idx < numberOfPixels; ++idx ) 
00761     {
00762     if ( data0->Get( pixel0, idx ) && data1->Get( pixel1, idx ) ) 
00763       {
00764       data0->Set( pixel0 - pixel1, idx );
00765       } 
00766     else
00767       {
00768       data0->SetPaddingAt( idx );
00769       }
00770     }
00771   
00772   return *this;
00773 }
00774 
00775 void ScalarImage::Mirror( const bool horizontal, const bool vertical )
00776 {
00777   if ( vertical ) 
00778     {
00779     for ( int y = 0; y < this->m_Dims[1]/2; ++y ) 
00780       {
00781       this->m_PixelData->BlockSwap( y * this->m_Dims[0], (this->m_Dims[1]-y-1) * this->m_Dims[0], this->m_Dims[0] );
00782       }
00783     this->m_ImageOrigin = this->m_ImageOrigin + ((this->m_Dims[1]-1) * this->m_PixelSize[1] / this->m_ImageDirectionY.RootSumOfSquares()) * this->m_ImageDirectionY;
00784     this->m_ImageDirectionY *= (-1.0);
00785     }
00786   
00787   if ( horizontal ) 
00788     {
00789     for ( int y = 0; y < this->m_Dims[1]; ++y ) 
00790       {
00791       this->m_PixelData->BlockReverse( y * this->m_Dims[0], this->m_Dims[0] );
00792       }
00793     this->m_ImageOrigin = this->m_ImageOrigin + ((this->m_Dims[1]-1) * this->m_PixelSize[0] / this->m_ImageDirectionX.RootSumOfSquares()) * this->m_ImageDirectionX;
00794     this->m_ImageDirectionX *= (-1.0);
00795     }
00796 }
00797 
00798 void
00799 ScalarImage::AdjustToIsotropic
00800 ( const Types::Coordinate pixelSize, const bool interpolate )
00801 {
00802   if ( pixelSize < this->m_PixelSize[0] )
00803     {
00804     // fake pixel size Y, then simply adjust aspect ratio
00805     const Types::Coordinate savePixelSizeY = this->m_PixelSize[1];
00806     this->m_PixelSize[1] = pixelSize;
00807     this->AdjustAspectX( interpolate );
00808     this->m_PixelSize[1] = savePixelSizeY;    
00809     }
00810 
00811   // now we can simply adjust aspect again in the other dimension
00812   if ( this->m_PixelSize[0] < this->m_PixelSize[1] )
00813     {
00814     this->AdjustAspectY( interpolate );
00815     }
00816 }
00817 
00818 void
00819 ScalarImage::AdjustAspect( const bool interpolate )
00820 {
00821   if ( this->m_PixelSize[0] < this->m_PixelSize[1] )
00822     this->AdjustAspectY( interpolate );
00823   else
00824     if ( this->m_PixelSize[0] > this->m_PixelSize[1] )
00825       this->AdjustAspectX( interpolate );
00826 }
00827 
00828 void
00829 ScalarImage::AdjustAspectY( const bool interpolate )
00830 {
00831   if ( this->m_Dims[0] < 2 )
00832     return;
00833   
00834   const int newDimsY = static_cast<int>( (this->m_Dims[1]-1) * this->m_PixelSize[1]/this->m_PixelSize[0] ) + 1;
00835   
00836   TypedArray::SmartPtr scaled = TypedArray::Create( this->m_PixelData->GetType(), this->m_Dims[0] * newDimsY );
00837   
00838   if ( interpolate ) 
00839     {
00840     // with interpolation
00841     std::vector<Types::DataItem> row0( this->m_Dims[0] ), row1( this->m_Dims[0] );
00842     this->m_PixelData->GetSubArray( &(row0[0]), 0, this->m_Dims[0] );
00843     this->m_PixelData->GetSubArray( &(row1[0]), this->m_Dims[0], this->m_Dims[0] );
00844     
00845     Types::Coordinate scanLine = 0;
00846     int ySource = 0;
00847     size_t offset = 0;
00848     for ( int y = 0; y < newDimsY; ++y ) 
00849       {
00850       Types::Coordinate factor = scanLine / this->m_PixelSize[1];
00851       for ( int x = 0; x < this->m_Dims[0]; ++x, ++offset ) 
00852         {
00853         scaled->Set( (1.0 - factor ) * row0[x] + factor * row1[x], offset );
00854         }
00855       
00856       scanLine += this->m_PixelSize[0];
00857       while ( (ySource < this->m_Dims[1]) && (scanLine >= this->m_PixelSize[1]) ) 
00858         {
00859         ++ySource;
00860         row0 = row1;
00861         this->m_PixelData->GetSubArray( &(row1[0]), (1+ySource) * this->m_Dims[0], this->m_Dims[0] );
00862         scanLine -= this->m_PixelSize[1];
00863         }
00864       }
00865     } 
00866   else
00867     {
00868     // no interpolation; can do with simply block copying
00869     char *scaledPtr = static_cast<char*>( scaled->GetDataPtr() );
00870     const char *pixelPtr = static_cast<char*>( this->m_PixelData->GetDataPtr() );
00871     
00872     Types::Coordinate scanLineOffset = this->m_PixelSize[1] / 2;
00873     Types::Coordinate scanLine = scanLineOffset; // correct offset for NN
00874     int ySource = 0;
00875     for ( int y = 0; y < newDimsY; ++y ) 
00876       {
00877       memcpy( scaledPtr, pixelPtr, scaled->GetItemSize() * this->m_Dims[0] );
00878       scanLine += this->m_PixelSize[0];
00879       while ( (ySource < this->m_Dims[1]) && (scanLine >= this->m_PixelSize[1]) ) 
00880         {
00881         ++ySource;
00882         pixelPtr += this->m_PixelData->GetItemSize() * this->m_Dims[0];
00883         scanLine -= this->m_PixelSize[1];
00884         }
00885       scaledPtr += scaled->GetItemSize() * this->m_Dims[0];
00886       }
00887     }
00888   
00889   this->m_PixelSize[1] = this->m_PixelSize[0];
00890   this->m_Dims[1] = newDimsY;
00891   this->SetPixelData( scaled );
00892 }
00893 
00894 void
00895 ScalarImage::AdjustAspectX( const bool interpolate )
00896 {
00897   if ( this->m_Dims[1] < 2 )
00898     return;
00899   
00900   const int newDimsX = static_cast<int>( (this->m_Dims[0]-1) * this->m_PixelSize[0]/this->m_PixelSize[1] ) + 1;
00901   
00902   TypedArray::SmartPtr scaled = TypedArray::Create( this->m_PixelData->GetType(), newDimsX * this->m_Dims[1] );
00903   
00904   if ( interpolate ) 
00905     {
00906     std::vector<Types::Coordinate> factor( newDimsX );
00907     std::vector<int> fromPixel( newDimsX );
00908     
00909     Types::Coordinate scanLine = 0;
00910     int xSource = 0;
00911     for ( int x = 0; x < newDimsX; ++x ) 
00912       {
00913       fromPixel[x] = xSource;
00914       factor[x] = scanLine / this->m_PixelSize[0];
00915       scanLine += this->m_PixelSize[1];
00916       while ( (xSource < this->m_Dims[0]) && (scanLine >= this->m_PixelSize[0]) ) 
00917         {
00918         ++xSource;
00919         scanLine -= this->m_PixelSize[0];
00920         }
00921       }
00922     
00923     std::vector<Types::DataItem> rowFrom( this->m_Dims[0] );
00924     size_t offset = 0;
00925     for ( int y = 0; y < this->m_Dims[1]; ++y ) 
00926       {
00927       this->m_PixelData->GetSubArray( &(rowFrom[0]), y * this->m_Dims[0], this->m_Dims[0] );
00928       for ( int x = 0; x < newDimsX; ++x, ++offset ) 
00929         {
00930         scaled->Set( (1.0 - factor[x] ) * rowFrom[fromPixel[x]] + factor[x] * rowFrom[fromPixel[x]+1], offset );
00931         }
00932       }
00933     } 
00934   else
00935     {
00936     Types::Coordinate scanLine = this->m_PixelSize[0] / 2; // correct offset for NN
00937     int xSource = 0;
00938     std::vector<int> fromPixel( newDimsX );
00939     for ( int x = 0; x < newDimsX; ++x ) 
00940       {
00941       fromPixel[x] = xSource * scaled->GetItemSize();
00942       scanLine += this->m_PixelSize[1];
00943       while ( (xSource < this->m_Dims[0]) && (scanLine >= this->m_PixelSize[0]) ) 
00944         {
00945         ++xSource;
00946         scanLine -= this->m_PixelSize[0];
00947         }
00948       }
00949     
00950     // no interpolation; can do with simply block copying
00951     char *scaledPtr = static_cast<char*>( scaled->GetDataPtr() );
00952     const char *pixelPtr = static_cast<char*>( this->m_PixelData->GetDataPtr() );
00953     
00954     for ( int y = 0; y < this->m_Dims[1]; ++y ) 
00955       {
00956       for ( int x = 0; x < newDimsX; ++x ) 
00957         {
00958         memcpy( scaledPtr, pixelPtr+fromPixel[x], scaled->GetItemSize() );
00959         scaledPtr += scaled->GetItemSize();
00960         }
00961       pixelPtr += scaled->GetItemSize() * this->m_Dims[0];
00962       }
00963     }
00964   
00965   this->m_PixelSize[0] = this->m_PixelSize[1];
00966   this->m_Dims[0] = newDimsX;
00967   this->SetPixelData( scaled );
00968 }
00969 
00970 void
00971 ScalarImage::ProjectPixel
00972 ( const Self::SpaceVectorType& v, int& i, int& j ) const
00973 {
00974   Self::SpaceVectorType p(v);
00975   p -= this->m_ImageOrigin;
00976   
00977   i = MathUtil::Round( ( p * this->m_ImageDirectionX ) / ( this->m_ImageDirectionX.SumOfSquares() * this->m_PixelSize[0] ) );
00978   j = MathUtil::Round( ( p * this->m_ImageDirectionY ) / ( this->m_ImageDirectionY.SumOfSquares() * this->m_PixelSize[1] ) );
00979 }
00980 
00981 void 
00982 ScalarImage::Print() const
00983 {
00984   StdErr.printf( "ScalarImage at %p\n", this );
00985 
00986   StdErr.indent();
00987   StdErr.printf( "Dimensions: [%d,%d]\n", this->m_Dims[0], this->m_Dims[1] );
00988   StdErr.printf( "Pixel size: [%f,%f]\n", this->m_PixelSize[0], this->m_PixelSize[1] );
00989   StdErr.printf( "Origin: [%f,%f,%f]\n", this->m_ImageOrigin[0], this->m_ImageOrigin[1], this->m_ImageOrigin[2] );
00990 
00991   StdErr.printf( "DirectionX: [%f,%f,%f]\n", this->m_ImageDirectionX[0], this->m_ImageDirectionX[1], this->m_ImageDirectionX[2] );
00992   StdErr.printf( "DirectionY: [%f,%f,%f]\n", this->m_ImageDirectionY[0], this->m_ImageDirectionY[1], this->m_ImageDirectionY[2] );
00993   StdErr.unindent();
00994 }
00995 
00996 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines