Mercurial > hg > minc-tools
changeset 765:409f874f1231
Initial revision
author | david <david> |
---|---|
date | Tue, 21 Feb 1995 01:17:20 +0000 |
parents | 910c49dd12b6 |
children | f06d03e1b18b |
files | volume_io/Volumes/evaluate.c |
diffstat | 1 files changed, 867 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/volume_io/Volumes/evaluate.c @@ -0,0 +1,867 @@ +#include <internal_volume_io.h> +#include <vols.h> +#include <numerical.h> + +private void trilinear_interpolate_volume( + Volume volume, + Real x, + Real y, + Real z, + BOOLEAN x_use_higher, + BOOLEAN y_use_higher, + BOOLEAN z_use_higher, + Real *value, + Real *deriv_x, + Real *deriv_y, + Real *deriv_z ); + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : evaluate_3D_volume_in_world +@INPUT : volume + x + y + z + degrees_continuity - 0 = linear, 2 = cubic +@OUTPUT : value + deriv_x + deriv_y + deriv_z +@RETURNS : +@DESCRIPTION: Takes a world space position and evaluates the value within + the volume. + If deriv_x is not a null pointer, then the 3 derivatives are + passed back. +@CREATED : Mar 1993 David MacDonald +@MODIFIED : +---------------------------------------------------------------------------- */ + +public void evaluate_3D_volume_in_world( + Volume volume, + Real x, + Real y, + Real z, + int degrees_continuity, + Real *value, + Real *deriv_x, + Real *deriv_y, + Real *deriv_z, + Real *deriv_xx, + Real *deriv_xy, + Real *deriv_xz, + Real *deriv_yy, + Real *deriv_yz, + Real *deriv_zz ) +{ + Real ignore, dxx, dxy, dxz, dyy, dyz, dzz; + Real voxel[MAX_DIMENSIONS]; + Real txx, txy, txz; + Real tyx, tyy, tyz; + Real tzx, tzy, tzz; + + if( get_volume_n_dimensions(volume) != 3 ) + { + handle_internal_error( + "evaluate_3D_volume_in_world: volume must be 3D.\n" ); + } + + convert_world_to_voxel( volume, x, y, z, voxel ); + + evaluate_3D_volume( volume, voxel[X], voxel[Y], voxel[Z], + degrees_continuity, value, deriv_x, deriv_y, deriv_z, + deriv_xx, deriv_xy, deriv_xz, + deriv_yy, deriv_yz, deriv_zz ); + + if( deriv_x != (Real *) 0 ) + { + convert_voxel_normal_vector_to_world( volume, + *deriv_x, *deriv_y, *deriv_z, + deriv_x, deriv_y, deriv_z ); + } + + if( deriv_xx != (Real *) 0 ) + { + dxx = *deriv_xx; + dxy = *deriv_xy; + dxz = *deriv_xz; + dyy = *deriv_yy; + dyz = *deriv_yz; + dzz = *deriv_zz; + convert_voxel_normal_vector_to_world( volume, + dxx, dxy, dxz, + &txx, &txy, &txz ); + convert_voxel_normal_vector_to_world( volume, + dxy, dyy, dyz, + &tyx, &tyy, &tyz ); + convert_voxel_normal_vector_to_world( volume, + dxz, dyz, dzz, + &tzx, &tzy, &tzz ); + + convert_voxel_normal_vector_to_world( volume, + txx, tyx, tzx, + deriv_xx, &ignore, &ignore ); + convert_voxel_normal_vector_to_world( volume, + txy, tyy, tzy, + deriv_xy, deriv_yy, &ignore ); + convert_voxel_normal_vector_to_world( volume, + txz, tyz, tzz, + deriv_xz, deriv_yz, deriv_zz ); + } +} + +public void special_evaluate_3D_volume_in_world( + Volume volume, + Real x, + Real y, + Real z, + BOOLEAN x_use_higher, + BOOLEAN y_use_higher, + BOOLEAN z_use_higher, + Real *value, + Real *deriv_x, + Real *deriv_y, + Real *deriv_z ) +{ + Real voxel[MAX_DIMENSIONS]; + int sizes[MAX_DIMENSIONS]; + + convert_world_to_voxel( volume, x, y, z, voxel ); + + get_volume_sizes( volume, sizes ); + if( x < -0.5 || x > (Real) sizes[X] - 0.5 || + y < -0.5 || y > (Real) sizes[Y] - 0.5 || + z < -0.5 || z > (Real) sizes[Z] - 0.5 ) + { + *value = get_volume_voxel_min( volume ); + if( deriv_x != (Real *) NULL ) + { + *deriv_x = 0.0; + *deriv_y = 0.0; + *deriv_z = 0.0; + } + return; + } + + trilinear_interpolate_volume( volume, voxel[X], voxel[Y], voxel[Z], + x_use_higher, y_use_higher, z_use_higher, + value, deriv_x, deriv_y, deriv_z ); + + if( deriv_x != (Real *) 0 ) + { + convert_voxel_normal_vector_to_world( volume, + *deriv_x, *deriv_y, *deriv_z, + deriv_x, deriv_y, deriv_z ); + } +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : evaluate_3D_slice_in_world +@INPUT : volume + x + y + z +@OUTPUT : value + deriv_x + deriv_y + deriv_xx + deriv_xy + deriv_yy +@RETURNS : +@DESCRIPTION: Takes a world space position and evaluates the value within + the volume by bilinear interpolation within the slice. + If deriv_x is not a null pointer, then the derivatives are passed + back. +@CREATED : Mar 1993 David MacDonald +@MODIFIED : +---------------------------------------------------------------------------- */ + +public void evaluate_3D_slice_in_world( + Volume volume, + Real x, + Real y, + Real z, + Real *value, + Real *deriv_x, + Real *deriv_y, + Real *deriv_xx, + Real *deriv_xy, + Real *deriv_yy ) +{ + Real ignore, dxx, dxy, dyy; + Real voxel[MAX_DIMENSIONS]; + Real txx, txy, txz; + Real tyx, tyy, tyz; + Real tzx, tzy, tzz; + + if( get_volume_n_dimensions(volume) != 3 ) + { + handle_internal_error( + "evaluate_3D_slice_in_world: volume must be 3D.\n" ); + } + + convert_world_to_voxel( volume, x, y, z, voxel ); + + evaluate_3D_slice( volume, voxel[X], voxel[Y], voxel[Z], + value, deriv_x, deriv_y, + deriv_xx, deriv_xy, deriv_yy ); + + if( deriv_x != (Real *) 0 ) + { + convert_voxel_normal_vector_to_world( volume, + *deriv_x, *deriv_y, 0.0, + deriv_x, deriv_y, &ignore ); + } + + if( deriv_xx != (Real *) 0 ) + { + dxx = *deriv_xx; + dxy = *deriv_xy; + dyy = *deriv_yy; + convert_voxel_normal_vector_to_world( volume, + dxx, dxy, 0.0, + &txx, &txy, &txz ); + convert_voxel_normal_vector_to_world( volume, + dxy, dyy, 0.0, + &tyx, &tyy, &tyz ); + convert_voxel_normal_vector_to_world( volume, + 0.0, 0.0, 0.0, + &tzx, &tzy, &tzz ); + + convert_voxel_normal_vector_to_world( volume, + txx, tyx, tzx, + deriv_xx, &ignore, &ignore ); + convert_voxel_normal_vector_to_world( volume, + txy, tyy, tzy, + deriv_xy, deriv_yy, &ignore ); + } +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : triconstant_interpolate_volume +@INPUT : volume + x + y + z +@OUTPUT : value + deriv_x + deriv_y + deriv_z +@RETURNS : +@DESCRIPTION: Returns the value within the volume, assuming constant voxels, + (step function). Derivative is approximated by neighbours. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : 1993 David MacDonald +@MODIFIED : +---------------------------------------------------------------------------- */ + +private void triconstant_interpolate_volume( + Volume volume, + Real x, + Real y, + Real z, + Real *value, + Real *deriv_x, + Real *deriv_y, + Real *deriv_z ) +{ + int i, j, k, sizes[MAX_DIMENSIONS]; + Real prev, next, dx, dy, dz, voxel_value; + + get_volume_sizes( volume, sizes ); + + i = ROUND( x ); + if( i == sizes[X] ) + i = sizes[X]-1; + j = ROUND( y ); + if( j == sizes[Y] ) + j = sizes[Y]-1; + k = ROUND( z ); + if( k == sizes[Z] ) + k = sizes[Z]-1; + + GET_VALUE_3D( voxel_value, volume, i, j, k ); + + if( value != (Real *) 0 ) + *value = voxel_value; + + if( deriv_x != (Real *) NULL ) + { + /* --- get derivative wrt x */ + + dx = 0; + if( i == 0 ) + prev = voxel_value; + else + { + GET_VALUE_3D( prev, volume, i-1, j, k ); + ++dx; + } + + if( i == sizes[X]-1 ) + next = voxel_value; + else + { + GET_VALUE_3D( next, volume, i+1, j, k ); + ++dx; + } + + if( dx == 0 ) + *deriv_x = 0.0; + else + *deriv_x = (next - prev) / (Real) dx; + + /* --- get derivative wrt y */ + + dy = 0; + if( j == 0 ) + prev = voxel_value; + else + { + GET_VALUE_3D( prev, volume, i, j-1, k ); + ++dy; + } + + if( j == sizes[Y]-1 ) + next = voxel_value; + else + { + GET_VALUE_3D( next, volume, i, j+1, k ); + ++dy; + } + + if( dy == 0 ) + *deriv_y = 0.0; + else + *deriv_y = (next - prev) / (Real) dy; + + /* --- get derivative wrt z */ + + dz = 0; + if( k == 0 ) + prev = voxel_value; + else + { + GET_VALUE_3D( prev, volume, i, j, k-1 ); + ++dz; + } + + if( k == sizes[Z]-1 ) + next = voxel_value; + else + { + GET_VALUE_3D( next, volume, i, j, k+1 ); + ++dz; + } + + if( dz == 0 ) + *deriv_z = 0.0; + else + *deriv_z = (next - prev) / (Real) dz; + } +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : trilinear_interpolate_volume +@INPUT : volume + x + y + z +@OUTPUT : value + deriv_x + deriv_y + deriv_z +@RETURNS : +@DESCRIPTION: Returns the value within the volume, assuming trilinear + interpolation. +@METHOD : +@GLOBALS : +@CALLS : +@CREATED : 1993 David MacDonald +@MODIFIED : +---------------------------------------------------------------------------- */ + +private void trilinear_interpolate_volume( + Volume volume, + Real x, + Real y, + Real z, + BOOLEAN x_use_higher, + BOOLEAN y_use_higher, + BOOLEAN z_use_higher, + Real *value, + Real *deriv_x, + Real *deriv_y, + Real *deriv_z ) +{ + int i, j, k, sizes[MAX_DIMENSIONS]; + Real u, v, w; + Real c000, c001, c010, c011, c100, c101, c110, c111; + Real c00, c01, c10, c11; + Real c0, c1; + Real du00, du01, du10, du11, du0, du1; + Real dv0, dv1; + + get_volume_sizes( volume, sizes ); + + if( x == (Real) (sizes[X]-1) ) + { + i = sizes[X]-2; + u = 1.0; + } + else + { + i = (int) x; + u = FRACTION( x ); + if( !x_use_higher && u == 0.0 && i > 0 ) + { + --i; + u = 1.0; + } + } + + if( y == (Real) (sizes[Y]-1) ) + { + j = sizes[Y]-2; + v = 1.0; + } + else + { + j = (int) y; + v = FRACTION( y ); + if( !y_use_higher && v == 0.0 && j > 0 ) + { + --j; + v = 1.0; + } + } + + if( z == (Real) (sizes[Z]-1) ) + { + k = sizes[Z]-2; + w = 1.0; + } + else + { + k = (int) z; + w = FRACTION( z ); + if( !z_use_higher && w == 0.0 && k > 0 ) + { + --k; + w = 1.0; + } + } + + GET_VALUE_3D( c000, volume, i, j, k ); + GET_VALUE_3D( c001, volume, i, j, k+1 ); + GET_VALUE_3D( c010, volume, i, j+1, k ); + GET_VALUE_3D( c011, volume, i, j+1, k+1 ); + GET_VALUE_3D( c100, volume, i+1, j, k ); + GET_VALUE_3D( c101, volume, i+1, j, k+1 ); + GET_VALUE_3D( c110, volume, i+1, j+1, k ); + GET_VALUE_3D( c111, volume, i+1, j+1, k+1 ); + + du00 = c100 - c000; + du01 = c101 - c001; + du10 = c110 - c010; + du11 = c111 - c011; + + c00 = c000 + u * du00; + c01 = c001 + u * du01; + c10 = c010 + u * du10; + c11 = c011 + u * du11; + + dv0 = c10 - c00; + dv1 = c11 - c01; + + c0 = c00 + v * dv0; + c1 = c01 + v * dv1; + + if( value != (Real *) 0 ) + *value = INTERPOLATE( w, c0, c1 ); + + if( deriv_x != (Real *) 0 ) + { + du0 = INTERPOLATE( v, du00, du10 ); + du1 = INTERPOLATE( v, du01, du11 ); + + *deriv_x = INTERPOLATE( w, du0, du1 ); + *deriv_y = INTERPOLATE( w, dv0, dv1 ); + *deriv_z = (c1 - c0); + } +} + +private void trivar_interpolate_volume( + Volume volume, + Real x, + Real y, + Real z, + int degree, + Real *value, + Real *deriv_x, + Real *deriv_y, + Real *deriv_z, + Real *deriv_xx, + Real *deriv_xy, + Real *deriv_xz, + Real *deriv_yy, + Real *deriv_yz, + Real *deriv_zz ) +{ + int i, j, k, tu, tv, tw, ind, n_derivs; + Real u, v, w, bound; + Real coefs[4*4*4]; + Real derivs[3*3*3]; + int sizes[MAX_DIMENSIONS]; + + get_volume_sizes( volume, sizes ); + + bound = (degree - 2) / 2.0; + + if( x >= (Real) sizes[X] - 1.0 - bound ) + { + i = sizes[X] - degree; + u = 1.0; + } + else + { + if( x < bound ) + x = bound; + + i = (int) ( x - bound ); + u = FRACTION( x - bound ); + } + + if( y >= (Real) sizes[Y] - 1.0 - bound ) + { + j = sizes[Y] - degree; + v = 1.0; + } + else + { + if( y < bound ) + y = bound; + + j = (int) ( y - bound ); + v = FRACTION( y - bound ); + } + + if( z >= (Real) sizes[Z] - 1.0 - bound ) + { + k = sizes[Z] - degree; + w = 1.0; + } + else + { + if( z < bound ) + z = bound; + + k = (int) ( z - bound ); + w = FRACTION( z - bound ); + } + + ind = 0; + for_less( tu, 0, degree ) + for_less( tv, 0, degree ) + for_less( tw, 0, degree ) + { + GET_VALUE_3D( coefs[ind], volume, i+tu, j+tv, k+tw ); + ++ind; + } + + if( deriv_xx != NULL ) + n_derivs = 2; + else if( deriv_x != NULL ) + n_derivs = 1; + else + n_derivs = 0; + + evaluate_trivariate_catmull_spline( u, v, w, degree, coefs, n_derivs, + derivs ); + + if( deriv_xx != NULL ) + { + *deriv_xx = derivs[IJK(2,0,0,n_derivs+1,n_derivs+1)]; + *deriv_xy = derivs[IJK(1,1,0,n_derivs+1,n_derivs+1)]; + *deriv_xz = derivs[IJK(1,0,1,n_derivs+1,n_derivs+1)]; + *deriv_yy = derivs[IJK(0,2,0,n_derivs+1,n_derivs+1)]; + *deriv_yz = derivs[IJK(0,1,1,n_derivs+1,n_derivs+1)]; + *deriv_zz = derivs[IJK(0,0,2,n_derivs+1,n_derivs+1)]; + } + + if( deriv_x != NULL ) + { + *deriv_x = derivs[IJK(1,0,0,n_derivs+1,n_derivs+1)]; + *deriv_y = derivs[IJK(0,1,0,n_derivs+1,n_derivs+1)]; + *deriv_z = derivs[IJK(0,0,1,n_derivs+1,n_derivs+1)]; + } + + if( value != NULL ) + *value = derivs[IJK(0,0,0,n_derivs+1,n_derivs+1)]; +} + +private void bicubic_interpolate_volume( + Volume volume, + Real x, + Real y, + Real z, + Real *value, + Real *deriv_x, + Real *deriv_y, + Real *deriv_xx, + Real *deriv_xy, + Real *deriv_yy ) +{ + int i, j, k, tu, tv, ind, n_derivs; + Real u, v; + Real coefs[4*4]; + Real derivs[3*3]; + int sizes[MAX_DIMENSIONS]; + + get_volume_sizes( volume, sizes ); + + if( x >= (Real) sizes[X] - 1.5 ) + { + i = sizes[X]-2; + u = 1.0; + } + else + { + i = (int) x; + u = FRACTION( x ); + } + + if( y >= (Real) sizes[Y] - 1.5 ) + { + j = sizes[Y]-2; + v = 1.0; + } + else + { + j = (int) y; + v = FRACTION( y ); + } + + if( z == (Real) sizes[Z] - 1.5 ) + { + k = sizes[Z]-2; + } + else + { + k = (int) z; + } + + ind = 0; + for_less( tu, 0, 4 ) + for_less( tv, 0, 4 ) + { + GET_VALUE_3D( coefs[ind], volume, i-1+tu, j-1+tv, k ); + ++ind; + } + + if( deriv_xx != NULL ) + n_derivs = 2; + else if( deriv_x != NULL ) + n_derivs = 1; + else + n_derivs = 0; + + evaluate_bivariate_catmull_spline( u, v, 4, coefs, n_derivs, derivs ); + + if( deriv_xx != NULL ) + { + *deriv_xx = derivs[IJ(2,0,n_derivs+1)]; + *deriv_xy = derivs[IJ(1,1,n_derivs+1)]; + *deriv_yy = derivs[IJ(0,2,n_derivs+1)]; + } + + if( deriv_x != NULL ) + { + *deriv_x = derivs[IJ(1,0,n_derivs+1)]; + *deriv_y = derivs[IJ(0,1,n_derivs+1)]; + } + + if( value != NULL ) + *value = derivs[IJ(0,0,n_derivs+1)]; +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : evaluate_3D_volume +@INPUT : volume + x + y + z +@OUTPUT : value + deriv_x + deriv_y + deriv_z +@RETURNS : +@DESCRIPTION: Takes a voxel space position and evaluates the value within + the volume by trilinear interpolation. + If deriv_x is not a null pointer, then the 3 derivatives are passed + back. +@CREATED : Mar 1993 David MacDonald +@MODIFIED : +---------------------------------------------------------------------------- */ + +public void evaluate_3D_volume( + Volume volume, + Real x, + Real y, + Real z, + int degrees_continuity, + Real *value, + Real *deriv_x, + Real *deriv_y, + Real *deriv_z, + Real *deriv_xx, + Real *deriv_xy, + Real *deriv_xz, + Real *deriv_yy, + Real *deriv_yz, + Real *deriv_zz ) +{ + int sizes[MAX_DIMENSIONS]; + + if( get_volume_n_dimensions(volume) != 3 ) + { + handle_internal_error( "evaluate_3D_volume: volume must be 3D.\n" ); + } + + get_volume_sizes( volume, sizes ); + + if( x < -0.5 || x > (Real) sizes[X] - 0.5 || + y < -0.5 || y > (Real) sizes[Y] - 0.5 || + z < -0.5 || z > (Real) sizes[Z] - 0.5 ) + { + *value = get_volume_voxel_min( volume ); + if( deriv_x != (Real *) NULL ) + { + *deriv_x = 0.0; + *deriv_y = 0.0; + *deriv_z = 0.0; + } + if( deriv_xx != (Real *) NULL ) + { + *deriv_xx = 0.0; + *deriv_xy = 0.0; + *deriv_xz = 0.0; + *deriv_yy = 0.0; + *deriv_yz = 0.0; + *deriv_zz = 0.0; + } + return; + } + + if( x < (Real) degrees_continuity * 0.5 || + x > (Real) (sizes[X]-1) - (Real) degrees_continuity * 0.5 || + y < (Real) degrees_continuity * 0.5 || + y > (Real) (sizes[Y]-1) - (Real) degrees_continuity * 0.5 || + z < (Real) degrees_continuity * 0.5 || + z > (Real) (sizes[Z]-1) - (Real) degrees_continuity * 0.5 ) + { + degrees_continuity = -1; + } + + if( degrees_continuity < 1 && deriv_xx != (Real *) NULL ) + { + *deriv_xx = 0.0; + *deriv_xy = 0.0; + *deriv_xz = 0.0; + *deriv_yy = 0.0; + *deriv_yz = 0.0; + *deriv_zz = 0.0; + } + + switch( degrees_continuity ) + { + case -1: + triconstant_interpolate_volume( volume, x, y, z, value, + deriv_x, deriv_y, deriv_z ); + break; + + case 0: + trilinear_interpolate_volume( volume, x, y, z, + TRUE, TRUE, TRUE, value, + deriv_x, deriv_y, deriv_z ); + break; + + case 1: + case 2: + trivar_interpolate_volume( volume, x, y, z, degrees_continuity+2, + value, + deriv_x, deriv_y, deriv_z, + deriv_xx, deriv_xy, deriv_xz, + deriv_yy, deriv_yz, deriv_zz ); + break; + + default: + handle_internal_error( "evaluate_3D_volume: invalid continuity" ); + } +} + +/* ----------------------------- MNI Header ----------------------------------- +@NAME : evaluate_3D_slice +@INPUT : volume + x + y + z +@OUTPUT : value + deriv_x + deriv_y + deriv_xx + deriv_xy + deriv_yy +@RETURNS : +@DESCRIPTION: Takes a voxel position and evaluates the value within + the volume by bilinear interpolation within the slice. + If deriv_x is not a null pointer, then the + derivatives are passed back. +@CREATED : Mar 1993 David MacDonald +@MODIFIED : +---------------------------------------------------------------------------- */ + +public void evaluate_3D_slice( + Volume volume, + Real x, + Real y, + Real z, + Real *value, + Real *deriv_x, + Real *deriv_y, + Real *deriv_xx, + Real *deriv_xy, + Real *deriv_yy ) +{ + int sizes[MAX_DIMENSIONS]; + + if( get_volume_n_dimensions(volume) != 3 ) + { + handle_internal_error( "evaluate_3D_slice: volume must be 3D.\n" ); + } + + get_volume_sizes( volume, sizes ); + + if( x < 1.0 || x > (Real) sizes[X] - 2.0 || + y < 1.0 || y > (Real) sizes[Y] - 2.0 || + z < 1.0 || z > (Real) sizes[Z] - 2.0 ) + { + *value = get_volume_voxel_min( volume ); + if( deriv_x != (Real *) NULL ) + { + *deriv_x = 0.0; + *deriv_y = 0.0; + } + if( deriv_xx != (Real *) NULL ) + { + *deriv_xx = 0.0; + *deriv_xy = 0.0; + *deriv_yy = 0.0; + } + return; + } + + bicubic_interpolate_volume( volume, x, y, z, value, + deriv_x, deriv_y, + deriv_xx, deriv_xy, deriv_yy ); +}