/* binarise a volume between a range */ Volume *binarise(Volume * vol, double floor, double ceil, double fg, double bg) { int x, y, z; int sizes[MAX_VAR_DIMS]; double value; progress_struct progress; if(verbose){ fprintf(stdout, "Binarising, range: [%g:%g] fg/bg: [%g:%g]\n", floor, ceil, fg, bg); } get_volume_sizes(*vol, sizes); initialize_progress_report(&progress, FALSE, sizes[2], "Binarise"); for(z = sizes[0]; z--;){ for(y = sizes[1]; y--;){ for(x = sizes[2]; x--;){ value = get_volume_voxel_value(*vol, z, y, x, 0, 0); if((value >= floor) && (value <= ceil)){ set_volume_voxel_value(*vol, z, y, x, 0, 0, fg); } else { set_volume_voxel_value(*vol, z, y, x, 0, 0, bg); } } } update_progress_report(&progress, z + 1); } terminate_progress_report(&progress); return (vol); }
image_metadata * read_minc(char *filename, float **image, int *sizes){ VIO_Volume volume; VIO_Real dummy[3]; image_metadata *meta; if( input_volume(filename, 3, NULL, NC_UNSPECIFIED, FALSE, 0.0, 0.0, TRUE, &volume, (minc_input_options *) NULL ) != VIO_OK ) return( NULL ); meta = (image_metadata *)calloc( 1 , sizeof(image_metadata) ) ; meta->start = calloc(3,sizeof(float)); meta->step = calloc(3,sizeof(float)); meta->length = calloc(3,sizeof(int)); get_volume_sizes(volume,sizes); *image=malloc(sizes[0]*sizes[1]*sizes[2]*sizeof(**image)); set_volume(*image, volume, sizes); meta->length[0]=sizes[0]; meta->length[1]=sizes[1]; meta->length[2]=sizes[2]; get_volume_starts(volume,dummy); meta->start[0]=dummy[0]; meta->start[1]=dummy[1]; meta->start[2]=dummy[2]; get_volume_separations(volume,dummy); meta->step[0]=dummy[0]; meta->step[1]=dummy[1]; meta->step[2]=dummy[2]; delete_volume(volume); return meta; }
/* clamp a volume between a range */ Volume *clamp(Volume * vol, double floor, double ceil, double bg) { int x, y, z; int sizes[MAX_VAR_DIMS]; double value; progress_struct progress; if(verbose){ fprintf(stdout, "Clamping, range: [%g:%g] bg: %g\n", floor, ceil, bg); } get_volume_sizes(*vol, sizes); initialize_progress_report(&progress, FALSE, sizes[2], "Clamping"); for(z = sizes[0]; z--;){ for(y = sizes[1]; y--;){ for(x = sizes[2]; x--;){ value = get_volume_voxel_value(*vol, z, y, x, 0, 0); if((value < floor) || (value > ceil)){ set_volume_voxel_value(*vol, z, y, x, 0, 0, bg); } } } update_progress_report(&progress, z + 1); } terminate_progress_report(&progress); return (vol); }
void scale_volume(VIO_Volume * vol, double o_min, double o_max, double min, double max) { double value, a, b; int sizes[MAX_VAR_DIMS]; int i, j, k, v; VIO_progress_struct progress; get_volume_sizes(*vol, sizes); /* rescale the volume */ a = (max - min) / (o_max - o_min); b = min - (o_min * a); initialize_progress_report(&progress, FALSE, sizes[Z_IDX], "Rescaling Volume"); for(k = sizes[Z_IDX]; k--;){ for(j = sizes[Y_IDX]; j--;){ for(i = sizes[X_IDX]; i--;){ for(v = sizes[V_IDX]; v--;){ value = (get_volume_real_value(*vol, k, j, i, v, 0) * a) + b; set_volume_real_value(*vol, k, j, i, v, 0, value); } } } update_progress_report(&progress, k + 1); } terminate_progress_report(&progress); if(verbose){ fprintf(stdout, " + rescaled data range: [%g:%g]\n", min, max); } set_volume_real_range(*vol, min, max); }
int write_volume(char *name, VIO_Volume vol, float *data){ int i,j,k,index,sizes[5]; float min=FLT_MAX,max=FLT_MIN; fprintf(stderr,"Writing %s\n",name); get_volume_sizes(vol,sizes); for (i=0;i<sizes[0];i++){ for (j=0;j<sizes[1];j++){ for (k=0;k<sizes[2];k++){ index=i*sizes[2]*sizes[1] + j*sizes[2] + k; min=MIN(min,data[index]); max=MAX(max,data[index]); } } } set_volume_real_range(vol,min,max); get_volume(data, vol, sizes); output_volume( name, NC_FLOAT,FALSE,min,max,vol,NULL, (minc_output_options *)NULL); return STATUS_OK; }
/* Build the target lattice by transforming the source points through the current non-linear transformation stored in: Glinear_transform and Gsuper_d{x,y,z} deformation volumes both input (px,py,pz) and output (tx,ty,tz) coordinate lists are in WORLD COORDINATES */ void build_target_lattice_using_super_sampled_def( float px[], float py[], float pz[], float tx[], float ty[], float tz[], int len, int dim) { int i,j, sizes[VIO_MAX_DIMENSIONS], xyzv[VIO_MAX_DIMENSIONS]; VIO_Real def_vector[VIO_N_DIMENSIONS], voxel[VIO_MAX_DIMENSIONS], x,y,z; long index[VIO_MAX_DIMENSIONS]; get_volume_sizes(Gsuper_sampled_vol,sizes); get_volume_XYZV_indices(Gsuper_sampled_vol,xyzv); for(i=1; i<=len; i++) { /* apply linear part of the transformation */ general_transform_point(Glinear_transform, (VIO_Real)px[i], (VIO_Real)py[i], (VIO_Real)pz[i], &x, &y, &z); /* now get the non-linear part, using nearest neighbour interpolation in the super-sampled deformation volume. */ convert_world_to_voxel(Gsuper_sampled_vol, x,y,z, voxel); if ((voxel[ xyzv[VIO_X] ] >= -0.5) && (voxel[ xyzv[VIO_X] ] < sizes[xyzv[VIO_X]]-0.5) && (voxel[ xyzv[VIO_Y] ] >= -0.5) && (voxel[ xyzv[VIO_Y] ] < sizes[xyzv[VIO_Y]]-0.5) && (voxel[ xyzv[VIO_Z] ] >= -0.5) && (voxel[ xyzv[VIO_Z] ] < sizes[xyzv[VIO_Z]]-0.5) ) { for(j=0; j<3; j++) index[ xyzv[j] ] = (long) (voxel[ xyzv[j] ]+0.5); for(index[xyzv[VIO_Z+1]]=0; index[xyzv[VIO_Z+1]]<sizes[xyzv[VIO_Z+1]]; index[xyzv[VIO_Z+1]]++) GET_VALUE_4D(def_vector[ index[ xyzv[VIO_Z+1] ] ], \ Gsuper_sampled_vol, \ index[0], index[1], index[2], index[3]); x += def_vector[VIO_X]; y += def_vector[VIO_Y]; z += def_vector[VIO_Z]; } tx[i] = (float)x; ty[i] = (float)y; tz[i] = (float)z; } }
VIO_BOOL vol_cog(VIO_Volume d1, VIO_Volume m1, float *centroid) { VIO_Real sx,sy,sz,si, true_value, tx,ty,tz; int i,j,k, count[VIO_MAX_DIMENSIONS]; sx = 0.0; /* init centroid vars */ sy = 0.0; sz = 0.0; si = 0.0; get_volume_sizes(d1, count); /* loop over all voxels */ for(i=0; i<count[0]; i++) for(j=0; j<count[1]; j++) for(k=0; k<count[2]; k++) { convert_3D_voxel_to_world(d1, i,j,k, &tx, &ty, &tz); if (point_not_masked(m1, tx, ty, tz)) { GET_VALUE_3D( true_value, d1, i,j,k); sx += tx * true_value; sy += ty * true_value; sz += tz * true_value; si += true_value; } } /* calc centroids */ if (si!=0.0) { centroid[0] = sx/ si; centroid[1] = sy/ si; centroid[2] = sz/ si; return(TRUE); } else { return(FALSE); } }
/* perform an erosion on a volume */ Volume *erosion_kernel(Kernel * K, Volume * vol) { int x, y, z, c; double value; int sizes[MAX_VAR_DIMS]; progress_struct progress; Volume tmp_vol; if(verbose){ fprintf(stdout, "Erosion kernel\n"); } get_volume_sizes(*vol, sizes); initialize_progress_report(&progress, FALSE, sizes[2], "Erosion"); /* copy the volume */ tmp_vol = copy_volume(*vol); for(z = -K->pre_pad[2]; z < sizes[0] - K->post_pad[2]; z++){ for(y = -K->pre_pad[1]; y < sizes[1] - K->post_pad[1]; y++){ for(x = -K->pre_pad[0]; x < sizes[2] - K->post_pad[0]; x++){ value = get_volume_real_value(tmp_vol, z, y, x, 0, 0); for(c = 0; c < K->nelems; c++){ if(get_volume_real_value(*vol, z + K->K[c][2], y + K->K[c][1], x + K->K[c][0], 0 + K->K[c][3], 0 + K->K[c][4]) > value){ set_volume_real_value(*vol, z + K->K[c][2], y + K->K[c][1], x + K->K[c][0], 0 + K->K[c][3], 0 + K->K[c][4], value * K->K[c][5]); } } value = get_volume_real_value(tmp_vol, z, y, x, 0, 0); } } update_progress_report(&progress, z + 1); } delete_volume(tmp_vol); terminate_progress_report(&progress); return (vol); }
/* pad a volume using the background value */ Volume *pad(Kernel * K, Volume * vol, double bg) { int x, y, z; int sizes[MAX_VAR_DIMS]; get_volume_sizes(*vol, sizes); /* z */ for(y = 0; y < sizes[1]; y++){ for(x = 0; x < sizes[2]; x++){ for(z = 0; z < -K->pre_pad[2]; z++){ set_volume_real_value(*vol, z, y, x, 0, 0, bg); } for(z = sizes[0] - K->post_pad[2]; z < sizes[0]; z++){ set_volume_real_value(*vol, z, y, x, 0, 0, bg); } } } /* y */ for(z = 0; z < sizes[0]; z++){ for(x = 0; x < sizes[2]; x++){ for(y = 0; y < -K->pre_pad[1]; y++){ set_volume_real_value(*vol, z, y, x, 0, 0, bg); } for(y = sizes[1] - K->post_pad[1]; y < sizes[1]; y++){ set_volume_real_value(*vol, z, y, x, 0, 0, bg); } } } /* x */ for(z = 0; z < sizes[0]; z++){ for(y = 0; y < sizes[1]; y++){ for(x = 0; x < -K->pre_pad[0]; x++){ set_volume_real_value(*vol, z, y, x, 0, 0, bg); } for(x = sizes[2] - K->post_pad[0]; x < sizes[2]; x++){ set_volume_real_value(*vol, z, y, x, 0, 0, bg); } } } return (vol); }
void calc_volume_range(VIO_Volume * vol, double *min, double *max) { int x, y, z; int sizes[MAX_VAR_DIMS]; double value; VIO_progress_struct progress; *min = DBL_MAX; *max = -DBL_MIN; get_volume_sizes(*vol, sizes); initialize_progress_report(&progress, FALSE, sizes[2], "Finding Range"); for(z = sizes[0]; z--;){ for(y = sizes[1]; y--;){ for(x = sizes[2]; x--;){ value = get_volume_voxel_value(*vol, z, y, x, 0, 0); if(value < *min){ *min = value; } else if(value > *max){ *max = value; } } } update_progress_report(&progress, z + 1); } terminate_progress_report(&progress); if (*min == *max) { *max = *min + 1.0; } if(verbose){ fprintf(stdout, "Found range of [%g:%g]\n", *min, *max); } }
VIO_BOOL vol_to_cov(VIO_Volume d1, VIO_Volume m1, float centroid[4], float covar[4][4], double *step) { VectorR vector_step, slice_step, row_step, col_step; PointR starting_offset, starting_origin, starting_position, slice, row, col, voxel; VIO_Real tx,ty,tz; int i,r,c,s, limits[VOL_NDIMS]; float t, sxx,syy,szz, sxy,syz,sxz, sx,sy,sz,si; VIO_Real thickness[3]; int sizes[3]; VIO_Real true_value; get_volume_separations(d1, thickness); get_volume_sizes(d1, sizes); /* build sampling lattice info */ for(i=0; i<3; i++) { step[i] *= thickness[i] / fabs( thickness[i]); } fill_Vector( col_step, step[COL_IND], 0.0, 0.0 ); fill_Vector( row_step, 0.0, step[ROW_IND], 0.0 ); fill_Vector( slice_step, 0.0, 0.0, step[SLICE_IND] ); convert_3D_voxel_to_world(d1, 0.0, 0.0, 0.0, &tx, &ty, &tz); fill_Point( starting_origin, tx, ty, tz); for(i=0; i<3; i++) { /* for each dim, get # of steps in that direction, and set starting offset */ t = sizes[i] * thickness[i] / step[i]; limits[i] = abs( t ); Point_coord( starting_offset, (i) ) = ( (sizes[i]-1)*thickness[i] - (limits[i] * step[i] ) ) / 2.0; } ADD_POINTS( starting_position, starting_origin, starting_offset ); /* */ /* calculate centroids first */ sx = 0.0; sy = 0.0; sz = 0.0; si = 0.0; for(s=0; s<=limits[SLICE_IND]; s++) { SCALE_VECTOR( vector_step, slice_step, s); ADD_POINT_VECTOR( slice, starting_position, vector_step ); for(r=0; r<=limits[ROW_IND]; r++) { SCALE_VECTOR( vector_step, row_step, r); ADD_POINT_VECTOR( row, slice, vector_step ); SCALE_POINT( col, row, 1.0); /* init first col position */ for(c=0; c<=limits[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))) { if (INTERPOLATE_TRUE_VALUE( d1, &voxel, &true_value )) { sx += Point_x(col) * true_value; sy += Point_y(col) * true_value; sz += Point_z(col) * true_value; si += true_value; } /* else requested voxel is just outside volume., so ignore it */ } ADD_POINT_VECTOR( col, col, col_step ); } } } if (si!=0.0) { centroid[1] = sx/ si; centroid[2] = sy/ si; centroid[3] = sz/ si; sxx = syy = szz = 0.0; sxy = syz = sxz = 0.0; /* now calculate variances and co-variances */ for(s=0; s<=limits[VIO_Z]; s++) { SCALE_VECTOR( vector_step, slice_step, s); ADD_POINT_VECTOR( slice, starting_position, vector_step ); for(r=0; r<=limits[VIO_Y]; r++) { SCALE_VECTOR( vector_step, row_step, r); ADD_POINT_VECTOR( row, slice, vector_step ); SCALE_POINT( col, row, 1.0); /* init first col position */ for(c=0; c<=limits[VIO_X]; 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))) { if (INTERPOLATE_TRUE_VALUE( d1, &voxel, &true_value )) { sxx += (Point_x( col )-centroid[1]) * (Point_x( col )-centroid[1]) * true_value; syy += (Point_y( col )-centroid[2]) * (Point_y( col )-centroid[2]) * true_value; szz += (Point_z( col )-centroid[3]) * (Point_z( col )-centroid[3]) * true_value; sxy += (Point_x( col )-centroid[1]) * (Point_y( col )-centroid[2]) * true_value; syz += (Point_y( col )-centroid[2]) * (Point_z( col )-centroid[3]) * true_value; sxz += (Point_x( col )-centroid[1]) * (Point_z( col )-centroid[3]) * true_value; } /* else requested voxel is just outside volume., so ignore it */ } ADD_POINT_VECTOR( col, col, col_step ); } } } covar[1][1] = sxx/si; covar[1][2] = sxy/si; covar[1][3] = sxz/si; covar[2][1] = sxy/si; covar[2][2] = syy/si; covar[2][3] = syz/si; covar[3][1] = sxz/si; covar[3][2] = syz/si; covar[3][3] = szz/si; return(TRUE); } else { return(FALSE); } }
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); }
void make_zscore_volume(VIO_Volume d1, VIO_Volume m1, VIO_Real *threshold) { unsigned long count; int stat_count, sizes[VIO_MAX_DIMENSIONS], s,r,c; VIO_Real wx,wy,wz, valid_min_dvoxel, valid_max_dvoxel, min,max, sum, sum2, mean, var, std, data_vox,data_val, thick[VIO_MAX_DIMENSIONS]; PointR voxel; VIO_Volume vol; VIO_progress_struct progress; /* get default information from data and mask */ /* build temporary working volume */ vol = copy_volume_definition(d1, NC_UNSPECIFIED, FALSE, 0.0, 0.0); set_volume_real_range(vol, MIN_ZRANGE, MAX_ZRANGE); get_volume_sizes(d1, sizes); get_volume_separations(d1, thick); get_volume_voxel_range(d1, &valid_min_dvoxel, &valid_max_dvoxel); /* initialize counters and sums */ count = 0; sum = 0.0; sum2 = 0.0; min = 1e38; max = -1e38; stat_count = 0; initialize_progress_report(&progress, FALSE, sizes[0]*sizes[1]*sizes[2] + 1, "Tally stats" ); /* do first pass, to get mean and std */ for(s=0; s<sizes[0]; s++) { for(r=0; r<sizes[1]; r++) { for(c=0; c<sizes[2]; c++) { stat_count++; update_progress_report( &progress, stat_count); convert_3D_voxel_to_world(d1, (VIO_Real)s, (VIO_Real)r, (VIO_Real)c, &wx, &wy, &wz); if (m1 != NULL) { convert_3D_world_to_voxel(m1, wx, wy, wz, &Point_x(voxel), &Point_y(voxel), &Point_z(voxel)); } else { wx = 0.0; wy = 0.0; wz = 0.0; } if (point_not_masked(m1, wx,wy,wz)) { GET_VOXEL_3D( data_vox, d1 , s, r, c ); if (data_vox >= valid_min_dvoxel && data_vox <= valid_max_dvoxel) { data_val = CONVERT_VOXEL_TO_VALUE(d1, data_vox); if (data_val > *threshold) { sum += data_val; sum2 += data_val*data_val; count++; if (data_val < min) min = data_val; else if (data_val > max) max = data_val; } } } } } } terminate_progress_report( &progress ); stat_count = 0; initialize_progress_report(&progress, FALSE, sizes[0]*sizes[1]*sizes[2] + 1, "Zscore convert" ); /* calc mean and std */ mean = sum / (float)count; var = ((float)count*sum2 - sum*sum) / ((float)count*((float)count-1)); std = sqrt(var); min = 1e38; max = -1e38; /* replace the voxel values */ for(s=0; s<sizes[0]; s++) { for(r=0; r<sizes[1]; r++) { for(c=0; c<sizes[2]; c++) { stat_count++; update_progress_report( &progress, stat_count); GET_VOXEL_3D( data_vox, d1, s, r, c ); if (data_vox >= valid_min_dvoxel && data_vox <= valid_max_dvoxel) { data_val = CONVERT_VOXEL_TO_VALUE(d1, data_vox); if (data_val > *threshold) { /* instead of data_val = CONVERT_VALUE_TO_VOXEL(d1, data_vox); i will use data_val = CONVERT_VALUE_TO_VOXEL(d1, vol); since the values in vol are changed with respect to the new z-score volume */ data_val = (data_val - mean) / std; if (data_val< MIN_ZRANGE) data_val = MIN_ZRANGE; if (data_val> MAX_ZRANGE) data_val = MAX_ZRANGE; data_vox = CONVERT_VALUE_TO_VOXEL( vol, data_val); if (data_val < min) { min = data_val; } else { if (data_val > max) max = data_val; } } else data_vox = -DBL_MAX; /* should be fill_value! */ SET_VOXEL_3D( d1 , s, r, c, data_vox ); } } } } terminate_progress_report( &progress ); set_volume_real_range(d1, MIN_ZRANGE, MAX_ZRANGE); /* reset the data volume's range */ *threshold = (*threshold - mean) / std; delete_volume(vol); }
int main(int argc, char *argv[]) { int count, i,j,k, p,r,s, flag, sizes1[3],sizes2[3], sizes3[3]; VIO_Real thresh; VIO_Real mean1, std1, mean2, std2, corr, v1, v2, v3, s1, s2, s12, u,v,w, x,y,z; VIO_Status status; VIO_Volume data1, data2, mask; char *f1, *f2, *mf; if (argc<4) { print ("usage: xcorr_vol.c vol1.mnc vol2.mnc threshold [mask.mnc]\n"); exit(EXIT_FAILURE); } prog_name = argv[0]; f1 = argv[1]; f2 = argv[2]; thresh = atof(argv[3]); if (argc==5) mf = argv[4]; status = input_volume(f1, 3, default_dim_names, NC_UNSPECIFIED, FALSE, 0.0,0.0, TRUE, &data1, (minc_input_options *)NULL); if (status!=VIO_OK) { print ("Error reading %s.\n",f1); exit(EXIT_FAILURE); } status = input_volume(f2, 3, default_dim_names, NC_UNSPECIFIED, FALSE, 0.0,0.0, TRUE, &data2, (minc_input_options *)NULL); if (status!=VIO_OK) { print ("Error reading %s.\n",f2); exit(EXIT_FAILURE); } if (argc==5) { status = input_volume(mf, 3, default_dim_names, NC_UNSPECIFIED, FALSE, 0.0,0.0, TRUE, &mask, (minc_input_options *)NULL); if (status!=VIO_OK) { print ("Error reading %s.\n",mf); exit(EXIT_FAILURE); } get_volume_sizes(mask,sizes3); } else mask = (VIO_Volume)NULL; get_volume_sizes(data1,sizes1); get_volume_sizes(data2,sizes2); if (sizes1[0] != sizes2[0] || sizes1[1] != sizes2[1] || sizes1[2] != sizes2[2]) { print ("Size mismatch between %s and %s.\n",f1,f2); print ("%d,%d,%d != %d,%d,%d\n", sizes1[0],sizes1[1],sizes1[2], sizes2[0],sizes2[1],sizes2[2]); exit(EXIT_FAILURE); } get_zscore_values(data1, mask, thresh, &mean1, &std1); get_zscore_values(data2, mask, thresh, &mean2, &std2); if (std1==0.0 || std2==0.0) { print ("No standard deviation in one of %s and %s.\n",f1,f2); exit(EXIT_FAILURE); } count = 0; s1 = s2 = s12 = 0.0; for(i=0; i<sizes1[0]; i++) { for(j=0; j<sizes1[1]; j++) { for(k=0; k<sizes1[2]; k++) { flag = TRUE; if (mask != NULL) { convert_3D_voxel_to_world(data1, i,j,k, &x, &y, &z); convert_3D_world_to_voxel(mask, x,y,z, &u, &v, &w); p = VIO_ROUND(u); r = VIO_ROUND(v); s = VIO_ROUND(w); if (p>=0 && p<sizes3[0] && r>=0 && r<sizes3[1] && s>=0 && s<sizes3[2]) { GET_VALUE_3D( v3 , mask, p, r, s); if (v3 < 0.5) flag = FALSE; } else flag = FALSE; } if (flag ) { GET_VALUE_3D( v1 , data1, i, j, k); GET_VALUE_3D( v2 , data2, i, j, k); v1 = (v1 - mean1) / std1; v2 = (v2 - mean2) / std2; v1 = v1 - v2; s12 += fabs(v1); count++; } } } } if (count==0) { exit(EXIT_FAILURE); print ("No masked voxels\n"); } else { corr = s12 / count; print ("%15.12f\n",corr); exit(EXIT_SUCCESS); } }
void get_zscore_values(VIO_Volume d1, VIO_Volume m1, VIO_Real threshold, VIO_Real *mean, VIO_Real *std) { unsigned long count; int sizes[VIO_MAX_DIMENSIONS], s,r,c; VIO_Real wx,wy,wz, valid_min_dvoxel, valid_max_dvoxel, min,max, sum, sum2, var, data_vox,data_val, thick[VIO_MAX_DIMENSIONS]; /* get default information from data and mask */ get_volume_sizes(d1, sizes); get_volume_separations(d1, thick); get_volume_voxel_range(d1, &valid_min_dvoxel, &valid_max_dvoxel); /* initialize counters and sums */ count = 0; sum = 0.0; sum2 = 0.0; min = FLT_MAX; max = -FLT_MAX; /* get mean and std */ for(s=0; s<sizes[0]; s++) { for(r=0; r<sizes[1]; r++) { for(c=0; c<sizes[2]; c++) { convert_3D_voxel_to_world(d1, (VIO_Real)s, (VIO_Real)r, (VIO_Real)c, &wx, &wy, &wz); if (point_not_masked(m1, wx,wy,wz)) { GET_VOXEL_3D( data_vox, d1 , s, r, c ); if (data_vox >= valid_min_dvoxel && data_vox <= valid_max_dvoxel) { data_val = CONVERT_VOXEL_TO_VALUE(d1, data_vox); if (data_val > threshold) { sum += data_val; sum2 += data_val*data_val; count++; if (data_val < min) min = data_val; else if (data_val > max) max = data_val; } } } } } } /* calc mean and std */ *mean = sum / (float)count; var = ((float)count*sum2 - sum*sum) / ((float)count*((float)count-1)); *std = sqrt(var); }
/* regrid a point in a file using the input co-ordinate and data */ void regrid_point(VIO_Volume * totals, VIO_Volume * weights, double x, double y, double z, int v_size, double *data_buf) { int sizes[MAX_VAR_DIMS]; VIO_Real steps[MAX_VAR_DIMS]; VIO_Real starts[MAX_VAR_DIMS]; int start_idx[3]; int stop_idx[3]; double value, weight; double euc_dist; double euc[3]; double c_pos[3]; int i, j, k, v; double coord[3]; /* target point in mm coordinates, in X, Y, Z order */ VIO_Transform dircos, invdircos; VIO_Vector vector; VIO_Real dir[3]; /* the coord used below has to be in mm coordinates in the dircos space of the target volume. Hence the manipulations with the vols direction_cosines */ make_identity_transform(&dircos); get_volume_direction_cosine(*totals, perm[0], dir); fill_Vector(vector, dir[0], dir[1], dir[2]); set_transform_x_axis(&dircos, &vector); get_volume_direction_cosine(*totals, perm[1], dir); fill_Vector(vector, dir[0], dir[1], dir[2]); set_transform_y_axis(&dircos, &vector); get_volume_direction_cosine(*totals, perm[2], dir); fill_Vector(vector, dir[0], dir[1], dir[2]); set_transform_z_axis(&dircos, &vector); for(i = 0; i < 4; i++){ for(j = 0; j < 4; j++){ Transform_elem(invdircos, i, j) = Transform_elem(dircos, j, i); } } transform_point(&invdircos, x, y, z, &coord[0], &coord[1], &coord[2]); get_volume_sizes(*totals, sizes); /* in volume voxel order, ie z,y,x with x fastest */ get_volume_separations(*totals, steps); get_volume_starts(*totals, starts); /* figure out the neighbouring voxels start and stop (in voxel co-ordinates) */ for(i = 0; i < 3; i++){ /* go through x, y and z */ start_idx[i] = (int)rint((coord[i] - starts[perm[i]] - regrid_radius[i]) / steps[perm[i]]); stop_idx[i] = start_idx[i] + rint((regrid_radius[i] * 2) / steps[perm[i]]); /* flip if required */ if(start_idx[i] > stop_idx[i]){ value = start_idx[i]; start_idx[i] = stop_idx[i]; stop_idx[i] = value; } /* check that we aren't off the edge */ if(start_idx[i] < 0){ start_idx[i] = 0; } if(stop_idx[i] >= sizes[perm[i]]){ stop_idx[i] = sizes[perm[i]] - 1; } } /* loop over the neighbours, getting euclidian distance */ c_pos[0] = starts[perm[0]] + (start_idx[0] * steps[perm[0]]); for(i = start_idx[0]; i <= stop_idx[0]; i++){ euc[0] = fabs(c_pos[0] - coord[0]); c_pos[1] = starts[perm[1]] + (start_idx[1] * steps[perm[1]]); for(j = start_idx[1]; j <= stop_idx[1]; j++){ euc[1] = fabs(c_pos[1] - coord[1]); c_pos[2] = starts[perm[2]] + (start_idx[2] * steps[perm[2]]); for(k = start_idx[2]; k <= stop_idx[2]; k++){ euc[2] = fabs(c_pos[2] - coord[2]); euc_dist = sqrt(SQR2(euc[0]) + SQR2(euc[1]) + SQR2(euc[2])); if((regrid_radius[0] == 0 || euc[0] <= regrid_radius[0]) && (regrid_radius[1] == 0 || euc[1] <= regrid_radius[1]) && (regrid_radius[2] == 0 || euc[2] <= regrid_radius[2])){ /* calculate the weighting factor */ switch (regrid_type){ default: fprintf(stderr, "Erk! unknown regrid_type. File: %s Line: %d\n", __FILE__, __LINE__); exit(EXIT_FAILURE); break; case NEAREST_FUNC: case LINEAR_FUNC: weight = euc_dist; break; case KAISERBESSEL_FUNC: weight = gsl_sf_bessel_I0(regrid_sigma[0] * sqrt(1 - SQR2(euc[0] / regrid_radius[0]))) * gsl_sf_bessel_I0(regrid_sigma[1] * sqrt(1 - SQR2(euc[1] / regrid_radius[1]))) * gsl_sf_bessel_I0(regrid_sigma[2] * sqrt(1 - SQR2(euc[2] / regrid_radius[2]))) / SQR3((regrid_radius[0] + regrid_radius[1] + regrid_radius[2]) / 3); break; case GAUSSIAN_FUNC: weight = exp(-SQR2(euc[0]) / SQR2(regrid_sigma[0])) * exp(-SQR2(euc[1]) / SQR2(regrid_sigma[1])) * exp(-SQR2(euc[2]) / SQR2(regrid_sigma[2])); break; } /* set data values */ if(regrid_type == NEAREST_FUNC){ value = get_volume_real_value(*weights, k, j, i, 0, 0); if(weight < value){ set_volume_real_value(*weights, k, j, i, 0, 0, weight); for(v = 0; v < v_size; v++){ set_volume_real_value(*totals, k, j, i, v, 0, data_buf[0 + v] * weight); } } } else{ for(v = 0; v < v_size; v++){ value = get_volume_real_value(*totals, k, j, i, v, 0); set_volume_real_value(*totals, k, j, i, v, 0, value + (data_buf[0 + v] * weight)); } /* increment count value */ value = get_volume_real_value(*weights, k, j, i, 0, 0); set_volume_real_value(*weights, k, j, i, 0, 0, value + weight); } } c_pos[2] += steps[perm[2]]; } c_pos[1] += steps[perm[1]]; } c_pos[0] += steps[perm[0]]; } }
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__); } }
int main(int argc, char *argv[]) { VIO_Volume volume; VIO_Real variability, rand_val, voxel[VIO_MAX_DIMENSIONS]; int progress_count, sizes[VIO_MAX_DIMENSIONS], index[VIO_MAX_DIMENSIONS], i,j,k; VIO_progress_struct progress; union { long l; char c[4]; } seedval; time_t t; char tmp; prog_name = argv[0]; /* Check arguments */ if (argc != 4) { (void) fprintf(stderr, "Usage: %s input.mnc output.mnc std_dev\n", argv[0]); exit(EXIT_FAILURE); } if( input_volume( argv[1], 3, NULL, NC_UNSPECIFIED, FALSE, 0.0, 0.0, TRUE, &volume, (minc_input_options *)NULL ) != OK ) { (void)fprintf(stderr, "Error opening input volume file %s.\n", argv[1]); exit(EXIT_FAILURE); } variability = atof( argv[3] ); /* initialize drand function */ t = 2*time(NULL); seedval.l = t; tmp = seedval.c[0]; seedval.c[0] = seedval.c[3]; seedval.c[3] = tmp; tmp = seedval.c[1]; seedval.c[1] = seedval.c[2]; seedval.c[2] = tmp; srand48(seedval.l); set_volume_real_range(volume, -5.0*variability, 5.0*variability); get_volume_sizes(volume,sizes); initialize_progress_report(&progress, FALSE, sizes[VIO_X]*sizes[VIO_Y]*sizes[VIO_Z]+1, "Randomizing volume"); progress_count = 0; for(i=0; i<MAX_DIMENSIONS; i++) index[i] = 0; /* loop over all voxels */ for(index[X]=0; index[X]<sizes[X]; index[X]++) for(index[Y]=0; index[Y]<sizes[Y]; index[Y]++) for(index[Z]=0; index[Z]<sizes[Z]; index[Z]++) { /* get a random value from a gaussian distribution */ rand_val = variability * gaussian_random_0_1(); if (rand_val > 5.0*variability) rand_val = 5.0*variability; if (rand_val < -5.0*variability) rand_val = -5.0*variability; set_volume_real_value(volume, index[0],index[1],index[2],index[3],index[4], rand_val); progress_count++; update_progress_report(&progress, progress_count); } terminate_progress_report(&progress); /* Write out the random volume */ if (output_volume(argv[2], NC_UNSPECIFIED, FALSE, 0.0, 0.0, volume, (char *)NULL, (minc_output_options *)NULL) != OK) { (void) fprintf(stderr, "%s: Error writing volume file %s\n", argv[0], argv[2]); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
int main(int argc, char *argv[]) { VIO_General_transform transform, *grid_transform_ptr, forward_transform; VIO_Volume target_vol, volume; volume_input_struct input_info; VIO_Real voxel[VIO_MAX_DIMENSIONS], steps[VIO_MAX_DIMENSIONS], start[VIO_N_DIMENSIONS], target_steps[VIO_MAX_DIMENSIONS], wx,wy,wz, inv_x, inv_y, inv_z, def_values[VIO_MAX_DIMENSIONS]; static int clobber_flag = FALSE, verbose = TRUE, debug = FALSE; static char *target_file; int parse_flag, prog_count, sizes[VIO_MAX_DIMENSIONS], target_sizes[VIO_MAX_DIMENSIONS], xyzv[VIO_MAX_DIMENSIONS], target_xyzv[VIO_MAX_DIMENSIONS], index[VIO_MAX_DIMENSIONS], i, trans_count; VIO_progress_struct progress; static ArgvInfo argTable[] = { {"-like", ARGV_STRING, (char *) 0, (char *) &target_file, "Specify target volume sampling information."}, {"-no_clobber", ARGV_CONSTANT, (char *) FALSE, (char *) &clobber_flag, "Do not overwrite output file (default)."}, {"-clobber", ARGV_CONSTANT, (char *) TRUE, (char *) &clobber_flag, "Overwrite output file."}, {"-verbose", ARGV_CONSTANT, (char *) TRUE, (char *) &verbose, "Write messages indicating progress (default)"}, {"-quiet", ARGV_CONSTANT, (char *) FALSE, (char *) &verbose, "Do not write log messages"}, {"-debug", ARGV_CONSTANT, (char *) TRUE, (char *) &debug, "Print out debug info."}, {NULL, ARGV_END, NULL, NULL, NULL} }; prog_name = argv[0]; target_file = malloc(1024); strcpy(target_file,""); /* Call ParseArgv to interpret all command line args (returns TRUE if error) */ parse_flag = ParseArgv(&argc, argv, argTable, 0); /* Check remaining arguments */ if (parse_flag || argc != 3) print_usage_and_exit(prog_name); /* Read in file that has a def field to invert */ if (input_transform_file(argv[1], &transform) != OK) { (void) fprintf(stderr, "%s: Error reading transform file %s\n", argv[0], argv[1]); exit(EXIT_FAILURE); } for(trans_count=0; trans_count<get_n_concated_transforms(&transform); trans_count++ ) { grid_transform_ptr = get_nth_general_transform(&transform, trans_count ); if (grid_transform_ptr->type == GRID_TRANSFORM) { copy_general_transform(grid_transform_ptr, &forward_transform); /* this is the call that should be made with the latest version of internal_libvolume_io invert_general_transform(&forward_transform); */ forward_transform.inverse_flag = !(forward_transform.inverse_flag); volume = grid_transform_ptr->displacement_volume; if (strlen(target_file)!=0) { if (debug) print ("Def field will be resampled like %s\n",target_file); if (!file_exists( target_file ) ) { (void) fprintf(stderr, "%s: Target file '%s' does not exist\n", prog_name,target_file); exit(EXIT_FAILURE); } start_volume_input(target_file, 3, (char **)NULL, NC_UNSPECIFIED, FALSE, 0.0, 0.0, TRUE, &target_vol, (minc_input_options *)NULL, &input_info); get_volume_XYZV_indices(volume, xyzv); get_volume_separations (volume, steps); get_volume_sizes (volume, sizes); get_volume_XYZV_indices(target_vol, target_xyzv); get_volume_separations (target_vol, target_steps); get_volume_sizes (target_vol, target_sizes); for(i=0; i<VIO_MAX_DIMENSIONS; i++) { index[i] = 0; voxel[i] = 0.0; } convert_voxel_to_world(target_vol, voxel, &start[VIO_X], &start[VIO_Y], &start[VIO_Z]); if( volume != (void *) NULL ){ free_volume_data( volume ); } for(i=VIO_X; i<=VIO_Z; i++) { steps[ xyzv[i] ] = target_steps[ target_xyzv[i] ] ; sizes[ xyzv[i] ] = target_sizes[ target_xyzv[i] ] ; } set_volume_separations(volume, steps); set_volume_sizes( volume, sizes); set_volume_starts(volume, start); alloc_volume_data( volume ); } get_volume_sizes(volume, sizes); get_volume_XYZV_indices(volume,xyzv); for(i=0; i<VIO_MAX_DIMENSIONS; i++){ index[i] = 0; } if (verbose){ initialize_progress_report(&progress, FALSE, sizes[xyzv[VIO_X]]*sizes[xyzv[VIO_Y]]*sizes[xyzv[VIO_Z]]+1, "Inverting def field"); } prog_count = 0; for(index[xyzv[VIO_X]]=0; index[xyzv[VIO_X]]<sizes[xyzv[VIO_X]]; index[xyzv[VIO_X]]++) for(index[xyzv[VIO_Y]]=0; index[xyzv[VIO_Y]]<sizes[xyzv[VIO_Y]]; index[xyzv[VIO_Y]]++) for(index[xyzv[VIO_Z]]=0; index[xyzv[VIO_Z]]<sizes[xyzv[VIO_Z]]; index[xyzv[VIO_Z]]++) { index[ xyzv[VIO_Z+1] ] = 0; for(i=0; i<VIO_MAX_DIMENSIONS; i++) voxel[i] = (VIO_Real)index[i]; convert_voxel_to_world(volume, voxel, &wx, &wy, &wz); if (sizes[ xyzv[VIO_Z] ] ==1) general_inverse_transform_point_in_trans_plane(&forward_transform, wx, wy, wz, &inv_x, &inv_y, &inv_z); else grid_inverse_transform_point(&forward_transform, wx, wy, wz, &inv_x, &inv_y, &inv_z); def_values[VIO_X] = inv_x - wx; def_values[VIO_Y] = inv_y - wy; def_values[VIO_Z] = inv_z - wz; for(index[xyzv[VIO_Z+1]]=0; index[xyzv[VIO_Z+1]]<3; index[xyzv[VIO_Z+1]]++) set_volume_real_value(volume, index[0],index[1],index[2],index[3],index[4], def_values[ index[ xyzv[VIO_Z+1] ]]); prog_count++; if (verbose) update_progress_report(&progress, prog_count); } if (verbose) terminate_progress_report(&progress); delete_general_transform(&forward_transform); grid_transform_ptr->inverse_flag = !(grid_transform_ptr->inverse_flag); } } /* Write out the transform */ if (output_transform_file(argv[2], NULL, &transform) != OK) { (void) fprintf(stderr, "%s: Error writing transform file %s\n", argv[0], argv[2]); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
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); }
/* perform a median kernel operation on a volume */ Volume *median_dilation_kernel(Kernel * K, Volume * vol) { int x, y, z, c, i; int sizes[MAX_VAR_DIMS]; progress_struct progress; Volume tmp_vol; double value; unsigned int kvalue; unsigned int neighbours[K->nelems]; if(verbose){ fprintf(stdout, "Median Dilation kernel\n"); } get_volume_sizes(*vol, sizes); initialize_progress_report(&progress, FALSE, sizes[2], "Median Dilation"); /* copy the volume */ tmp_vol = copy_volume(*vol); for(z = -K->pre_pad[2]; z < sizes[0] - K->post_pad[2]; z++){ for(y = -K->pre_pad[1]; y < sizes[1] - K->post_pad[1]; y++){ for(x = -K->pre_pad[0]; x < sizes[2] - K->post_pad[0]; x++){ /* only modify background voxels */ value = get_volume_voxel_value(tmp_vol, z, y, x, 0, 0); if(value == 0.0){ i = 0; for(c = 0; c < K->nelems; c++){ kvalue = (unsigned int)get_volume_voxel_value(tmp_vol, z + K->K[c][2], y + K->K[c][1], x + K->K[c][0], 0 + K->K[c][3], 0 + K->K[c][4]); if(kvalue != 0){ neighbours[i] = kvalue; i++; } } /* only run this for adjacent voxels */ if(i > 0){ /* find the median of our little array */ qsort(&neighbours[0], (size_t) i, sizeof(unsigned int), &compare_ints); /* store the median value */ set_volume_voxel_value(*vol, z, y, x, 0, 0, (double)neighbours[(int)floor((i - 1) / 2)]); } } /* else just copy the original value over */ else { set_volume_voxel_value(*vol, z, y, x, 0, 0, value); } } } update_progress_report(&progress, z + 1); } delete_volume(tmp_vol); terminate_progress_report(&progress); return (vol); }
int main( int argc, char *argv[] ) { STRING volume_filename; STRING output_filename; Real x, y, z, xc, yc, zc, xp, yp, zp, len, pos; Real value, scaling, min_value, max_value; int v[MAX_DIMENSIONS], sizes[MAX_DIMENSIONS]; Real voxel[MAX_DIMENSIONS], scale; Volume volume; initialize_argument_processing( argc, argv ); if( !get_string_argument( "", &volume_filename ) || !get_string_argument( "", &output_filename ) || !get_real_argument( 0.0, &x ) || !get_real_argument( 0.0, &y ) || !get_real_argument( 0.0, &z ) || !get_real_argument( 0.0, &scaling ) ) { return( 1 ); } len = sqrt( x * x + y * y + z * z ); x /= len; y /= len; z /= len; if( input_volume( volume_filename, 3, File_order_dimension_names, NC_UNSPECIFIED, FALSE, 0.0, 0.0, TRUE, &volume, NULL ) != OK ) return( 1 ); get_volume_sizes( volume, sizes ); get_volume_real_range( volume, &min_value, &max_value ); voxel[0] = (Real) (sizes[0]-1) / 2.0; voxel[1] = (Real) (sizes[1]-1) / 2.0; voxel[2] = (Real) (sizes[2]-1) / 2.0; convert_voxel_to_world( volume, voxel, &xc, &yc, &zc ); BEGIN_ALL_VOXELS( volume, v[0], v[1], v[2], v[3], v[4] ) voxel[0] = (Real) v[0]; voxel[1] = (Real) v[1]; voxel[2] = (Real) v[2]; convert_voxel_to_world( volume, voxel, &xp, &yp, &zp ); pos = (xp - xc) * x + (yp - yc) * y + (zp - zc) * z; scale = 1.0 + pos * scaling; value = get_volume_real_value( volume, v[0], v[1], v[2], v[3], v[4] ); value *= scale; if( value < min_value ) value = min_value; else if( value > max_value ) value = max_value; set_volume_real_value( volume, v[0], v[1], v[2], v[3], v[4], value ); END_ALL_VOXELS (void) output_modified_volume( output_filename, NC_UNSPECIFIED, FALSE, 0.0, 0.0, volume, volume_filename, "Scaled\n", NULL ); return( 0 ); }
/* return resulting totals and weights volumes */ void regrid_arb_path(char *coord_fn, char *data_fn, int buff_size, VIO_Volume * totals, VIO_Volume * weights, int v_size, double regrid_floor, double regrid_ceil) { Coord_list coord_buf; double *data_buf = NULL; size_t data_buf_alloc_size = 0; int sizes[MAX_VAR_DIMS]; int c, v; int total_pts; double value; int valid; /* global max-min counters */ double v_min, v_max; double x_min, y_min, z_min; double x_max, y_max, z_max; /* loop max-min counters */ double l_v_min, l_v_max; double l_x_min, l_y_min, l_z_min; double l_x_max, l_y_max, l_z_max; /* get volume info */ get_volume_sizes(*totals, sizes); /* check for the config file */ if(!file_exists(coord_fn)){ fprintf(stderr, "Couldn't find config file %s.\n\n", coord_fn); exit(EXIT_FAILURE); } /* initialise the parser with the config file */ if(!init_arb_path(coord_fn, data_fn)){ fprintf(stderr, "Failed to init arb_path, this isn't good\n"); exit(EXIT_FAILURE); } /* get some co-ordinates */ if(verbose){ fprintf(stdout, " + Doing arbitrary path (vector: %d)\n", v_size); } total_pts = 0; v_min = DBL_MAX; v_max = -DBL_MAX; x_min = y_min = z_min = DBL_MAX; x_max = y_max = z_max = -DBL_MAX; coord_buf = get_some_arb_path_coords(buff_size); while(coord_buf->n_pts != 0){ /* grow data_buf if we have to */ if(coord_buf->n_pts * v_size > data_buf_alloc_size){ data_buf_alloc_size = coord_buf->n_pts * v_size; data_buf = realloc(data_buf, data_buf_alloc_size * sizeof(*data_buf)); } /* get the data */ if(!get_some_arb_path_data (data_buf, in_dtype, in_is_signed, coord_buf->n_pts, v_size)){ fprintf(stderr, "failed getting data\n"); exit(EXIT_FAILURE); } total_pts += coord_buf->n_pts; if(verbose){ fprintf(stdout, " | %d co-ords total: %d ", coord_buf->n_pts, total_pts); fflush(stdout); } /* regrid (do the nasty) */ l_v_min = DBL_MAX; l_v_max = -DBL_MAX; l_x_min = l_y_min = l_z_min = DBL_MAX; l_x_max = l_y_max = l_z_max = -DBL_MAX; for(c = 0; c < coord_buf->n_pts; c++){ /* check if this point is in range */ valid = 1; for(v = 0; v < v_size; v++){ value = data_buf[(c * v_size) + v]; if(value < regrid_floor || value > regrid_ceil){ valid = 0; } else { /* do range calculation */ if(verbose){ if(value > l_v_max){ l_v_max = value; } else if(value < l_v_min){ l_v_min = value; } } } // fprintf(stderr, "Value: %g valid %d\n", value, valid); } // fprintf(stderr, "VV %d [%g:%g:%g]\n", valid, // coord_buf->pts[c].coord[0], // coord_buf->pts[c].coord[1], // coord_buf->pts[c].coord[2] // ); if(valid){ regrid_point(totals, weights, coord_buf->pts[c].coord[0], coord_buf->pts[c].coord[1], coord_buf->pts[c].coord[2], v_size, &data_buf[c * v_size]); /* coord max-min storage */ if(verbose){ if(coord_buf->pts[c].coord[0] > l_x_max){ l_x_max = coord_buf->pts[c].coord[0]; } else if(coord_buf->pts[c].coord[0] < l_x_min){ l_x_min = coord_buf->pts[c].coord[0]; } if(coord_buf->pts[c].coord[1] > l_y_max){ l_y_max = coord_buf->pts[c].coord[1]; } else if(coord_buf->pts[c].coord[1] < l_y_min){ l_y_min = coord_buf->pts[c].coord[1]; } if(coord_buf->pts[c].coord[2] > l_z_max){ l_z_max = coord_buf->pts[c].coord[2]; } else if(coord_buf->pts[c].coord[2] < l_z_min){ l_z_min = coord_buf->pts[c].coord[2]; } } } } if(verbose){ fprintf(stdout, " xyz [%4.1g:%4.1g:%4.1g] : [%4.1g:%4.1g:%4.1g] v: [%g:%g]\n", l_x_min, l_y_min, l_z_min, l_x_max, l_y_max, l_z_max, l_v_min, l_v_max); } /* update global counters */ if(verbose){ if(l_v_min < v_min){ v_min = l_v_min; } if(l_v_max > v_max){ v_max = l_v_max; } if(l_x_min < x_min){ x_min = l_x_min; } if(l_y_min < y_min){ y_min = l_y_min; } if(l_z_min < z_min){ z_min = l_z_min; } if(l_x_max > x_max){ x_max = l_x_max; } if(l_y_max > y_max){ y_max = l_y_max; } if(l_z_max > z_max){ z_max = l_z_max; } } /* get the next lot of co-ordinates */ coord_buf = get_some_arb_path_coords(buff_size); } if(verbose){ fprintf(stdout, " | == global xyz [%4.1g:%4.1g:%4.1g] : [%4.1g:%4.1g:%4.1g] v: [%g:%g]\n", x_min, y_min, z_min, x_max, y_max, z_max, v_min, v_max); } /* finish up */ end_arb_path(); }
int main(int argc, char *argv[]) { int v1, v2, v3, v4; int sizes[VIO_MAX_DIMENSIONS], grid_sizes[4]; int n_concat_transforms, i; VIO_STR arg_string; char *input_volume_name; char *input_xfm; VIO_STR outfile; VIO_Real w1, w2, w3; VIO_Real nw1, nw2, nw3; VIO_Real original[3], transformed[3]; VIO_Real value; VIO_Real cosine[3]; VIO_Real original_separation[3], grid_separation[4]; VIO_Real original_starts[3], grid_starts[4]; VIO_Volume eval_volume, new_grid; VIO_General_transform xfm, *voxel_to_world; VIO_STR *dimnames, dimnames_grid[4]; VIO_progress_struct progress; arg_string = time_stamp(argc, argv); /* Check arguments */ if(ParseArgv(&argc, argv, argTable, 0) || (argc != 4)){ fprintf(stderr, "\nUsage: %s [options] input.mnc input.xfm output_grid.mnc\n", argv[0]); fprintf(stderr, " %s -help\n\n", argv[0]); exit(EXIT_FAILURE); } input_volume_name = argv[1]; input_xfm = argv[2]; outfile = argv[3]; /* check for the infile and outfile */ if(access(input_volume_name, F_OK) != 0){ fprintf(stderr, "%s: Couldn't find %s\n\n", argv[0], input_volume_name); exit(EXIT_FAILURE); } if(access(input_xfm, F_OK) != 0) { fprintf(stderr, "%s: Couldn't find %s\n\n", argv[0], input_xfm); exit(EXIT_FAILURE); } if(access(outfile, F_OK) == 0 && !clobber){ fprintf(stderr, "%s: %s exists! (use -clobber to overwrite)\n\n", argv[0], outfile); exit(EXIT_FAILURE); } /*--- input the volume */ /* if( input_volume( input_volume_name, 3, NULL, MI_ORIGINAL_TYPE, FALSE, 0.0, 0.0, TRUE, &eval_volume,(minc_input_options *) NULL ) != OK ) return( 1 ); */ if (input_volume_header_only( input_volume_name, 3, NULL, &eval_volume,(minc_input_options *) NULL ) != VIO_OK ) { return( 1 ); } /* get information about the volume */ get_volume_sizes( eval_volume, sizes ); voxel_to_world = get_voxel_to_world_transform(eval_volume); dimnames = get_volume_dimension_names(eval_volume); get_volume_separations(eval_volume, original_separation); get_volume_starts(eval_volume, original_starts); /* create new 4D volume, last three dims same as other volume, first dimension being the vector dimension. */ for(i=1; i < 4; i++) { dimnames_grid[i] = dimnames[i-1]; grid_separation[i] = original_separation[i-1]; grid_sizes[i] = sizes[i-1]; grid_starts[i] = original_starts[i-1]; } dimnames_grid[0] = "vector_dimension"; grid_sizes[0] = 3; grid_separation[0] = 1; grid_starts[0] = 0; new_grid = create_volume(4, dimnames_grid, NC_SHORT, FALSE, 0.0, 0.0); //set_voxel_to_world_transform(new_grid, voxel_to_world); // initialize the new grid volume, otherwise the output will be // garbage... set_volume_real_range(new_grid, -100, 100); set_volume_sizes(new_grid, grid_sizes); set_volume_separations(new_grid, grid_separation); set_volume_starts(new_grid, grid_starts); /* for (i=0; i < 3; i++) { get_volume_direction_cosine(eval_volume, i, cosine); set_volume_direction_cosine(new_grid, i+1, cosine); } */ alloc_volume_data(new_grid); /* get the transforms */ if( input_transform_file( input_xfm, &xfm ) != VIO_OK ) return( 1 ); /* see how many transforms will be applied */ n_concat_transforms = get_n_concated_transforms( &xfm ); printf("Number of transforms to be applied: %d\n", n_concat_transforms); initialize_progress_report(&progress, FALSE, sizes[0], "Processing"); /* evaluate the transform at every voxel, keep the displacement in the three cardinal directions */ for( v1 = 0; v1 < sizes[0]; ++v1 ) { update_progress_report(&progress, v1 + 1); for( v2 = 0; v2 < sizes[1]; ++v2 ) { for( v3 = 0; v3 < sizes[2]; ++v3 ) { convert_3D_voxel_to_world(eval_volume, v1, v2, v3, &original[0], &original[1], &original[2]); general_transform_point(&xfm, original[0], original[1], original[2], &transformed[0], &transformed[1], &transformed[2]); for(i=0; i < 3; i++) { value = transformed[i] - original[i]; set_volume_real_value(new_grid, i, v1, v2, v3, 0, value); } } } } terminate_progress_report(&progress); printf("Outputting volume.\n"); output_volume(outfile, MI_ORIGINAL_TYPE, TRUE, 0.0, 0.0, new_grid, arg_string, NULL); return(0); }
/* xcorr = sum((a*b)^2) / (sqrt(sum(a^2)) * sqrt(sum(b^2)) */ VIO_Volume *lcorr_kernel(Kernel * K, VIO_Volume * vol, VIO_Volume *cmp) { int x, y, z, c; double value, v1, v2; double ssum_v1, ssum_v2, sum_prd, denom; int sizes[MAX_VAR_DIMS]; progress_struct progress; Volume tmp_vol; if(verbose){ fprintf(stdout, "Local Correlation kernel\n"); } get_volume_sizes(*vol, sizes); initialize_progress_report(&progress, FALSE, sizes[2], "Local Correlation"); /* copy the volume */ tmp_vol = copy_volume(*vol); /* zero the output volume */ for(z = sizes[0]; z--;){ for(y = sizes[1]; y--;){ for(x = sizes[2]; x--;){ set_volume_voxel_value(*vol, z, y, x, 0, 0, 0); } } } /* set output range */ set_volume_real_range(*vol, 0.0, 1.0); for(z = -K->pre_pad[2]; z < sizes[0] - K->post_pad[2]; z++){ for(y = -K->pre_pad[1]; y < sizes[1] - K->post_pad[1]; y++){ for(x = -K->pre_pad[0]; x < sizes[2] - K->post_pad[0]; x++){ /* init counters */ ssum_v1 = ssum_v2 = sum_prd = 0; for(c = 0; c < K->nelems; c++){ v1 = get_volume_real_value(tmp_vol, z + K->K[c][2], y + K->K[c][1], x + K->K[c][0], 0 + K->K[c][3], 0 + K->K[c][4]) * K->K[c][5]; v2 = get_volume_real_value(*cmp, z + K->K[c][2], y + K->K[c][1], x + K->K[c][0], 0 + K->K[c][3], 0 + K->K[c][4]) * K->K[c][5]; /* increment counters */ ssum_v1 += v1*v1; ssum_v2 += v2*v2; sum_prd += v1*v2; } denom = sqrt(ssum_v1 * ssum_v2); value = (denom == 0.0) ? 0.0 : sum_prd / denom; set_volume_real_value(*vol, z, y, x, 0, 0, value); } } update_progress_report(&progress, z + 1); } terminate_progress_report(&progress); /* tidy up */ delete_volume(tmp_vol); return (vol); }
/* ----------------------------- MNI Header ----------------------------------- @NAME : compute_chamfer @INPUT/OUTPUT: chamfer The original input volume will be destroyed and replaced with the resulting chamfer distance volume. The chamfer will contains 0's where the mask was and values > 0.0 for all other voxels, where the value is an estimate of the distance to the the nearest voxel of the mask. @RETURNS : ERROR if error, OK otherwise @DESCRIPTION: Uses an idea from georges, who got it from claire, who got it from Borgefors @GLOBALS : @CALLS : @CREATED : Nov 2, 1998 Louis @MODIFIED : ---------------------------------------------------------------------------- */ VIO_Status compute_chamfer(VIO_Volume chamfer, VIO_Real max_val) { VIO_Real mask_f[3][3][3], mask_b[3][3][3], zero, min, vox_min, vox_max, val, val2; int sizes[VIO_MAX_DIMENSIONS], i,j,k, ind0,ind1,ind2; VIO_progress_struct progress; get_volume_sizes(chamfer, sizes); get_volume_voxel_range(chamfer, &vox_min, &vox_max); zero = CONVERT_VALUE_TO_VOXEL(chamfer,0.0); /* init chamfer to be binary valued with 0.0 on the object, and infinity (or vox_max) elsewhere */ if (debug) print ("initing chamfer vol (%d %d %d)\n",sizes[0],sizes[1],sizes[2]); for(ind0=0; ind0<sizes[0]; ind0++) { for(ind1=0; ind1<sizes[1]; ind1++) { for(ind2=0; ind2<sizes[2]; ind2++) { GET_VOXEL_3D(val, chamfer, ind0, ind1, ind2); if (val == zero) { SET_VOXEL_3D(chamfer, ind0, ind1, ind2, vox_max ); } else { SET_VOXEL_3D(chamfer, ind0, ind1, ind2, vox_min); } } } } if (debug) print ("building mask\n"); build_mask(chamfer, mask_f, mask_b); set_volume_real_range(chamfer, 0.0, max_val); zero = CONVERT_VALUE_TO_VOXEL(chamfer,0.0); if (verbose) initialize_progress_report( &progress, TRUE, sizes[0], "forward pass"); for(ind0=1; ind0<sizes[0]-1; ind0++) { for(ind1=1; ind1<sizes[1]-1; ind1++) { for(ind2=1; ind2<sizes[2]-1; ind2++) { GET_VALUE_3D(val, chamfer, ind0, ind1, ind2); if (val != zero) { /* then apply forward mask */ min = val; for(i=-1; i<=+1; i++) { for(j=-1; j<=+1; j++) { for(k=-1; k<=+1; k++) { GET_VALUE_3D(val, chamfer, i+ind0, j+ind1, k+ind2); val2 = val + mask_f[i+1][j+1][k+1]; min = MIN (min, val2); } } } min = convert_value_to_voxel(chamfer, min); SET_VOXEL_3D(chamfer, ind0, ind1, ind2, min ); } /* if val != 0.0 */ } /* ind2 */ } /* ind1 */ if (verbose) update_progress_report( &progress, ind0+1 ); } /* ind0 */ if (verbose) terminate_progress_report( &progress ); if (verbose) initialize_progress_report( &progress, TRUE, sizes[0], "reverse pass"); for(ind0=sizes[0]-2; ind0>=1; ind0--) { for(ind1=sizes[1]-2; ind1>=1; ind1--) { for(ind2=sizes[2]-2; ind2>=1; ind2--) { GET_VALUE_3D(val, chamfer, ind0, ind1, ind2); if (val != zero) { /* then apply backwardmask */ min = val; for(i=-1; i<=1; i++) { for(j=-1; j<=+1; j++) { for(k=-1; k<=+1; k++) { GET_VALUE_3D(val, chamfer, i+ind0, j+ind1, k+ind2); val2 = val + mask_b[i+1][j+1][k+1]; min = MIN (min, val2); } } } min = convert_value_to_voxel(chamfer, min); SET_VOXEL_3D(chamfer, ind0, ind1, ind2, min ); } /* if val != 0.0 */ } /* ind2 */ } /* ind1 */ if (verbose) update_progress_report( &progress, ind0+1 ); } /* ind0 */ if (verbose) terminate_progress_report( &progress ); return (OK); }
/* from the original 2 pass Borgefors alg */ Volume *distance_kernel(Kernel * K, Volume * vol, double bg) { int x, y, z, c; double value, min; int sizes[MAX_VAR_DIMS]; progress_struct progress; Kernel *k1, *k2; /* split the Kernel */ k1 = new_kernel(K->nelems); k2 = new_kernel(K->nelems); split_kernel(K, k1, k2); setup_pad_values(k1); setup_pad_values(k2); if(verbose){ fprintf(stdout, "Distance kernel - background %g\n", bg); fprintf(stdout, "forward direction kernel:\n"); print_kernel(k1); fprintf(stdout, "\nreverse direction kernel:\n"); print_kernel(k2); } get_volume_sizes(*vol, sizes); initialize_progress_report(&progress, FALSE, sizes[2] * 2, "Distance"); /* forward raster direction */ for(z = -K->pre_pad[2]; z < sizes[0] - K->post_pad[2]; z++){ for(y = -K->pre_pad[1]; y < sizes[1] - K->post_pad[1]; y++){ for(x = -K->pre_pad[0]; x < sizes[2] - K->post_pad[0]; x++){ if(get_volume_real_value(*vol, z, y, x, 0, 0) != bg){ /* find the minimum */ min = DBL_MAX; for(c = 0; c < k1->nelems; c++){ value = get_volume_real_value(*vol, z + k1->K[c][2], y + k1->K[c][1], x + k1->K[c][0], 0 + k1->K[c][3], 0 + k1->K[c][4]) + 1; if(value < min){ min = value; } } set_volume_real_value(*vol, z, y, x, 0, 0, min); } } } update_progress_report(&progress, z + 1); } /* reverse raster direction */ for(z = sizes[0] - k2->post_pad[2] - 1; z >= -k2->pre_pad[2]; z--){ for(y = sizes[1] - k2->post_pad[1] - 1; y >= -k2->pre_pad[1]; y--){ for(x = sizes[2] - k2->post_pad[0] - 1; x >= -k2->pre_pad[0]; x--){ min = get_volume_real_value(*vol, z, y, x, 0, 0); if(min != bg){ /* find the minimum distance to bg in the neighbouring vectors */ for(c = 0; c < k2->nelems; c++){ value = get_volume_real_value(*vol, z + k2->K[c][2], y + k2->K[c][1], x + k2->K[c][0], 0 + k2->K[c][3], 0 + k2->K[c][4]) + 1; if(value < min){ min = value; } } set_volume_real_value(*vol, z, y, x, 0, 0, min); } } } update_progress_report(&progress, sizes[2] + z + 1); } free(k1); free(k2); terminate_progress_report(&progress); return (vol); }
/* resulting groups are sorted WRT size */ Volume *group_kernel(Kernel * K, Volume * vol, double bg) { int x, y, z; int sizes[MAX_VAR_DIMS]; progress_struct progress; Volume tmp_vol; Kernel *k1, *k2; unsigned int *equiv; unsigned int *counts; unsigned int *trans; unsigned int neighbours[K->nelems]; /* counters */ unsigned int c; unsigned int value; unsigned int group_idx; /* label for the next group */ unsigned int num_groups; unsigned int min_label; unsigned int curr_label; unsigned int prev_label; unsigned int num_matches; /* structure for group data */ Group_info *group_data; /* split the Kernel into forward and backwards kernels */ k1 = new_kernel(K->nelems); k2 = new_kernel(K->nelems); split_kernel(K, k1, k2); setup_pad_values(k1); setup_pad_values(k2); if(verbose){ fprintf(stdout, "Group kernel - background %g\n", bg); fprintf(stdout, "forward direction kernel:\n"); print_kernel(k1); fprintf(stdout, "\nreverse direction kernel:\n"); print_kernel(k2); } get_volume_sizes(*vol, sizes); initialize_progress_report(&progress, FALSE, sizes[2], "Groups"); /* copy and then zero out the original volume */ tmp_vol = copy_volume(*vol); for(z = sizes[0]; z--;){ for(y = sizes[1]; y--;){ for(x = sizes[2]; x--;){ set_volume_voxel_value(*vol, z, y, x, 0, 0, 0); } } } /* pass 1 - forward direction (we assume a symmetric kernel) */ /* our first group is given the label 1 */ group_idx = 1; /* initialise the equiv and counts arrays */ SET_ARRAY_SIZE(equiv, 0, group_idx, 500); equiv[0] = 0; SET_ARRAY_SIZE(counts, 0, group_idx, 500); counts[0] = 0; for(z = -k1->pre_pad[2]; z < sizes[0] - k1->post_pad[2]; z++){ for(y = -k1->pre_pad[1]; y < sizes[1] - k1->post_pad[1]; y++){ for(x = -k1->pre_pad[0]; x < sizes[2] - k1->post_pad[0]; x++){ if(get_volume_voxel_value(tmp_vol, z, y, x, 0, 0) != bg){ /* search this voxels neighbours */ num_matches = 0; min_label = INT_MAX; for(c = 0; c < k1->nelems; c++){ value = (unsigned int)get_volume_voxel_value(*vol, z + k1->K[c][2], y + k1->K[c][1], x + k1->K[c][0], 0 + k1->K[c][3], 0 + k1->K[c][4]); if(value != 0){ if(value < min_label){ min_label = value; } neighbours[num_matches] = value; num_matches++; } } switch (num_matches){ case 0: /* no neighbours, make a new label and increment */ set_volume_voxel_value(*vol, z, y, x, 0, 0, (Real) group_idx); SET_ARRAY_SIZE(equiv, group_idx, group_idx + 1, 500); equiv[group_idx] = group_idx; SET_ARRAY_SIZE(counts, group_idx, group_idx + 1, 500); counts[group_idx] = 1; group_idx++; break; case 1: /* only one neighbour, no equivalences needed */ set_volume_voxel_value(*vol, z, y, x, 0, 0, (Real) min_label); counts[min_label]++; break; default: /* more than one neighbour */ /* first sort the neighbours array */ qsort(&neighbours[0], (size_t) num_matches, sizeof(unsigned int), &compare_ints); /* find the minimum possible label for this voxel, */ /* this is done by descending through each neighbours */ /* equivalences until an equivalence equal to itself */ /* is found */ prev_label = -1; for(c = 0; c < num_matches; c++){ curr_label = neighbours[c]; /* recurse this label if we haven't yet */ if(curr_label != prev_label){ while(equiv[curr_label] != equiv[equiv[curr_label]]){ curr_label = equiv[curr_label]; } /* check against the current minimum value */ if(equiv[curr_label] < min_label){ min_label = equiv[curr_label]; } } prev_label = neighbours[c]; } /* repeat, setting equivalences to the min_label */ prev_label = -1; for(c = 0; c < num_matches; c++){ curr_label = neighbours[c]; if(curr_label != prev_label){ while(equiv[curr_label] != equiv[equiv[curr_label]]){ curr_label = equiv[curr_label]; equiv[curr_label] = min_label; } /* set the label itself */ if(equiv[neighbours[c]] != min_label){ equiv[neighbours[c]] = min_label; } } prev_label = neighbours[c]; } /* finally set the voxel in question to the minimum value */ set_volume_voxel_value(*vol, z, y, x, 0, 0, (Real) min_label); counts[min_label]++; break; } /* end case */ } } } update_progress_report(&progress, z + 1); } terminate_progress_report(&progress); /* reduce the equiv and counts array */ num_groups = 0; for(c = 0; c < group_idx; c++){ /* if this equivalence is not resolved yet */ if(c != equiv[c]){ /* find the min label value */ min_label = equiv[c]; while(min_label != equiv[min_label]){ min_label = equiv[min_label]; } /* update the label and its counters */ equiv[c] = min_label; counts[min_label] += counts[c]; counts[c] = 0; } else { num_groups++; } } /* Allocate space for the array of groups */ group_data = (Group_info *) malloc(num_groups * sizeof(Group_info)); num_groups = 0; for(c = 0; c < group_idx; c++){ if(counts[c] > 0){ /* allocate space for this element */ group_data[num_groups] = malloc(sizeof(group_info_struct)); group_data[num_groups]->orig_label = equiv[c]; group_data[num_groups]->count = counts[c]; num_groups++; } } /* sort the groups by the count size */ if(verbose){ fprintf(stdout, "Found %d unique groups from %d, sorting...\n", num_groups, group_idx); } qsort(group_data, num_groups, sizeof(Group_info), &compare_groups); /* set up the transpose array */ trans = (unsigned int *)malloc(sizeof(unsigned int) * group_idx); for(c = 0; c < num_groups; c++){ trans[group_data[c]->orig_label] = c + 1; /* +1 to bump past 0 */ } /* pass 2 - resolve equivalences in the output data */ if(verbose){ fprintf(stdout, "Resolving equivalences...\n"); } for(z = sizes[0]; z--;){ for(y = sizes[1]; y--;){ for(x = sizes[2]; x--;){ value = (unsigned int)get_volume_voxel_value(*vol, z, y, x, 0, 0); if(value != 0){ value = trans[equiv[value]]; set_volume_voxel_value(*vol, z, y, x, 0, 0, (Real) value); } } } } /* tidy up */ delete_volume(tmp_vol); for(c = 0; c < num_groups; c++){ free(group_data[c]); } free(group_data); free(trans); free(k1); free(k2); return (vol); }
/* ----------------------------- MNI Header ----------------------------------- @NAME : average_smoothness @INPUT : tmp_lambda_file - tmp file with unaveraged smoothness values @OUTPUT : lambda_file - file where final values are to be placed @RETURNS : nothing @DESCRIPTION: routine to create buffers for calculating smoothness of field @CREATED : Nov. 3, 1997, J. Taylor @MODIFIED : ---------------------------------------------------------------------------- */ int average_smoothness(char *tmp_lambda_file, char *lambda_file, double scalar) { Volume volume; nc_type in_nc_type; int in_signed_flag = FALSE; volume_input_struct volume_input; int v1, v2, v3; int num_dim; int sizes[MAX_DIMENSIONS]; double avg, values[8]; int i; if(start_volume_input(tmp_lambda_file, 3, NULL, NC_UNSPECIFIED, FALSE, 0.0, 0.0, TRUE, &volume, (minc_input_options *) NULL, &volume_input) != OK){ fprintf(stderr,"\nError opening %s.\n", tmp_lambda_file); exit(EXIT_FAILURE); } in_nc_type = get_volume_nc_data_type(volume, &in_signed_flag); get_volume_sizes(volume, sizes); num_dim = get_volume_n_dimensions(volume); cancel_volume_input(volume, &volume_input); if( input_volume(tmp_lambda_file, 3, NULL, NC_FLOAT, FALSE, 0.0, 0.0, TRUE, &volume, (minc_input_options *) NULL) != OK) { (void) fprintf(stderr, "Error reading file \"%s\"\n", tmp_lambda_file); return FALSE; } for(v1=0; v1<sizes[0]; v1++) { for(v2=0; v2<sizes[1]; v2++) { for(v3=0; v3<sizes[2]; v3++) { avg = 0.0; if((v1<sizes[0]-1) && (v2<sizes[1]-1) && (v3<sizes[2])-1) { values[0] = get_volume_real_value(volume, v1+1, v2, v3, 0, 0); values[1] = get_volume_real_value(volume, v1, v2+1, v3, 0, 0); values[2] = get_volume_real_value(volume, v1, v2, v3+1, 0, 0); values[3] = get_volume_real_value(volume,v1+1, v2+1, v3, 0, 0); values[4] = get_volume_real_value(volume, v1+1,v2, v3+1, 0, 0); values[5] = get_volume_real_value(volume, v1, v2+1,v3+1, 0, 0); values[6] = get_volume_real_value(volume, v1, v2, v3, 0, 0); values[7] = get_volume_real_value(volume, v1+1, v2+1,v3+1,0,0); for(i=0; i<8; i++) { if(values[i] != INVALID_DATA) avg += values[i]; else { avg = INVALID_DATA; i = 8; } } } else avg = INVALID_DATA; if (avg == 0.0) avg = INVALID_DATA; if (avg != INVALID_DATA) avg = scalar * 8.0 / pow(avg, (1.0 / num_dim)); set_volume_real_value(volume, v1, v2, v3, 0, 0, avg); } } } if( output_modified_volume(lambda_file, in_nc_type, in_signed_flag, 0.0, 0.0, volume, tmp_lambda_file, NULL, (minc_output_options *) NULL) != OK) { (void) fprintf(stderr, "Error writing file \"%s\"\n", lambda_file); return FALSE; } return TRUE; }