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 "cmtkUniformVolume.h"
00034
00035 #include <Base/cmtkAffineXform.h>
00036 #include <Base/cmtkEigenSystemSymmetricMatrix3x3.h>
00037
00038 namespace
00039 cmtk
00040 {
00041
00042 UniformVolume::UniformVolume
00043 ( const DataGrid::IndexType& dims, const Self::CoordinateVectorType& size, TypedArray::SmartPtr& data )
00044 {
00045 this->SetData( data );
00046 this->SetDims( dims );
00047
00048 for ( int i=0; i<3; ++i ) {
00049 Size[i] = static_cast<Types::Coordinate>( size[i] );
00050 this->m_Delta[i] = ( this->m_Dims[i] == 1 ) ? 0 : Size[i] / (this->m_Dims[i] - 1);
00051 }
00052
00053 this->CropRegion() = this->GetWholeImageRegion();
00054 this->CreateDefaultIndexToPhysicalMatrix();
00055 }
00056
00057 UniformVolume::UniformVolume
00058 ( const DataGrid::IndexType& dims, const Types::Coordinate deltaX, const Types::Coordinate deltaY, const Types::Coordinate deltaZ, TypedArray::SmartPtr& data )
00059 {
00060 this->SetData( data );
00061 this->SetDims( dims );
00062
00063 this->m_Delta[0] = deltaX;
00064 this->m_Delta[1] = deltaY;
00065 this->m_Delta[2] = deltaZ;
00066
00067 for ( int i=0; i<3; ++i )
00068 Size[i] = this->m_Delta[i] * (this->m_Dims[i]-1);
00069
00070 this->CropRegion() = this->GetWholeImageRegion();
00071 this->CreateDefaultIndexToPhysicalMatrix();
00072 }
00073
00074 UniformVolume::UniformVolume
00075 ( const UniformVolume& other, const Types::Coordinate resolution, const bool allowUpsampling )
00076 {
00077 Self::IndexType newDims;
00078 for ( int dim=0; dim<3; ++dim )
00079 {
00080 Size[dim] = other.Size[dim];
00081 int new_dims=(int) (Size[dim]/resolution)+1;
00082 if ( allowUpsampling || (new_dims<=other.m_Dims[dim]) )
00083 {
00084 newDims[dim]=new_dims;
00085 this->m_Delta[dim]=Size[dim]/(new_dims-1);
00086 }
00087 else
00088 {
00089 if ( other.m_Dims[dim] == 1 )
00090 {
00091 this->m_Delta[dim] = Size[dim];
00092 newDims[dim] = 1;
00093 }
00094 else
00095 {
00096 this->m_Delta[dim] = other.m_Delta[dim];
00097 newDims[dim] = ((int)(Size[dim]/this->m_Delta[dim])) + 1;
00098 Size[dim] = (newDims[dim]-1) * this->m_Delta[dim];
00099 }
00100 }
00101 }
00102
00103 this->SetDims( newDims );
00104 TypedArray::SmartPtr resampledData( this->Resample( other ) );
00105 this->SetData( resampledData );
00106
00107 this->m_IndexToPhysicalMatrix = other.m_IndexToPhysicalMatrix;
00108
00109 this->SetHighResCropRegion( other.GetHighResCropRegion() );
00110 this->SetOffset( other.m_Offset );
00111 this->m_MetaInformation = other.m_MetaInformation;
00112 }
00113
00114 UniformVolume*
00115 UniformVolume::CloneVirtual( const bool copyData )
00116 {
00117 if ( copyData )
00118 {
00119 return this->CloneVirtual();
00120 }
00121 else
00122 {
00123 UniformVolume *result = this->CloneGridVirtual();
00124 result->SetData( this->GetData() );
00125
00126 return result;
00127 }
00128 }
00129
00130 UniformVolume*
00131 UniformVolume::CloneVirtual() const
00132 {
00133 UniformVolume *result = this->CloneGridVirtual();
00134
00135 if ( this->GetData() )
00136 {
00137 TypedArray::SmartPtr clonedData( this->GetData()->Clone() );
00138 result->SetData( clonedData );
00139 }
00140 else
00141 {
00142 result->SetData( TypedArray::SmartPtr::Null );
00143 }
00144
00145 return result;
00146 }
00147
00148 UniformVolume*
00149 UniformVolume::CloneGridVirtual() const
00150 {
00151 UniformVolume* clone = new UniformVolume( this->m_Dims, Size );
00152 clone->SetOffset( this->m_Offset );
00153 clone->m_MetaInformation = this->m_MetaInformation;
00154 clone->m_IndexToPhysicalMatrix = this->m_IndexToPhysicalMatrix;
00155 return clone;
00156 }
00157
00158 UniformVolume*
00159 UniformVolume::GetDownsampledAndAveraged( const int downsample, const bool approxIsotropic ) const
00160 {
00161 if ( approxIsotropic )
00162 {
00163 const Types::Coordinate minDelta = std::min<Types::Coordinate>( this->m_Delta[0], std::min<Types::Coordinate>( this->m_Delta[1], this->m_Delta[2] ) );
00164 const int downsampleByAxis[3] = { std::max<int>( 1, downsample / std::max<int>( 1, static_cast<int>(this->m_Delta[0] / minDelta) ) ),
00165 std::max<int>( 1, downsample / std::max<int>( 1, static_cast<int>(this->m_Delta[1] / minDelta) ) ),
00166 std::max<int>( 1, downsample / std::max<int>( 1, static_cast<int>(this->m_Delta[2] / minDelta) ) ) };
00167 return this->GetDownsampledAndAveraged( downsampleByAxis );
00168 }
00169 else
00170 {
00171 const int downsampleByAxis[3] = { downsample, downsample, downsample };
00172 return this->GetDownsampledAndAveraged( downsampleByAxis );
00173 }
00174 }
00175
00176 UniformVolume*
00177 UniformVolume::GetDownsampledAndAveraged( const int (&downsample)[3] ) const
00178 {
00179 DataGrid::SmartPtr newDataGrid( this->DataGrid::GetDownsampledAndAveraged( downsample ) );
00180 TypedArray::SmartPtr newData = newDataGrid->GetData();
00181
00182
00183 UniformVolume* dsVolume = new UniformVolume( newDataGrid->GetDims(), downsample[0] * this->m_Delta[0], downsample[1] * this->m_Delta[1], downsample[2] * this->m_Delta[2], newData );
00184
00185
00186 const Types::Coordinate shift[3] = { (downsample[0]-1)*this->m_Delta[0]/2, (downsample[1]-1)*this->m_Delta[1]/2, (downsample[2]-1)*this->m_Delta[2]/2 };
00187
00188
00189 Self::CoordinateVectorType offset( this->m_Offset );
00190 offset += Self::CoordinateVectorType( shift );
00191 dsVolume->SetOffset( offset );
00192
00193
00194 dsVolume->SetHighResCropRegion( this->GetHighResCropRegion() );
00195
00196 dsVolume->m_MetaInformation = this->m_MetaInformation;
00197 dsVolume->m_IndexToPhysicalMatrix = this->m_IndexToPhysicalMatrix;
00198
00199
00200 for ( int axis = 0; axis < 3; ++axis )
00201 for ( int i = 0; i < 3; ++i )
00202 {
00203 dsVolume->m_IndexToPhysicalMatrix[3][i] += (downsample[i]-1) * dsVolume->m_IndexToPhysicalMatrix[axis][i] / 2;
00204
00205 dsVolume->m_IndexToPhysicalMatrix[axis][i] *= downsample[i];
00206 }
00207
00208 return dsVolume;
00209 }
00210
00211 UniformVolume*
00212 UniformVolume::GetInterleavedSubVolume
00213 ( const int axis, const int factor, const int idx ) const
00214 {
00215 Self::IndexType dims;
00216 Self::CoordinateVectorType size;
00217
00218 for ( int dim = 0; dim < 3; ++dim )
00219 {
00220 dims[dim] = this->m_Dims[dim];
00221 size[dim] = this->Size[ dim ];
00222 }
00223 dims[axis] = this->m_Dims[axis] / factor;
00224 if ( this->m_Dims[axis] % factor > idx )
00225 ++dims[axis];
00226 size[axis] = (dims[axis]-1) * factor * this->m_Delta[axis];
00227
00228 Self::CoordinateVectorType offset( Self::CoordinateVectorType::Init( 0 ) );
00229 offset[axis] = idx * this->m_Delta[axis];
00230
00231 UniformVolume* volume = new UniformVolume( dims, size );
00232 volume->SetOffset( offset );
00233 for ( int i = 0; i < dims[axis]; ++i )
00234 {
00235 ScalarImage::SmartPtr slice( this->GetOrthoSlice( axis, idx + i * factor ) );
00236 volume->SetOrthoSlice( axis, i, slice );
00237 }
00238
00239 volume->m_MetaInformation = this->m_MetaInformation;
00240
00241 volume->m_IndexToPhysicalMatrix = this->m_IndexToPhysicalMatrix;
00242
00243 for ( int i = 0; i < 3; ++i )
00244 volume->m_IndexToPhysicalMatrix[3][i] += idx * volume->m_IndexToPhysicalMatrix[axis][i];
00245
00246 for ( int i = 0; i < 3; ++i )
00247 volume->m_IndexToPhysicalMatrix[axis][i] *= factor;
00248
00249 if ( this->GetData()->GetPaddingFlag() )
00250 {
00251 volume->GetData()->SetPaddingValue( this->GetData()->GetPaddingValue() );
00252 }
00253
00254 return volume;
00255 }
00256
00257 UniformVolume*
00258 UniformVolume::GetInterleavedPaddedSubVolume
00259 ( const int axis, const int factor, const int idx ) const
00260 {
00261 int sDims = this->m_Dims[axis] / factor;
00262 if ( this->m_Dims[axis] % factor > idx )
00263 ++sDims;
00264
00265 UniformVolume* volume = new UniformVolume( this->m_Dims, this->Size );
00266 (volume->CreateDataArray( this->GetData()->GetType() ))->Fill( 0.0 );
00267 volume->SetOffset( this->m_Offset );
00268 for ( int i = 0; i < sDims; ++i )
00269 {
00270 const size_t sliceIdx = idx + i * factor;
00271 ScalarImage::SmartPtr slice( this->GetOrthoSlice( axis, sliceIdx ) );
00272 volume->SetOrthoSlice( axis, sliceIdx, slice );
00273 }
00274
00275 volume->m_MetaInformation = this->m_MetaInformation;
00276 volume->m_IndexToPhysicalMatrix = this->m_IndexToPhysicalMatrix;
00277 return volume;
00278 }
00279
00280 const UniformVolume::RegionType
00281 UniformVolume::GetGridRange
00282 ( const Self::CoordinateVectorType& fromVOI, const Self::CoordinateVectorType& toVOI ) const
00283 {
00284 Self::IndexType from, to;
00285
00286 for ( size_t i = 0; i < 3; ++i )
00287 {
00288 from[i] = std::max<IndexType::ValueType>( 0, static_cast<IndexType::ValueType>( (fromVOI[i]-this->m_Offset[i]) / this->m_Delta[i] ) );
00289 to[i] = 1+std::min( this->m_Dims[i]-1, 1+static_cast<IndexType::ValueType>( (toVOI[i]-this->m_Offset[i]) / this->m_Delta[i] ) );
00290 }
00291
00292 return UniformVolume::RegionType( from, to );
00293 }
00294
00295 void
00296 UniformVolume::Mirror ( const int axis )
00297 {
00298 this->DataGrid::ApplyMirrorPlane( axis );
00299
00300 this->CropRegion().From()[ axis ] = this->m_Dims[ axis ] - 1 - this->CropRegion().From()[ axis ];
00301 this->CropRegion().To()[ axis ] = this->m_Dims[ axis ] - 1 - this->CropRegion().To()[ axis ];
00302 }
00303
00304 ScalarImage*
00305 UniformVolume::GetOrthoSlice
00306 ( const int axis, const unsigned int plane ) const
00307 {
00308 ScalarImage* sliceImage = DataGrid::GetOrthoSlice( axis, plane );
00309 sliceImage->SetImageSlicePosition( this->GetPlaneCoord( axis, plane ) );
00310
00311 Self::CoordinateVectorType imageOffset( Self::CoordinateVectorType::Init( 0 ) );
00312 Self::CoordinateVectorType directionX( Self::CoordinateVectorType::Init( 0 ) );
00313 Self::CoordinateVectorType directionY( Self::CoordinateVectorType::Init( 0 ) );
00314 switch ( axis )
00315 {
00316 case AXIS_X:
00317 sliceImage->SetPixelSize( this->GetDelta( AXIS_Y ), this->GetDelta( AXIS_Z ) );
00318 imageOffset[0] = this->GetPlaneCoord( AXIS_X, plane );
00319 directionX[1] = 1;
00320 directionY[2] = 1;
00321 break;
00322 case AXIS_Y:
00323 sliceImage->SetPixelSize( this->GetDelta( AXIS_X ), this->GetDelta( AXIS_Z ) );
00324 imageOffset[1] = this->GetPlaneCoord( AXIS_X, plane );
00325 directionX[0] = 1;
00326 directionY[2] = 1;
00327 break;
00328 case AXIS_Z:
00329 sliceImage->SetPixelSize( this->GetDelta( AXIS_X ), this->GetDelta( AXIS_Y ) );
00330 imageOffset[2] = this->GetPlaneCoord( AXIS_X, plane );
00331 directionX[0] = 1;
00332 directionY[1] = 1;
00333 break;
00334 }
00335
00336 sliceImage->SetImageDirectionX( directionX );
00337 sliceImage->SetImageDirectionY( directionY );
00338
00339 sliceImage->SetImageOrigin( imageOffset );
00340 return sliceImage;
00341 }
00342
00343 UniformVolume*
00344 UniformVolume::ExtractSliceVirtual
00345 ( const int axis, const int plane ) const
00346 {
00347 DataGrid::SmartPtr sliceGrid( this->DataGrid::ExtractSliceVirtual( axis, plane ) );
00348 Self* sliceVolume = new Self( sliceGrid->m_Dims, this->m_Delta[0], this->m_Delta[1], this->m_Delta[2], sliceGrid->m_Data );
00349
00350 sliceVolume->m_Offset = this->m_Offset;
00351 sliceVolume->m_Offset[axis] += plane * this->m_Delta[axis];
00352
00353 return sliceVolume;
00354 }
00355
00356 ScalarImage*
00357 UniformVolume::GetNearestOrthoSlice
00358 ( const int axis, const Types::Coordinate location ) const
00359 {
00360 return this->GetOrthoSlice( axis, this->GetCoordIndex( axis, location ) );
00361 }
00362
00363 ScalarImage*
00364 UniformVolume::GetOrthoSliceInterp
00365 ( const int axis, const Types::Coordinate location ) const
00366 {
00367 unsigned int baseSliceIndex = this->GetCoordIndex( axis, location );
00368
00369 const Types::Coordinate baseSliceLocation = this->GetPlaneCoord( axis, baseSliceIndex );
00370 const Types::Coordinate nextSliceLocation = this->GetPlaneCoord( axis, baseSliceIndex+1 );
00371
00372
00373 if ( ((location - baseSliceLocation) / (nextSliceLocation-baseSliceLocation )) < 0.01 )
00374 return this->GetOrthoSlice( axis, baseSliceIndex );
00375
00376
00377 if ( ((nextSliceLocation - location) / (nextSliceLocation-baseSliceLocation )) < 0.01 )
00378 return this->GetOrthoSlice( axis, baseSliceIndex+1 );
00379
00380 ScalarImage* image0 = this->GetOrthoSlice( axis, baseSliceIndex );
00381 ScalarImage* image1 = this->GetOrthoSlice( axis, baseSliceIndex+1 );
00382
00383 TypedArray::SmartPtr data0 = image0->GetPixelData();
00384 TypedArray::SmartPtr data1 = image1->GetPixelData();
00385
00386 Types::Coordinate weight0 = (nextSliceLocation - location) / (nextSliceLocation - baseSliceLocation );
00387
00388 Types::DataItem value0, value1;
00389 for ( unsigned int idx = 0; idx < data0->GetDataSize(); ++idx )
00390 {
00391 if ( data0->Get( value0, idx ) && data1->Get( value1, idx ) )
00392 {
00393 data0->Set( weight0 * value0 + (1-weight0) * value1, idx );
00394 }
00395 else
00396 {
00397 data0->SetPaddingAt( idx );
00398 }
00399 }
00400 delete image1;
00401
00402 image0->SetImageSlicePosition( location );
00403 image0->SetImageOrigin( weight0 * image0->GetImageOrigin() + (1-weight0) * image1->GetImageOrigin() );
00404
00405 return image0;
00406 }
00407
00408 void
00409 UniformVolume
00410 ::GetPrincipalAxes( Matrix3x3<Types::Coordinate>& directions, Self::CoordinateVectorType& centerOfMass ) const
00411 {
00412 centerOfMass = this->GetCenterOfMass();
00413 const Types::Coordinate xg = centerOfMass[0];
00414 const Types::Coordinate yg = centerOfMass[1];
00415 const Types::Coordinate zg = centerOfMass[2];
00416
00417 Matrix3x3<Types::Coordinate> inertiaMatrix;
00418
00419 Types::DataItem ixx = 0, iyy = 0, izz = 0, ixy = 0, iyz = 0, izx = 0;
00420 for ( int k = 0; k < this->m_Dims[2]; ++k )
00421 {
00422 const Types::Coordinate Dz = this->GetPlaneCoord( AXIS_Z, k ) - zg;
00423 const Types::Coordinate Dz2 = Dz * Dz;
00424 for ( int j = 0; j < this->m_Dims[1]; ++j )
00425 {
00426 const Types::Coordinate Dy = this->GetPlaneCoord( AXIS_Y, j ) - yg;
00427 const Types::Coordinate Dy2 = Dy * Dy;
00428 for ( int i = 0; i < this->m_Dims[0]; ++i )
00429 {
00430 const Types::Coordinate Dx = this->GetPlaneCoord( AXIS_X, i ) - xg;
00431 const Types::Coordinate Dx2 = Dx * Dx;
00432
00433 Types::DataItem v;
00434 if ( this->GetDataAt( v, i, j, k ) )
00435 {
00436 ixx += v * ( Dy2 + Dz2 );
00437 iyy += v * ( Dz2 + Dx2 );
00438 izz += v * ( Dx2 + Dy2 );
00439
00440 ixy += v * Dx * Dy;
00441 iyz += v * Dy * Dz;
00442 izx += v * Dz * Dx;
00443 }
00444 }
00445 }
00446 }
00447 inertiaMatrix[0][0] = ixx;
00448 inertiaMatrix[0][1] = -ixy;
00449 inertiaMatrix[0][2] = -izx;
00450
00451 inertiaMatrix[1][0] = -ixy;
00452 inertiaMatrix[1][1] = iyy;
00453 inertiaMatrix[1][2] = -iyz;
00454
00455 inertiaMatrix[2][0] = -izx;
00456 inertiaMatrix[2][1] = -iyz;
00457 inertiaMatrix[2][2] = izz;
00458
00459 const EigenSystemSymmetricMatrix3x3<Types::Coordinate> eigensystem( inertiaMatrix );
00460 for ( int n = 0; n < 3; ++n )
00461 {
00462 const Self::CoordinateVectorType v = eigensystem.GetNthEigenvector( n );
00463 for ( int i = 0; i < 3; ++i )
00464 {
00465 directions[n][i] = v[i];
00466 }
00467 }
00468
00469
00470 const Types::Coordinate det = directions.Determinant();
00471 for ( int i = 0; i < 3; i++ )
00472 {
00473 directions[2][i] *= det;
00474 }
00475
00476 for ( int i = 0; i < 3; i++ )
00477 {
00478 const Types::Coordinate norm = sqrt( directions[i][0]*directions[i][0] + directions[i][1]*directions[i][1] + directions[i][2]*directions[i][2] );
00479 for ( int j = 0; j < 3; j++ )
00480 {
00481 directions[i][j] /= norm;
00482 }
00483 }
00484 }
00485
00486 }