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 "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 {
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
00166 if ( !this->GetPixelData() ) return result;
00167
00168
00169 result->CreatePixelData( this->GetPixelData()->GetType() );
00170 TypedArray* data = result->GetPixelData().GetPtr();
00171
00172
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
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
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
00290 if ( ! success ) return false;
00291
00292
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
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
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
00427
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
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
00544 for ( int x=0; x < this->m_Dims[0]; ++x )
00545 {
00546
00547 Types::DataItem correctOverlap = 0;
00548
00549 pixelBufferTo[x] = pixelBufferFrom[x] * filterX[0];
00550
00551 for ( int t=1; t < filterXsize; ++t )
00552 {
00553
00554 if ( x >= t )
00555
00556 pixelBufferTo[x] += pixelBufferFrom[x-t] * filterX[t];
00557 else
00558
00559 correctOverlap += filterX[t];
00560
00561
00562 if ( x+t < this->m_Dims[0] )
00563 pixelBufferTo[x] += pixelBufferFrom[x+t] * filterX[t];
00564 else
00565 correctOverlap += filterX[t];
00566 }
00567
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
00598 pixelBufferTo[y] /= (1-correctOverlap);
00599 }
00600
00601
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
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
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
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
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;
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;
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
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 }