void save_volume(VIO_Volume d, char *filename) { VIO_Status status; status = output_volume(filename,NC_UNSPECIFIED, FALSE, 0.0, 0.0, d, (char *)NULL, (minc_output_options *)NULL); if (status != OK) print_error_and_line_num("problems writing volume `%s'.",__FILE__, __LINE__, filename); }
VIO_Status gradient3D_volume(FILE *ifd, VIO_Volume data, int xyzv[VIO_MAX_DIMENSIONS], char *infile, char *outfile, int ndim, char *history, int curvature_flg) { float *fdata, /* floating point storage for blurred volume */ *f_ptr, /* pointer to fdata */ tmp, max_val, min_val, *dat_vector, /* temp storage of original row, col or slice vect. */ *dat_vecto2, /* storage of result of dat_vector*kern */ *kern; /* convolution kernel */ int total_voxels, vector_size_data, /* original size of row, col or slice vector */ array_size_pow2, /* actual size of vector/kernel data used in FFT */ /* routines - needs to be a power of two */ array_size; int data_offset; /* offset required to place original data (size n) */ /* into array (size m=2^n) so that data is centered*/ register int slice_limit, row,col,slice, /* counters to access original data */ vindex; /* counter to access vector and vecto2 */ int slice_size, /* size of each data step - in bytes */ row_size, col_size; char full_outfilename[256]; /* name of output file */ progress_struct progress; /* used to monitor progress of calculations */ VIO_Status status; int sizes[3], /* number of rows, cols and slices */ pos[3]; /* Input order of rows, cols, slices */ VIO_Real steps[3]; /* size of voxel step from center to center in x,y,z */ /*---------------------------------------------------------------------------------*/ /* start by setting up the raw data. */ /*---------------------------------------------------------------------------------*/ get_volume_sizes(data, sizes); /* rows,cols,slices */ get_volume_separations(data, steps); slice_size = sizes[xyzv[VIO_Y]] * sizes[xyzv[VIO_X]]; /* sizeof one slice */ col_size = sizes[xyzv[VIO_Y]]; /* sizeof one column */ row_size = sizes[xyzv[VIO_X]]; /* sizeof one row */ total_voxels = sizes[xyzv[VIO_Y]]*sizes[xyzv[VIO_X]]*sizes[xyzv[VIO_Z]]; ALLOC(fdata, total_voxels); f_ptr = fdata; /* read in data of input file. */ set_file_position(ifd,(long)0); status = io_binary_data(ifd,READ_FILE, fdata, sizeof(float), total_voxels); if (status != OK) print_error_and_line_num("problems reading binary data...\n",__FILE__, __LINE__); /*--------------------------------------------------------------------------------------*/ /* get ready to start up the transformation. */ /*--------------------------------------------------------------------------------------*/ initialize_progress_report( &progress, FALSE, sizes[xyzv[VIO_Z]] + sizes[xyzv[VIO_Y]] + sizes[xyzv[VIO_X]] + 1, "Gradient volume" ); /* note data is stored by rows (along x), then by cols (along y) then slices (along z) */ /*--------------------------------------------------------------------------------------*/ /* start with rows - i.e. the d/dx volume */ /*--------------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/ /* determine size of data structures needed */ vector_size_data = sizes[xyzv[VIO_X]]; /* array_size_pow2 will hold the size of the arrays for FFT convolution, remember that ffts require arrays 2^n in length */ array_size_pow2 = next_power_of_two(vector_size_data); array_size = 2*array_size_pow2+1; /* allocate 2*, since each point is a */ /* complex number for FFT, and the plus 1*/ /* is for the zero offset FFT routine */ ALLOC(dat_vector, array_size); ALLOC(dat_vecto2, array_size); ALLOC(kern , array_size); /* 1st calculate kern array for FT of 1st derivitive */ make_kernel_FT(kern,array_size_pow2, ABS(steps[xyzv[VIO_X]])); if (curvature_flg) /* 2nd derivative kernel */ muli_vects(kern,kern,kern,array_size_pow2); /* calculate offset for original data to be placed in vector */ data_offset = (array_size_pow2-sizes[xyzv[VIO_X]])/2; max_val = -FLT_MAX; min_val = FLT_MAX; /* 2nd now convolve this kernel with the rows of the dataset */ slice_limit = 0; switch (ndim) { case 1: slice_limit = 0; break; case 2: slice_limit = sizes[xyzv[VIO_Z]]; break; case 3: slice_limit = sizes[xyzv[VIO_Z]]; break; } for (slice = 0; slice < slice_limit; slice++) { /* for each slice */ for (row = 0; row < sizes[xyzv[VIO_Y]]; row++) { /* for each row */ f_ptr = fdata + slice*slice_size + row*sizes[xyzv[VIO_X]]; memset(dat_vector,0,(2*array_size_pow2+1)*sizeof(float)); for (col=0; col< sizes[xyzv[VIO_X]]; col++) { /* extract the row */ dat_vector[1 +2*(col+data_offset) ] = *f_ptr++; } fft1(dat_vector,array_size_pow2,1); muli_vects(dat_vecto2,dat_vector,kern,array_size_pow2); fft1(dat_vecto2,array_size_pow2,-1); f_ptr = fdata + slice*slice_size + row*sizes[xyzv[VIO_X]]; for (col=0; col< sizes[xyzv[VIO_X]]; col++) { /* put the row back */ vindex = 1 + 2*(col+data_offset); *f_ptr = dat_vecto2[vindex]/array_size_pow2; if (max_val<*f_ptr) max_val = *f_ptr; if (min_val>*f_ptr) min_val = *f_ptr; f_ptr++; } } update_progress_report( &progress, slice+1 ); } FREE(dat_vector); FREE(dat_vecto2); FREE(kern ); f_ptr = fdata; set_volume_real_range(data, min_val, max_val); printf("Making byte volume dx..." ); for(slice=0; slice<sizes[xyzv[VIO_Z]]; slice++) { pos[xyzv[VIO_Z]] = slice; for(row=0; row<sizes[xyzv[VIO_Y]]; row++) { pos[xyzv[VIO_Y]] = row; for(col=0; col<sizes[xyzv[VIO_X]]; col++) { pos[xyzv[VIO_X]] = col; tmp = CONVERT_VALUE_TO_VOXEL(data, *f_ptr); SET_VOXEL_3D( data, pos[0], pos[1], pos[2], tmp); f_ptr++; } } } if (!curvature_flg) sprintf(full_outfilename,"%s_dx.mnc",outfile); else sprintf(full_outfilename,"%s_dxx.mnc",outfile); if (debug) print ("dx: min = %f, max = %f\n",min_val, max_val); status = output_modified_volume(full_outfilename, NC_UNSPECIFIED, FALSE, min_val, max_val, data, infile, history, NULL); if (status != OK) print_error_and_line_num("problems writing dx gradient data...\n",__FILE__, __LINE__); /*--------------------------------------------------------------------------------------*/ /* now do cols - i.e. the d/dy volume */ /*--------------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/ /* determine size of data structures needed */ set_file_position(ifd,0); status = io_binary_data(ifd,READ_FILE, fdata, sizeof(float), total_voxels); if (status != OK) print_error_and_line_num("problems reading binary data...\n",__FILE__, __LINE__); f_ptr = fdata; vector_size_data = sizes[xyzv[VIO_Y]]; /* array_size_pow2 will hold the size of the arrays for FFT convolution, remember that ffts require arrays 2^n in length */ array_size_pow2 = next_power_of_two(vector_size_data); array_size = 2*array_size_pow2+1; /* allocate 2*, since each point is a */ /* complex number for FFT, and the plus 1*/ /* is for the zero offset FFT routine */ ALLOC(dat_vector, array_size); ALLOC(dat_vecto2, array_size); ALLOC(kern , array_size); /* 1st calculate kern array for FT of 1st derivitive */ make_kernel_FT(kern,array_size_pow2, ABS(steps[xyzv[VIO_Y]])); if (curvature_flg) /* 2nd derivative kernel */ muli_vects(kern,kern,kern,array_size_pow2); /* calculate offset for original data to be placed in vector */ data_offset = (array_size_pow2-sizes[xyzv[VIO_Y]])/2; /* 2nd now convolve this kernel with the rows of the dataset */ max_val = -FLT_MAX; min_val = FLT_MAX; switch (ndim) { case 1: slice_limit = 0; break; case 2: slice_limit = sizes[xyzv[VIO_Z]]; break; case 3: slice_limit = sizes[xyzv[VIO_Z]]; break; } for (slice = 0; slice < slice_limit; slice++) { /* for each slice */ for (col = 0; col < sizes[xyzv[VIO_X]]; col++) { /* for each col */ /* f_ptr = fdata + slice*slice_size + row*sizeof(float); */ f_ptr = fdata + slice*slice_size + col; memset(dat_vector,0,(2*array_size_pow2+1)*sizeof(float)); for (row=0; row< sizes[xyzv[VIO_Y]]; row++) { /* extract the col */ dat_vector[1 +2*(row+data_offset) ] = *f_ptr; f_ptr += row_size; } fft1(dat_vector,array_size_pow2,1); muli_vects(dat_vecto2,dat_vector,kern,array_size_pow2); fft1(dat_vecto2,array_size_pow2,-1); f_ptr = fdata + slice*slice_size + col; for (row=0; row< sizes[xyzv[VIO_Y]]; row++) { /* put the col back */ vindex = 1 + 2*(row+data_offset); *f_ptr = dat_vecto2[vindex]/array_size_pow2; if (max_val<*f_ptr) max_val = *f_ptr; if (min_val>*f_ptr) min_val = *f_ptr; f_ptr += row_size; } } update_progress_report( &progress, slice+sizes[xyzv[VIO_Z]]+1 ); } FREE(dat_vector); FREE(dat_vecto2); FREE(kern ); f_ptr = fdata; set_volume_real_range(data, min_val, max_val); printf("Making byte volume dy..." ); for(slice=0; slice<sizes[xyzv[VIO_Z]]; slice++) { pos[xyzv[VIO_Z]] = slice; for(row=0; row<sizes[xyzv[VIO_Y]]; row++) { pos[xyzv[VIO_Y]] = row; for(col=0; col<sizes[xyzv[VIO_X]]; col++) { pos[xyzv[VIO_X]] = col; tmp = CONVERT_VALUE_TO_VOXEL(data, *f_ptr); SET_VOXEL_3D( data, pos[0], pos[1], pos[2], tmp); f_ptr++; } } } if (!curvature_flg) sprintf(full_outfilename,"%s_dy.mnc",outfile); else sprintf(full_outfilename,"%s_dyy.mnc",outfile); if (debug) print ("dy: min = %f, max = %f\n",min_val, max_val); status = output_modified_volume(full_outfilename, NC_UNSPECIFIED, FALSE, min_val, max_val, data, infile, history, NULL); if (status != OK) print_error_and_line_num("problems writing dy gradient data...",__FILE__, __LINE__); /*--------------------------------------------------------------------------------------*/ /* now do slices - i.e. the d/dz volume */ /*--------------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/ /* determine size of data structures needed */ set_file_position(ifd,0); status = io_binary_data(ifd,READ_FILE, fdata, sizeof(float), total_voxels); if (status != OK) print_error_and_line_num("problems reading binary data...\n",__FILE__, __LINE__); f_ptr = fdata; vector_size_data = sizes[xyzv[VIO_Z]]; /* array_size_pow2 will hold the size of the arrays for FFT convolution, remember that ffts require arrays 2^n in length */ array_size_pow2 = next_power_of_two(vector_size_data); array_size = 2*array_size_pow2+1; /* allocate 2*, since each point is a */ /* complex number for FFT, and the plus 1*/ /* is for the zero offset FFT routine */ ALLOC(dat_vector, array_size); ALLOC(dat_vecto2, array_size); ALLOC(kern , array_size); if (ndim==1 || ndim==3) { /* 1st calculate kern array for FT of 1st derivitive */ make_kernel_FT(kern,array_size_pow2, ABS(steps[xyzv[VIO_Z]])); if (curvature_flg) /* 2nd derivative kernel */ muli_vects(kern,kern,kern,array_size_pow2); /* calculate offset for original data to be placed in vector */ data_offset = (array_size_pow2-sizes[xyzv[VIO_Z]])/2; /* 2nd now convolve this kernel with the slices of the dataset */ max_val = -FLT_MAX; min_val = FLT_MAX; for (col = 0; col < sizes[xyzv[VIO_X]]; col++) { /* for each column */ for (row = 0; row < sizes[xyzv[VIO_Y]]; row++) { /* for each row */ f_ptr = fdata + col*col_size + row; memset(dat_vector,0,(2*array_size_pow2+1)*sizeof(float)); for (slice=0; slice< sizes[xyzv[VIO_Z]]; slice++) { /* extract the slice vector */ dat_vector[1 +2*(slice+data_offset) ] = *f_ptr; f_ptr += slice_size; } fft1(dat_vector,array_size_pow2,1); muli_vects(dat_vecto2,dat_vector,kern,array_size_pow2); fft1(dat_vecto2,array_size_pow2,-1); f_ptr = fdata + col*col_size + row; for (slice=0; slice< sizes[xyzv[VIO_Z]]; slice++) { /* put the vector back */ vindex = 1 + 2*(slice+data_offset); *f_ptr = dat_vecto2[vindex]/array_size_pow2; if (max_val<*f_ptr) max_val = *f_ptr; if (min_val>*f_ptr) min_val = *f_ptr; f_ptr += slice_size; } } update_progress_report( &progress, col + 2*sizes[xyzv[VIO_Z]] + 1 ); } } /* if ndim */ else { max_val = 0.00001; min_val = 0.00000; for (col = 0; col < sizes[xyzv[VIO_X]]; col++) { /* for each column */ for (row = 0; row < sizes[xyzv[VIO_Y]]; row++) { /* for each row */ *f_ptr = 0.0; f_ptr++; } } } FREE(dat_vector); FREE(dat_vecto2); FREE(kern ); /* set up the correct info to copy the data back out in mnc */ f_ptr = fdata; set_volume_real_range(data, min_val, max_val); printf("Making byte volume dz..." ); for(slice=0; slice<sizes[xyzv[VIO_Z]]; slice++) { pos[xyzv[VIO_Z]] = slice; for(row=0; row<sizes[xyzv[VIO_Y]]; row++) { pos[xyzv[VIO_Y]] = row; for(col=0; col<sizes[xyzv[VIO_X]]; col++) { pos[xyzv[VIO_X]] = col; tmp = CONVERT_VALUE_TO_VOXEL(data, *f_ptr); SET_VOXEL_3D( data, pos[0], pos[1], pos[2], tmp); f_ptr++; } } } if (!curvature_flg) sprintf(full_outfilename,"%s_dz.mnc",outfile); else sprintf(full_outfilename,"%s_dzz.mnc",outfile); if (debug) print ("dz: min = %f, max = %f\n",min_val, max_val); status = output_modified_volume(full_outfilename, NC_UNSPECIFIED, FALSE, min_val, max_val, data, infile, history, NULL); if (status != OK) print_error_and_line_num("problems writing dz gradient data...",__FILE__, __LINE__); terminate_progress_report( &progress ); FREE(fdata); return(status); }
void normalize_data_to_match_target(VIO_Volume d1, VIO_Volume m1, VIO_Real thresh1, VIO_Volume d2, VIO_Volume m2, VIO_Real thresh2, Arg_Data *globals) { VectorR vector_step; PointR starting_position, slice, row, col, pos2, voxel; double tx,ty,tz; int i,j,k, r,c,s; VIO_Real min_range, max_range, data_vox, data_val, value1, value2; VIO_Real t1,t2, /* temporary threshold values */ s1,s2,s3; /* to store the sums for f1,f2,f3 */ float *ratios, result; /* the result */ int sizes[VIO_MAX_DIMENSIONS],ratios_size,count1,count2; VIO_Volume vol; VIO_progress_struct progress; VIO_Data_types data_type; set_feature_value_threshold(d1,d2, &thresh1, &thresh2, &t1, &t2); if (globals->flags.debug) { print ("In normalize_data_to_match_target, thresh = %10.3f %10.3f\n",t1,t2) ; } ratios_size = globals->count[ROW_IND] * globals->count[COL_IND] * globals->count[SLICE_IND]; ALLOC(ratios, ratios_size); fill_Point( starting_position, globals->start[VIO_X], globals->start[VIO_Y], globals->start[VIO_Z]); s1 = s2 = s3 = 0.0; count1 = count2 = 0; for(s=0; s<=globals->count[SLICE_IND]; s++) { SCALE_VECTOR( vector_step, globals->directions[SLICE_IND], s); ADD_POINT_VECTOR( slice, starting_position, vector_step ); for(r=0; r<=globals->count[ROW_IND]; r++) { SCALE_VECTOR( vector_step, globals->directions[ROW_IND], r); ADD_POINT_VECTOR( row, slice, vector_step ); SCALE_POINT( col, row, 1.0); /* init first col position */ for(c=0; c<=globals->count[COL_IND]; c++) { convert_3D_world_to_voxel(d1, Point_x(col), Point_y(col), Point_z(col), &tx, &ty, &tz); fill_Point( voxel, tx, ty, tz ); /* build the voxel POINT */ if (point_not_masked(m1, Point_x(col), Point_y(col), Point_z(col))) { value1 = get_value_of_point_in_volume( Point_x(col), Point_y(col), Point_z(col), d1); if ( value1 > t1 ) { count1++; DO_TRANSFORM(pos2, globals->trans_info.transformation, col); convert_3D_world_to_voxel(d2, Point_x(pos2), Point_y(pos2), Point_z(pos2), &tx, &ty, &tz); fill_Point( voxel, tx, ty, tz ); /* build the voxel POINT */ if (point_not_masked(m2, Point_x(pos2), Point_y(pos2), Point_z(pos2))) { value2 = get_value_of_point_in_volume( Point_x(pos2), Point_y(pos2), Point_z(pos2), d2); if ( (value2 > t2) && ((value2 < -1e-15) || (value2 > 1e-15)) ) { ratios[count2++] = value1 / value2 ; s1 += value1*value2; s2 += value1*value1; s3 += value2*value2; } /* if voxel in d2 */ } /* if point in mask volume two */ } /* if voxel in d1 */ } /* if point in mask volume one */ ADD_POINT_VECTOR( col, col, globals->directions[COL_IND] ); } /* for c */ } /* for r */ } /* for s */ if (count2 > 0) { if (globals->flags.debug) (void)print ("Starting qsort of ratios..."); qs_list (ratios,0,count2); if (globals->flags.debug) (void)print ("Done.\n"); result = ratios[ (int)(count2/2) ]; /* the median value */ if (globals->flags.debug) (void)print ("Normalization: %7d %7d -> %10.8f\n",count1,count2,result); if ( fabs(result) < 1e-15) { print_error_and_line_num("Error computing normalization ratio `%f'.",__FILE__, __LINE__, result); } else { data_type = get_volume_data_type(d1); switch( data_type ) { case SIGNED_BYTE: case UNSIGNED_BYTE: case SIGNED_SHORT: case UNSIGNED_SHORT: /* build temporary working volume */ vol = copy_volume_definition_no_alloc(d1, NC_UNSPECIFIED, FALSE, 0.0, 0.0); get_volume_minimum_maximum_real_value(d1, &min_range, &max_range); min_range /= result; max_range /= result; set_volume_real_range(vol, min_range, max_range); get_volume_sizes(d1, sizes); initialize_progress_report(&progress, FALSE, sizes[0]*sizes[1]*sizes[2] + 1, "Normalizing source data" ); count1 = 0; /* reset values in the data volume */ for(i=0; i<sizes[0]; i++) for(j=0; j<sizes[1]; j++) { count1++; update_progress_report( &progress, count1); for(k=0; k<sizes[2]; k++) { GET_VOXEL_3D( data_vox, d1, i, j, k ); data_val = CONVERT_VOXEL_TO_VALUE(d1, data_vox); data_val /= result; data_vox = CONVERT_VALUE_TO_VOXEL( vol, data_val); SET_VOXEL_3D( d1 , i, j, k, data_vox ); } } terminate_progress_report( &progress ); set_volume_real_range(d1, min_range, max_range); if (globals->flags.debug) (void)print ("After normalization min,max, thresh = %f %f %f\n", min_range, max_range, t1/result); delete_volume(vol); break; default: /* then volume should be either float or double */ get_volume_sizes(d1, sizes); initialize_progress_report(&progress, FALSE, sizes[0]*sizes[1]*sizes[2] + 1, "Normalizing source data" ); count1 = 0; /* nomalize the values in the data volume */ for(i=0; i<sizes[0]; i++) for(j=0; j<sizes[1]; j++) { count1++; update_progress_report( &progress, count1); for(k=0; k<sizes[2]; k++) { /* it should be possible to directly stream through the voxels, without indexing... */ GET_VOXEL_3D( data_vox, d1, i, j, k ); data_val = CONVERT_VOXEL_TO_VALUE(d1, data_vox); data_val /= result; data_vox = CONVERT_VALUE_TO_VOXEL( d1, data_val); SET_VOXEL_3D( d1 , i, j, k, data_vox ); } } terminate_progress_report( &progress ); } } } FREE(ratios); }
float go_get_samples_with_offset( VIO_Volume data, /* The volume of data */ VIO_Volume mask, /* The target mask */ float *x, float *y, float *z, /* the positions of the sub-lattice */ VIO_Real dx, VIO_Real dy, VIO_Real dz, /* the local displacement to apply */ int obj_func, /* the type of obj function req'd */ int len, /* number of sub-lattice nodes */ int *sample_target_count, /* number of nonmasked sub-lattice nodes */ float normalization, /* normalization factor for obj func*/ float *a1, /* feature value for (x,y,z) nodes */ VIO_BOOL *m1, /* mask flag for (x,y,z) nodes in source */ VIO_BOOL use_nearest_neighbour) /* interpolation flag */ { double sample, r, s1,s2,s3,s4,s5,tmp; /* accumulators for inner loop */ int sizes[3], ind0, ind1, ind2, offset0, offset1, offset2, c,number_of_nonzero_samples; int xs,ys,zs; float f_trans, f_scale; static double v0, v1, v2; static double f0, f1, f2, r0, r1, r2, r1r2, r1f2, f1r2, f1f2; static double v000, v001, v010, v011, v100, v101, v110, v111; double ***double_ptr; double mean_s = 0.0; /* init variables for stats */ double mean_t = 0.0; double var_s = 0.0; double var_t = 0.0; double covariance = 0.0; number_of_nonzero_samples = 0; get_volume_sizes(data, sizes); xs = sizes[0]; ys = sizes[1]; zs = sizes[2]; s1 = s2 = s3 = s4 = s5 = 0.0; ++a1; ++m1; /* inc pointer, so that we are pointing to the first feature value, corresponding to the first sub-lattice point x,y,z */ if (use_nearest_neighbour) { /* then do fast NN interpolation */ dx += 0.; /* to achieve `rounding' for ind0, ind1 and */ dy += 0.; /* ind2 below */ dz += 0.; double_ptr = VOXEL_DATA (data); /* increment by one as we index from 1...n (but the array is ALLOC'd from 0..n) */ x++; y++; z++; /* for each sub-lattice node */ for(c=len; c--;) { /* * this is code to test timing of David's evaluate_volume_in_world() * interpolation code. While it is _VERY_ general, the eval_vol_in_world()'s * NN interpolation is approximately 8-9 times slower than the bit of * fast NN code below. * * VIO_Real sampleR, index[5], wx, wy, wz; * index[0] = (VIO_Real) ( *x + dx ); * index[1] = (VIO_Real) ( *y + dy ); * index[2] = (VIO_Real) ( *z + dz ); * index[3] = index[4] = 0.0; * convert_voxel_to_world(data, index, &wx, &wy, &wz ); * evaluate_volume_in_world(data, wx, wy, wz, * 0, TRUE, 0.0, &sampleR, * NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); * sample = (double)sampleR; */ if (!(*m1) && (voxel_point_not_masked(mask, (VIO_Real)*x, (VIO_Real)*y, (VIO_Real)*z)) && (!(obj_func==NONLIN_CHAMFER) || (*a1>0)) ) { ind0 = (int) ( *x + dx ); ind1 = (int) ( *y + dy ); ind2 = (int) ( *z + dz ); if (ind0>=0 && ind0<xs && ind1>=0 && ind1<ys && ind2>=0 && ind2<zs) { sample = (double)(double_ptr[ind0][ind1][ind2]); } else { sample = 0.0; } #include "switch_obj_func.c" /* contains a case statement to do the sample-to-sample computations required for each possible non-lin objective function */ } /* increment the coordinate, value and mask array pointers */ x++; /* x,y,z are the coords of the sublattice in the fixed (source) image */ y++; z++; a1++; /* a1 is from the fixed image */ m1++; /* m1 is rom the mask on the fixed image */ } } else { /* then do fast trilinear interpolation */ /* set up offsets */ offset0 = (Gglobals->count[VIO_Z] > 1) ? 1 : 0; offset1 = (Gglobals->count[VIO_Y] > 1) ? 1 : 0; offset2 = (Gglobals->count[VIO_X] > 1) ? 1 : 0; double_ptr = VOXEL_DATA (data); /* increment by one as we index from 1...n */ ++x; ++y; ++z; /* for each sub-lattice node */ for(c=len; c--;) { /* fast tri-linear interplation */ if ( !(*m1) && (voxel_point_not_masked(mask, (VIO_Real)*x, (VIO_Real)*y, (VIO_Real)*z)) && (!(obj_func==NONLIN_CHAMFER) || (*a1>0)) ) { v0 = (VIO_Real) ( *x + dx ); v1 = (VIO_Real) ( *y + dy ); v2 = (VIO_Real) ( *z + dz ); ind0 = (int)v0; ind1 = (int)v1; ind2 = (int)v2; if (ind0>=0 && ind0<(xs-offset0) && ind1>=0 && ind1<(ys-offset1) && ind2>=0 && ind2<(zs-offset2)) { /* get the data */ v000 = (VIO_Real)(double_ptr[ind0 ][ind1 ][ind2 ]); v001 = (VIO_Real)(double_ptr[ind0 ][ind1 ][ind2+offset2]); v010 = (VIO_Real)(double_ptr[ind0 ][ind1+offset1][ind2 ]); v011 = (VIO_Real)(double_ptr[ind0 ][ind1+offset1][ind2+offset2]); v100 = (VIO_Real)(double_ptr[ind0+offset0][ind1 ][ind2 ]); v101 = (VIO_Real)(double_ptr[ind0+offset0][ind1 ][ind2+offset2]); v110 = (VIO_Real)(double_ptr[ind0+offset0][ind1+offset1][ind2 ]); v111 = (VIO_Real)(double_ptr[ind0+offset0][ind1+offset1][ind2+offset2]); /* Get the fraction parts */ f0 = v0 - ind0; f1 = v1 - ind1; f2 = v2 - ind2; r0 = 1.0 - f0; r1 = 1.0 - f1; r2 = 1.0 - f2; /* Do the interpolation */ r1r2 = r1 * r2; r1f2 = r1 * f2; f1r2 = f1 * r2; f1f2 = f1 * f2; sample = r0 * (r1r2 * v000 + r1f2 * v001 + f1r2 * v010 + f1f2 * v011); sample += f0 * (r1r2 * v100 + r1f2 * v101 + f1r2 * v110 + f1f2 * v111); sample = sample; } else { sample = 0.0; } #include "switch_obj_func.c" } /* increment the coordinate, value and mask array pointers */ x++; /* x,y,z are the coords of the sublattice in the fixed (source) image */ y++; z++; a1++; /* a1 is from the fixed image */ m1++; /* m1 is rom the mask on the fixed image */ } /* do the last bits of the similarity function calculation here - normalizing each obj_func where-ever possible: */ r = 0.0; switch (obj_func) { case NONLIN_XCORR: /* use standard normalized cross-correlation where 0.0 < r < 1.0, where 1.0 is best*/ if ( normalization < 0.001 && s3 < 0.00001) { r = 1.0; } else { if ( normalization < 0.001 || s3 < 0.00001) { r = 0.0; } else { r = s1 / ((sqrt((double)s2))*(sqrt((double)s3))); } } /* r = 1.0 - r; now, 0 is best */ break; case NONLIN_DIFF: /* normalization stores the number of samples in the sub-lattice s1 stores the sum of the magnitude of the differences*/ r = -s1 /number_of_nonzero_samples; /* r = average intensity difference ; with -max(intensity range) < r < 0, where 0 is best */ break; case NONLIN_LABEL: r = s1 /number_of_nonzero_samples; /* r = average label agreement, s1 stores the number of similar labels 0 < r < 1.0 where 1.0 is best */ break; case NONLIN_CHAMFER: if (number_of_nonzero_samples>0) { r = 1.0 - (s1 / (20.0*number_of_nonzero_samples)); /* r = 1- average distance / 20mm 0 < r < ~1.0 where 1.0 is best and where 2.0cm is an arbitrary value to norm the dist, corresponding to a guess at the maximum average cortical variability so the max(r) could be greater than 1.0, but when it is, shouldn't chamfer have larger weight to drive the fit? */ } else r = 2.0; /* this is simply a value > 1.5, used as a flag to indicate that there were no samples used for the chamfer */ break; case NONLIN_CORRCOEFF: { /* Accumulators: * s1 = sum of source image values * s2 = sum of target image values * s3 = sum of squared source image values * s4 = sum of squared target image values * s5 = sum of source*target values * * normalization = #values considered */ if (number_of_nonzero_samples>0) { mean_s = s1 / number_of_nonzero_samples; mean_t = s2 / number_of_nonzero_samples; var_s = s3 / number_of_nonzero_samples - mean_s*mean_s; var_t = s4 / number_of_nonzero_samples - mean_t*mean_t; covariance = s5 / number_of_nonzero_samples - mean_s*mean_t; } else { mean_s = 0.0; mean_t = 0.0; var_s = 0.0; var_t = 0.0; covariance = 0.0; } if ((var_s < 0.00001) || (var_t < 0.00001) ) { r = 0.0; } else { r = covariance / sqrt( var_s*var_t ); } } break; case NONLIN_SQDIFF: /* normalization stores the number of samples in the sub-lattice. s1 stores the sum of the squared intensity differences */ r = -s1 /number_of_nonzero_samples; break; default: print_error_and_line_num("Objective function %d not supported in go_get_samples_with_offset",__FILE__, __LINE__,obj_func); } return(r); } }
void interpolate_deformation_slice(VIO_Volume volume, VIO_Real wx,Real wy,Real wz, VIO_Real def[]) { VIO_Real world[VIO_N_DIMENSIONS], v00,v01,v02,v03, v10,v11,v12,v13, v20,v21,v22,v23, v30,v31,v32,v33; long ind0, ind1, ind2; VIO_Real voxel[VIO_MAX_DIMENSIONS], frac[VIO_MAX_DIMENSIONS]; int i, xyzv[VIO_MAX_DIMENSIONS], sizes[VIO_MAX_DIMENSIONS]; double temp_result; def[VIO_X] = def[VIO_Y] = def[VIO_Z] = 0.0; world[VIO_X] = wx; world[VIO_Y] = wy; world[VIO_Z] = wz; convert_world_to_voxel(volume, wx, wy, wz, voxel); /* Check that the coordinate is inside the volume */ get_volume_sizes(volume, sizes); get_volume_XYZV_indices(volume, xyzv); if ((voxel[ xyzv[VIO_X] ] < 0) || (voxel[ xyzv[VIO_X] ] >=sizes[ xyzv[VIO_X]]) || (voxel[ xyzv[VIO_Y] ] < 0) || (voxel[ xyzv[VIO_Y] ] >=sizes[ xyzv[VIO_Y]]) || (voxel[ xyzv[VIO_Z] ] < 0) || (voxel[ xyzv[VIO_Z] ] >=sizes[ xyzv[VIO_Z]])) { return ; } if (/*(sizes[ xyzv[VIO_Z] ] == 1) &&*/ xyzv[VIO_Z]==1) { /* Get the whole and fractional part of the coordinate */ ind0 = FLOOR( voxel[ xyzv[VIO_Z] ] ); ind1 = FLOOR( voxel[ xyzv[VIO_Y] ] ); ind2 = FLOOR( voxel[ xyzv[VIO_X] ] ); frac[VIO_Y] = voxel[ xyzv[VIO_Y] ] - ind1; frac[VIO_X] = voxel[ xyzv[VIO_X] ] - ind2; if (sizes[xyzv[VIO_X]] < 4 || sizes[xyzv[VIO_Y]] < 4) { def[VIO_X] = get_volume_real_value(volume, 0, ind0, ind1, ind2, 0); def[VIO_Y] = get_volume_real_value(volume, 1, ind0, ind1, ind2, 0); def[VIO_Z] = get_volume_real_value(volume, 2, ind0, ind1, ind2, 0); return; } if (ind1==0) frac[VIO_Y] -= 1.0; else { ind1--; while ( ind1+3 >= sizes[xyzv[VIO_Y]] ) { ind1--; frac[VIO_Y] += 1.0; } } if (ind2==0) frac[VIO_X] -= 1.0; else { ind2--; while ( ind2+3 >= sizes[xyzv[VIO_X]] ) { ind2--; frac[VIO_X] += 1.0; } } for(i=0; i<3; i++) { GET_VOXEL_4D(v00, volume, i, ind0, ind1, ind2); GET_VOXEL_4D(v01, volume, i, ind0, ind1, ind2+1); GET_VOXEL_4D(v02, volume, i, ind0, ind1, ind2+2); GET_VOXEL_4D(v03, volume, i, ind0, ind1, ind2+3); GET_VOXEL_4D(v10, volume, i, ind0, ind1+1, ind2); GET_VOXEL_4D(v11, volume, i, ind0, ind1+1, ind2+1); GET_VOXEL_4D(v12, volume, i, ind0, ind1+1, ind2+2); GET_VOXEL_4D(v13, volume, i, ind0, ind1+1, ind2+3); GET_VOXEL_4D(v20, volume, i, ind0, ind1+2, ind2); GET_VOXEL_4D(v21, volume, i, ind0, ind1+2, ind2+1); GET_VOXEL_4D(v22, volume, i, ind0, ind1+2, ind2+2); GET_VOXEL_4D(v23, volume, i, ind0, ind1+2, ind2+3); GET_VOXEL_4D(v30, volume, i, ind0, ind1+3, ind2); GET_VOXEL_4D(v31, volume, i, ind0, ind1+3, ind2+1); GET_VOXEL_4D(v32, volume, i, ind0, ind1+3, ind2+2); GET_VOXEL_4D(v33, volume, i, ind0, ind1+3, ind2+3); CUBIC_BIVAR(v00,v01,v02,v03, \ v10,v11,v12,v13, \ v20,v21,v22,v23, \ v30,v31,v32,v33, \ frac[VIO_Y],frac[VIO_X], temp_result); def[i] = CONVERT_VOXEL_TO_VALUE(volume,temp_result); } } else { print ("\n\nxyzv[] = %d %d %d %d\n",xyzv[0],xyzv[1],xyzv[2],xyzv[3]); print ("\n\nsizes[]= %d %d %d %d\n",sizes[0],sizes[1],sizes[2],sizes[3]); print_error_and_line_num("error in slice_interpolate", __FILE__, __LINE__); } }
static void resample_the_deformation_field(Arg_Data *globals) { VIO_Volume existing_field, new_field; VIO_Real vector_val[3], XYZstart[ VIO_MAX_DIMENSIONS ], wstart[ VIO_MAX_DIMENSIONS ], start[ VIO_MAX_DIMENSIONS ], XYZstep[ VIO_MAX_DIMENSIONS ], step[ VIO_MAX_DIMENSIONS ], step2[ VIO_MAX_DIMENSIONS ], s1[ VIO_MAX_DIMENSIONS ], voxel[ VIO_MAX_DIMENSIONS ], dir[3][3]; int i, siz[ VIO_MAX_DIMENSIONS ], index[ VIO_MAX_DIMENSIONS ], xyzv[ VIO_MAX_DIMENSIONS ], XYZcount[ VIO_MAX_DIMENSIONS ], count[ VIO_MAX_DIMENSIONS ]; VIO_General_transform *non_lin_part; VectorR XYZdirections[ VIO_MAX_DIMENSIONS ]; VIO_Real del_x, del_y, del_z, wx, wy,wz; VIO_progress_struct progress; char **data_dim_names; /* get the nonlinear part of the transformation */ existing_field = (VIO_Volume)NULL; non_lin_part = get_nth_general_transform(globals->trans_info.transformation, get_n_concated_transforms( globals->trans_info.transformation) -1); if (get_transform_type( non_lin_part ) == GRID_TRANSFORM){ existing_field = (VIO_Volume)(non_lin_part->displacement_volume); } else { for(i=0; i<get_n_concated_transforms(globals->trans_info.transformation); i++) print ("Transform %d is of type %d\n",i, get_transform_type( get_nth_general_transform(globals->trans_info.transformation, i) )); print_error_and_line_num("Cannot find the deformation field transform to resample", __FILE__, __LINE__); } /* build a vector volume to store the Grid VIO_Transform */ new_field = create_volume(4, dim_name_vector_vol, NC_DOUBLE, TRUE, 0.0, 0.0); get_volume_XYZV_indices(new_field, xyzv); for(i=0; i<VIO_N_DIMENSIONS; i++) step2[i] = globals->step[i]; /* get new start, count, step and directions, all returned in X, Y, Z order. */ set_up_lattice(existing_field, step2, XYZstart, wstart, XYZcount, XYZstep, XYZdirections); /* reset count and step to be in volume order */ for(i=0; i<VIO_N_DIMENSIONS; i++) { start[ i ] = wstart[ i ]; count[ xyzv[i] ] = XYZcount[ i ]; step[ xyzv[i] ] = XYZstep[ i ]; } /* add info for the vector dimension */ count[xyzv[VIO_Z+1]] = 3; step[xyzv[VIO_Z+1]] = 0.0; /* use the sign of the step returned to set the true step size */ for(i=0; i<VIO_N_DIMENSIONS; i++) { if (step[xyzv[i]]<0) step[xyzv[i]] = -1.0 * fabs(globals->step[i]); else step[xyzv[i]] = fabs(globals->step[i]); } for(i=0; i<VIO_MAX_DIMENSIONS; i++) /* set the voxel origin, used in the vol def */ voxel[i] = 0.0; set_volume_sizes( new_field, count); set_volume_separations( new_field, step); /* set_volume_voxel_range( new_field, -MY_MAX_VOX, MY_MAX_VOX); set_volume_real_range( new_field, -1.0*globals->trans_info.max_def_magnitude, globals->trans_info.max_def_magnitude); - no longer needed, because now using doubles*/ set_volume_translation( new_field, voxel, start); for(i=0; i<VIO_N_DIMENSIONS; i++) { dir[VIO_X][i]=XYZdirections[VIO_X].coords[i]; dir[VIO_Y][i]=XYZdirections[VIO_Y].coords[i]; dir[VIO_Z][i]=XYZdirections[VIO_Z].coords[i]; } set_volume_direction_cosine(new_field,xyzv[VIO_X],dir[VIO_X]); set_volume_direction_cosine(new_field,xyzv[VIO_Y],dir[VIO_Y]); set_volume_direction_cosine(new_field,xyzv[VIO_Z],dir[VIO_Z]); /* make sure that the vector dimension is named! */ data_dim_names = get_volume_dimension_names(new_field); if( strcmp( data_dim_names[ xyzv[VIO_Z+1] ] , MIvector_dimension ) != 0 ) { ALLOC((new_field)->dimension_names[xyzv[VIO_Z+1]], \ strlen(MIvector_dimension ) + 1 ); (void) strcpy( (new_field)->dimension_names[xyzv[VIO_Z+1]], MIvector_dimension ); } delete_dimension_names(new_field, data_dim_names); if (globals->flags.debug) { print ("in resample_deformation_field:\n"); print ("xyzv[axes] = %d, %d, %d, %d\n",xyzv[VIO_X],xyzv[VIO_Y],xyzv[VIO_Z],xyzv[VIO_Z+1]); get_volume_sizes(new_field, siz); get_volume_separations(new_field, s1); print ("seps: %7.3f %7.3f %7.3f %7.3f %7.3f \n",s1[0],s1[1],s1[2],s1[3],s1[4]); print ("size: %7d %7d %7d %7d %7d \n",siz[0],siz[1],siz[2],siz[3],siz[4]); } alloc_volume_data(new_field); if (globals->flags.verbose>0) initialize_progress_report( &progress, FALSE, count[xyzv[VIO_X]], "Interpolating new field" ); /* now resample the values from the input deformation */ for(i=0; i<VIO_MAX_DIMENSIONS; i++) { voxel[i] = 0.0; index[i] = 0; } for(index[xyzv[VIO_X]]=0; index[xyzv[VIO_X]]<count[xyzv[VIO_X]]; index[xyzv[VIO_X]]++) { voxel[xyzv[VIO_X]] = (VIO_Real)index[xyzv[VIO_X]]; for(index[xyzv[VIO_Y]]=0; index[xyzv[VIO_Y]]<count[xyzv[VIO_Y]]; index[xyzv[VIO_Y]]++) { voxel[xyzv[VIO_Y]] = (VIO_Real)index[xyzv[VIO_Y]]; for(index[xyzv[VIO_Z]]=0; index[xyzv[VIO_Z]]<count[xyzv[VIO_Z]]; index[xyzv[VIO_Z]]++) { voxel[xyzv[VIO_Z]] = (VIO_Real)index[xyzv[VIO_Z]]; convert_voxel_to_world(new_field, voxel, &wx,&wy,&wz); grid_transform_point(non_lin_part, wx, wy, wz, &del_x, &del_y, &del_z); /* get just the deformation part */ del_x = del_x - wx; del_y = del_y - wy; del_z = del_z - wz; /* del_x = del_y = del_z = 0.0; */ vector_val[0] = CONVERT_VALUE_TO_VOXEL(new_field, del_x); vector_val[1] = CONVERT_VALUE_TO_VOXEL(new_field, del_y); vector_val[2] = CONVERT_VALUE_TO_VOXEL(new_field, del_z); for(index[xyzv[VIO_Z+1]]=0; index[xyzv[VIO_Z+1]]<3; index[xyzv[VIO_Z+1]]++) { SET_VOXEL(new_field, \ index[0], index[1], index[2], index[3], index[4], \ vector_val[ index[ xyzv[ VIO_Z+1] ] ]); } } } if (globals->flags.verbose>0) update_progress_report( &progress,index[xyzv[VIO_X]]+1); } if (globals->flags.verbose>0) terminate_progress_report( &progress ); /* delete and free up old data */ delete_volume(non_lin_part->displacement_volume); /* set new volumes into transform */ non_lin_part->displacement_volume = new_field; }