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 "cmtkDataGrid.h"
00034
00035 #include <stdlib.h>
00036
00037 #include <System/cmtkConsole.h>
00038 #include <System/cmtkProgress.h>
00039
00040 namespace
00041 cmtk
00042 {
00043
00046
00047 const DataGrid::RegionType
00048 DataGrid::GetWholeImageRegion() const
00049 {
00050 const int zeroes[3] = {0,0,0};
00051 return Self::RegionType( Self::IndexType( zeroes ), Self::IndexType( this->m_Dims ) );
00052 }
00053
00054 TypedArray::SmartPtr
00055 DataGrid::CreateDataArray( const ScalarDataType dataType, const bool setToZero )
00056 {
00057 TypedArray::SmartPtr data( TypedArray::Create( dataType, this->GetNumberOfPixels() ) );
00058 if ( setToZero )
00059 data->ClearArray();
00060 this->SetData( data );
00061 return data;
00062 }
00063
00064 DataGrid*
00065 DataGrid::GetDownsampledAndAveraged( const int (&downsample)[3] ) const
00066 {
00067 const int newDims[3] = { (this->m_Dims[0]-1) / downsample[0] + 1, (this->m_Dims[1]-1) / downsample[1] + 1, (this->m_Dims[2]-1) / downsample[2] + 1 };
00068
00069 DataGrid* newDataGrid = new DataGrid;
00070 newDataGrid->SetDims( Self::IndexType( newDims ) );
00071
00072 const TypedArray* thisData = this->GetData();
00073 if ( thisData )
00074 {
00075 TypedArray::SmartPtr newData = TypedArray::Create( thisData->GetType(), newDataGrid->GetNumberOfPixels() );
00076
00077 #pragma omp parallel for
00078 for ( int z = 0; z < newDims[2]; ++z )
00079 {
00080 size_t toOffset = z * newDims[0] * newDims[1];
00081 int oldZ = z * downsample[2];
00082 int oldY = 0;
00083 for ( int y = 0; y < newDims[1]; ++y, oldY += downsample[1] )
00084 {
00085 int oldX = 0;
00086 for ( int x = 0; x < newDims[0]; ++x, oldX += downsample[0], ++toOffset )
00087 {
00088 Types::DataItem sum = 0;
00089 int count = 0;
00090 for ( int zz = 0; (zz < downsample[2]) && (oldZ+zz<this->m_Dims[2]); ++zz )
00091 {
00092 const size_t ofsZ = (oldZ+zz)*this->nextK;
00093 for ( int yy = 0; (yy < downsample[1]) && (oldY+yy<this->m_Dims[1]); ++yy )
00094 {
00095 const size_t ofsYZ = ofsZ + (oldY+yy)*this->nextJ;
00096 for ( int xx = 0; (xx < downsample[0]) && (oldX+xx<this->m_Dims[0]); ++xx )
00097 {
00098 Types::DataItem value;
00099 if ( thisData->Get( value, (oldX+xx) + ofsYZ ) )
00100 {
00101 sum += value;
00102 ++count;
00103 }
00104 }
00105 }
00106 }
00107 if ( count )
00108 {
00109 newData->Set( sum / count, toOffset );
00110 }
00111 else
00112 {
00113 newData->SetPaddingAt( toOffset );
00114 }
00115 }
00116 }
00117 }
00118 newDataGrid->SetData( TypedArray::SmartPtr( newData ) );
00119 }
00120
00121 newDataGrid->m_MetaInformation[META_IMAGE_ORIENTATION] = this->m_MetaInformation[META_IMAGE_ORIENTATION];
00122 newDataGrid->m_MetaInformation[META_IMAGE_ORIENTATION_ORIGINAL] = this->m_MetaInformation[META_IMAGE_ORIENTATION_ORIGINAL];
00123
00124 return newDataGrid;
00125 }
00126
00127 const DataGrid::SmartPtr
00128 DataGrid::GetReoriented( const char* newOrientation ) const
00129 {
00130 std::string curOrientation = this->m_MetaInformation[META_IMAGE_ORIENTATION];
00131 if ( curOrientation.length() != 3 )
00132 {
00133 curOrientation = std::string( AnatomicalOrientation::ORIENTATION_STANDARD );
00134 }
00135
00136 if ( !newOrientation )
00137 {
00138 newOrientation = AnatomicalOrientation::ORIENTATION_STANDARD;
00139 }
00140
00141
00142 AnatomicalOrientation::PermutationMatrix pmatrix( this->m_Dims, curOrientation, newOrientation );
00143
00144 Self::IndexType newDims = pmatrix.GetPermutedArray( this->m_Dims );
00145 DataGrid* newDataGrid = new DataGrid( newDims );
00146
00147 const TypedArray* oldData = this->GetData();
00148 if ( oldData )
00149 {
00150 newDataGrid->CreateDataArray( oldData->GetType() );
00151 TypedArray* newData = newDataGrid->GetData().GetPtr();
00152
00153 if ( oldData->GetPaddingFlag() )
00154 {
00155 newData->SetPaddingValue( oldData->GetPaddingValue() );
00156 }
00157
00158 const char* fromPtr = static_cast<const char*>( oldData->GetDataPtr() );
00159 char* toPtr = static_cast<char*>( newData->GetDataPtr() );
00160
00161
00162 const size_t bytesPerPixel = oldData->GetItemSize();
00163
00164 int fromPoint[3];
00165 for ( fromPoint[2] = 0; fromPoint[2] < this->m_Dims[2]; fromPoint[2]++ )
00166 {
00167 for ( fromPoint[1] = 0; fromPoint[1] < this->m_Dims[1]; fromPoint[1]++ )
00168 {
00169 for ( fromPoint[0] = 0; fromPoint[0] < this->m_Dims[0]; fromPoint[0]++, fromPtr += bytesPerPixel )
00170 {
00171 memcpy( toPtr + bytesPerPixel * pmatrix.NewOffsetFromPoint( fromPoint ), fromPtr, bytesPerPixel );
00172 }
00173 }
00174 }
00175 }
00176
00177 newDataGrid->m_MetaInformation = this->m_MetaInformation;
00178 newDataGrid->m_MetaInformation[META_IMAGE_ORIENTATION] = newOrientation;
00179 newDataGrid->m_MetaInformation[META_IMAGE_ORIENTATION_ORIGINAL] = this->m_MetaInformation[META_IMAGE_ORIENTATION_ORIGINAL];
00180
00181 return Self::SmartPtr( newDataGrid );
00182 }
00183
00184 void
00185 DataGrid::SetDims( const Self::IndexType& dims )
00186 {
00187 this->m_Dims = dims;
00188 this->m_CropRegion = this->GetWholeImageRegion();
00189
00190 nextI = 1;
00191 nextJ = nextI * this->m_Dims[0];
00192 nextK = nextJ * this->m_Dims[1];
00193 nextIJ = nextI + nextJ;
00194 nextIK = nextI + nextK;
00195 nextJK = nextJ + nextK;
00196 nextIJK = nextI + nextJ + nextK;
00197 }
00198
00199 bool
00200 DataGrid::TrilinearInterpolation
00201 ( Types::DataItem& value, const int X, const int Y, const int Z,
00202 const Self::SpaceVectorType& Location, const Types::Coordinate* from,
00203 const Types::Coordinate* to ) const
00204 {
00205 Types::DataItem corners[8];
00206
00207 const size_t offset = this->GetOffsetFromIndex( X, Y, Z );
00208
00209 const TypedArray* data = this->GetData();
00210 bool data_present = data->Get( corners[0], offset );
00211
00212 if ( X<this->m_Dims[0]-1 )
00213 {
00214 data_present &= data->Get( corners[1] , offset+nextI );
00215
00216 if ( Y<this->m_Dims[1]-1 )
00217 {
00218 data_present &= data->Get( corners[3], offset+nextIJ );
00219
00220 if ( Z<this->m_Dims[2]-1 )
00221 data_present &= data->Get( corners[7], offset+nextIJK );
00222 else
00223 return false;
00224 }
00225 else
00226 {
00227 return false;
00228 }
00229 data_present &= data->Get( corners[5], offset+nextIK );
00230 }
00231 else
00232 {
00233 return false;
00234 }
00235
00236 data_present &= data->Get( corners[2], offset+nextJ );
00237 data_present &= data->Get( corners[6], offset+nextJK );
00238 data_present &= data->Get( corners[4], offset+nextK );
00239
00240 if (data_present)
00241 {
00242 const Types::Coordinate deltaX=1/(to[0]-from[0]), deltaY=1/(to[1]-from[1]), deltaZ=1/(to[2]-from[2]);
00243
00244 const Types::Coordinate revX = deltaX*(Location[0]-from[0]);
00245 const Types::Coordinate revY = deltaY*(Location[1]-from[1]);
00246 const Types::Coordinate revZ = deltaZ*(Location[2]-from[2]);
00247 const Types::Coordinate offsX = 1-revX;
00248 const Types::Coordinate offsY = 1-revY;
00249 const Types::Coordinate offsZ = 1-revZ;
00250
00251 value =
00252 static_cast<Types::DataItem>( offsZ*(offsY*(offsX*corners[0]+revX*corners[1])+
00253 revY*(offsX*corners[2]+revX*corners[3]))+
00254 revZ*(offsY*(offsX*corners[4]+revX*corners[5])+
00255 revY*(offsX*corners[6]+revX*corners[7])));
00256
00257 return true;
00258 }
00259
00260 return false;
00261 }
00262
00263 TypedArray::SmartPtr
00264 DataGrid::GetDataMirrorPlane( const int axis ) const
00265 {
00266 TypedArray::SmartPtr result( this->GetData()->Clone() );
00267 this->MirrorPlaneInPlace( *result, this->m_Dims, axis );
00268
00269 return result;
00270 }
00271
00272 void
00273 DataGrid::ApplyMirrorPlane( const int axis )
00274 {
00275 this->MirrorPlaneInPlace( *(this->GetData()), this->m_Dims, axis );
00276 }
00277
00278 void
00279 DataGrid::MirrorPlaneInPlace
00280 ( TypedArray& data, const Self::IndexType& dims, const int axis )
00281 {
00282 switch ( axis )
00283 {
00284 case AXIS_X:
00285 {
00286 int offset = 0;
00287 for ( int z = 0; z < dims[2]; ++z )
00288 for ( int y = 0; y < dims[1]; ++y, offset += dims[0] )
00289 data.BlockReverse( offset, dims[0] );
00290 }
00291 break;
00292 case AXIS_Y:
00293 {
00294 size_t zOffset = 0;
00295 for ( int z = 0; z < dims[2]; ++z, zOffset += dims[0] * dims[1] )
00296 {
00297 for ( int y = 0; y < (dims[1] / 2); ++y )
00298 data.BlockSwap( zOffset + y * dims[0], zOffset + (dims[1] - 1 - y) * dims[0], dims[0] );
00299 }
00300 }
00301 break;
00302 case AXIS_Z:
00303 {
00304 size_t blockSize = dims[0] * dims[1];
00305 for ( int z = 0; z < (dims[2] / 2); ++z )
00306 {
00307 data.BlockSwap( z * blockSize, (dims[2] - 1 - z) * blockSize, blockSize );
00308 }
00309 }
00310 break;
00311 }
00312 }
00313
00314 TypedArray::SmartPtr
00315 DataGrid::GetDataMirrored
00316 ( const int axis ) const
00317 {
00318 const TypedArray* dataArray = this->GetData();
00319 if ( ! dataArray )
00320 throw( Exception( "No input data in DataGrid::GetDataMirrored()" ) );
00321
00322 TypedArray::SmartPtr mirroredArray = TypedArray::Create( dataArray->GetType(), dataArray->GetDataSize() );
00323
00324 Progress::Begin( 0, this->m_Dims[2], 1, "Mirror image" );
00325
00326 size_t offset = 0;
00327 switch ( axis )
00328 {
00329 case AXIS_X:
00330 for ( int z = 0; z < this->m_Dims[2]; ++z )
00331 {
00332 Progress::SetProgress( z );
00333 for ( int y = 0; y < this->m_Dims[1]; ++y )
00334 {
00335 for ( int x = 0; x < this->m_Dims[0]; ++x, ++offset )
00336 {
00337 dataArray->BlockCopy( *mirroredArray, offset, offset, this->m_Dims[0] );
00338 mirroredArray->BlockReverse( offset, this->m_Dims[0] );
00339 }
00340 }
00341 }
00342 break;
00343 case AXIS_Y:
00344 case AXIS_Z:
00345 default:
00346 StdErr << "DataGrid::GetDataMirrored: Flip not yet implemented\n";
00347 break;
00348 }
00349
00350 Progress::Done();
00351
00352 return mirroredArray;
00353 }
00354
00355 ScalarImage*
00356 DataGrid::GetOrthoSlice
00357 ( const int axis, const unsigned int plane ) const
00358 {
00359 unsigned int dims[2], depth, incX, incY, incZ;
00360
00361 switch ( axis )
00362 {
00363 case AXIS_X:
00364 dims[0] = this->m_Dims[1];
00365 dims[1] = this->m_Dims[2];
00366 depth = this->m_Dims[0];
00367 incX = this->m_Dims[0];
00368 incY = this->m_Dims[0] * this->m_Dims[1];
00369 incZ = 1;
00370 break;
00371 case AXIS_Y:
00372 dims[0] = this->m_Dims[0];
00373 dims[1] = this->m_Dims[2];
00374 depth = this->m_Dims[1];
00375 incX = 1;
00376 incY = this->m_Dims[0] * this->m_Dims[1];
00377 incZ = this->m_Dims[0];
00378 break;
00379 case AXIS_Z:
00380 default:
00381 dims[0] = this->m_Dims[0];
00382 dims[1] = this->m_Dims[1];
00383 depth = this->m_Dims[2];
00384 incX = 1;
00385 incY = this->m_Dims[0];
00386 incZ = this->m_Dims[0] * this->m_Dims[1];
00387 break;
00388 }
00389
00390 const TypedArray* data = this->GetData();
00391 TypedArray::SmartPtr sliceData = TypedArray::Create( data->GetType(), dims[0] * dims[1] );
00392 if ( data->GetPaddingFlag() )
00393 {
00394 sliceData->SetPaddingValue( data->GetPaddingValue() );
00395 }
00396
00397
00398 if ( (plane >= depth) )
00399 {
00400 sliceData->ClearArray( true );
00401 }
00402 else
00403 {
00404 const unsigned int itemSize = data->GetItemSize();
00405
00406 unsigned int sliceOffset = 0;
00407 unsigned int offset = plane * incZ;
00408 for ( unsigned int y = 0; y < dims[1]; ++y )
00409 {
00410 unsigned int offsetY = offset + incY;
00411 for ( unsigned int x = 0; x < dims[0]; ++x, ++sliceOffset )
00412 {
00413 unsigned int offsetX = offset + incX;
00414
00415 memcpy( sliceData->GetDataPtr( sliceOffset ), data->GetDataPtr( offset ), itemSize );
00416 offset = offsetX;
00417 }
00418 offset = offsetY;
00419 }
00420 }
00421
00422 ScalarImage* sliceImage = new ScalarImage( dims[0], dims[1] );
00423 sliceImage->SetPixelData( TypedArray::SmartPtr( sliceData ) );
00424
00425 return sliceImage;
00426 }
00427
00428 DataGrid*
00429 DataGrid::ExtractSliceVirtual
00430 ( const int axis, const int plane ) const
00431 {
00432 unsigned int dims[2], depth, incX, incY, incZ;
00433
00434 switch ( axis )
00435 {
00436 case AXIS_X:
00437 dims[0] = this->m_Dims[1];
00438 dims[1] = this->m_Dims[2];
00439 depth = this->m_Dims[0];
00440 incX = this->m_Dims[0];
00441 incY = this->m_Dims[0] * this->m_Dims[1];
00442 incZ = 1;
00443 break;
00444 case AXIS_Y:
00445 dims[0] = this->m_Dims[0];
00446 dims[1] = this->m_Dims[2];
00447 depth = this->m_Dims[1];
00448 incX = 1;
00449 incY = this->m_Dims[0] * this->m_Dims[1];
00450 incZ = this->m_Dims[0];
00451 break;
00452 case AXIS_Z:
00453 default:
00454 dims[0] = this->m_Dims[0];
00455 dims[1] = this->m_Dims[1];
00456 depth = this->m_Dims[2];
00457 incX = 1;
00458 incY = this->m_Dims[0];
00459 incZ = this->m_Dims[0] * this->m_Dims[1];
00460 break;
00461 }
00462
00463 const TypedArray& data = *(this->GetData());
00464 TypedArray::SmartPtr sliceData = TypedArray::Create( data.GetType(), dims[0] * dims[1] );
00465 if ( data.GetPaddingFlag() )
00466 {
00467 sliceData->SetPaddingValue( data.GetPaddingValue() );
00468 }
00469
00470 if ( plane >= this->m_Dims[axis] )
00471 {
00472 sliceData->ClearArray( true );
00473 }
00474 else
00475 {
00476 const unsigned int itemSize = data.GetItemSize();
00477
00478 unsigned int sliceOffset = 0;
00479 unsigned int offset = plane * incZ;
00480 for ( unsigned int y = 0; y < dims[1]; ++y )
00481 {
00482 unsigned int offsetY = offset + incY;
00483 for ( unsigned int x = 0; x < dims[0]; ++x, ++sliceOffset )
00484 {
00485 unsigned int offsetX = offset + incX;
00486
00487 memcpy( sliceData->GetDataPtr( sliceOffset ), data.GetDataPtr( offset ), itemSize );
00488 offset = offsetX;
00489 }
00490 offset = offsetY;
00491 }
00492 }
00493
00494 IndexType newDims = this->m_Dims;
00495 newDims[axis] = 1;
00496
00497 return new DataGrid( newDims, sliceData );
00498 }
00499
00500 void
00501 DataGrid::SetOrthoSlice
00502 ( const int axis, const unsigned int idx, const ScalarImage* slice )
00503 {
00504 const TypedArray* sliceData = slice->GetPixelData();
00505 if ( ! sliceData ) return;
00506
00507 TypedArray::SmartPtr data = this->GetData();
00508 if ( ! data )
00509 {
00510 data = this->CreateDataArray( sliceData->GetType() );
00511 }
00512
00513 unsigned int dims[2], depth, incX, incY, incZ;
00514
00515 switch ( axis )
00516 {
00517 case AXIS_X:
00518 dims[0] = this->m_Dims[1];
00519 dims[1] = this->m_Dims[2];
00520 depth = this->m_Dims[0];
00521 incX = this->m_Dims[0];
00522 incY = this->m_Dims[0] * this->m_Dims[1];
00523 incZ = 1;
00524 break;
00525 case AXIS_Y:
00526 dims[0] = this->m_Dims[0];
00527 dims[1] = this->m_Dims[2];
00528 depth = this->m_Dims[1];
00529 incX = 1;
00530 incY = this->m_Dims[0] * this->m_Dims[1];
00531 incZ = this->m_Dims[0];
00532 break;
00533 case AXIS_Z:
00534 default:
00535 dims[0] = this->m_Dims[0];
00536 dims[1] = this->m_Dims[1];
00537 depth = this->m_Dims[2];
00538 incX = 1;
00539 incY = this->m_Dims[0];
00540 incZ = this->m_Dims[0] * this->m_Dims[1];
00541 break;
00542 }
00543
00544 if ( (idx < depth) )
00545 {
00546 unsigned int sliceOffset = 0;
00547 unsigned int offset = idx * incZ;
00548 for ( unsigned int y = 0; y < dims[1]; ++y )
00549 {
00550 unsigned int offsetY = offset + incY;
00551 for ( unsigned int x = 0; x < dims[0]; ++x, ++sliceOffset )
00552 {
00553 unsigned int offsetX = offset + incX;
00554
00555 sliceData->BlockCopy( *data, offset, sliceOffset, 1 );
00556 offset = offsetX;
00557 }
00558 offset = offsetY;
00559 }
00560 }
00561 }
00562
00563 FixedVector<3,Types::Coordinate>
00564 DataGrid
00565 ::GetCenterOfMassGrid() const
00566 {
00567 FixedVector<3,Types::Coordinate> com( FixedVector<3,Types::Coordinate>::Init( 0 ) );
00568
00569 double sumOfSamples = 0;
00570 size_t ofs = 0;
00571 for ( int z = 0; z < this->m_Dims[2]; ++z )
00572 for ( int y = 0; y < this->m_Dims[1]; ++y )
00573 for ( int x = 0; x < this->m_Dims[0]; ++x, ++ofs )
00574 {
00575 Types::DataItem value;
00576 if ( this->GetDataAt( value, x, y, z ) )
00577 {
00578 const Types::Coordinate pixelCOM[3] = { value * x, value * y, value * z };
00579 com += Self::SpaceVectorType( pixelCOM );
00580 sumOfSamples += value;
00581 }
00582 }
00583
00584 com *= (1.0 / sumOfSamples);
00585
00586 return com;
00587 }
00588
00589 FixedVector<3,Types::Coordinate>
00590 DataGrid
00591 ::GetCenterOfMassGrid( FixedVector<3,Types::Coordinate>& firstOrderMoment ) const
00592 {
00593 FixedVector<3,Types::Coordinate> com = this->Self::GetCenterOfMassGrid();
00594 firstOrderMoment = FixedVector<3,Types::Coordinate>( FixedVector<3,Types::Coordinate>::Init( 0 ) );
00595
00596 double sumOfSamples = 0;
00597 size_t ofs = 0;
00598 for ( int z = 0; z < this->m_Dims[2]; ++z )
00599 for ( int y = 0; y < this->m_Dims[1]; ++y )
00600 for ( int x = 0; x < this->m_Dims[0]; ++x, ++ofs )
00601 {
00602 Types::DataItem value;
00603 if ( this->GetDataAt( value, x, y, z ) )
00604 {
00605 const Types::Coordinate pixelMoment[3] = { value * fabs(x - com[0]), value * fabs(y - com[1]), value * fabs(z - com[2]) };
00606 firstOrderMoment += Self::SpaceVectorType( pixelMoment );
00607 sumOfSamples += value;
00608 }
00609 }
00610
00611 firstOrderMoment *= (1.0 / sumOfSamples);
00612
00613 return com;
00614 }
00615
00616 void
00617 DataGrid::Print() const
00618 {
00619 StdErr.printf( "DataGrid at %p\n", this );
00620
00621 StdErr.printf( "\tthis->m_Dims: [%d,%d,%d])\n", this->m_Dims[0], this->m_Dims[1], this->m_Dims[2] );
00622 StdErr.printf( "\tData array at %p\n", this );
00623 }
00624
00625 }