/* returns a new Kernel struct (pointer) */ Kernel *new_kernel(int nelems) { int i, j; Kernel *tmp; ALLOC_VAR_SIZED_STRUCT(tmp, VIO_Real, 10); /* allocate and initialise the Kernel Array */ SET_ARRAY_SIZE(tmp->K, 0, nelems, 10); for(i = 0; i < nelems; i++){ ALLOC(tmp->K[i], KERNEL_DIMS + 1); for(j = 0; j < KERNEL_DIMS; j++){ tmp->K[i][j] = 0.0; } tmp->K[i][KERNEL_DIMS] = 1.0; } tmp->nelems = nelems; return tmp; }
/* 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); }
/* reads in a Kernel from a file */ VIO_Status input_kernel(const char *kernel_file, Kernel * kernel) { int i, j; VIO_STR line; VIO_STR type_name; VIO_STR str; VIO_Real tmp_real; FILE *file; /* parameter checking */ if(kernel_file == NULL){ print_error("input_kernel(): passed NULL FILE.\n"); return (VIO_ERROR); } file = fopen(kernel_file, "r"); if(file == NULL){ print_error("input_kernel(): error opening Kernel file.\n"); return (VIO_ERROR); } /* okay read the header */ if(mni_input_string(file, &line, (char)0, (char)0) != VIO_OK){ delete_string(line); print_error("input_kernel(): could not read header in file.\n"); return (VIO_ERROR); } if(!equal_strings(line, KERNEL_FILE_HEADER)){ delete_string(line); print_error("input_kernel(): invalid header in file.\n"); return (VIO_ERROR); } /* --- read the type of Kernel */ if(mni_input_keyword_and_equal_sign(file, KERNEL_TYPE, FALSE) != VIO_OK){ return (VIO_ERROR); } if(mni_input_string(file, &type_name, (char)';', (char)0) != VIO_OK){ print_error("input_kernel(): missing kernel type.\n"); return (VIO_ERROR); } if(mni_skip_expected_character(file, (char)';') != VIO_OK){ return (VIO_ERROR); } if(!equal_strings(type_name, NORMAL_KERNEL)){ print_error("input_kernel(): invalid kernel type.\n"); delete_string(type_name); return (VIO_ERROR); } delete_string(type_name); /* --- read the next string */ if(mni_input_string(file, &str, (char)'=', (char)0) != VIO_OK) return (VIO_ERROR); if(!equal_strings(str, KERNEL)){ print_error("Expected %s =\n", KERNEL); delete_string(str); return (VIO_ERROR); } delete_string(str); if(mni_skip_expected_character(file, (char)'=') != VIO_OK){ return (VIO_ERROR); } /* now read the elements (lines) of the kernel */ if(verbose){ fprintf(stderr, "Reading [%s]", kernel_file); } for(i = 0; i < MAX_KERNEL_ELEMS; i++){ /* allocate a bit of memory */ SET_ARRAY_SIZE(kernel->K, kernel->nelems, kernel->nelems + 1, 10); ALLOC(kernel->K[i], KERNEL_DIMS + 1); /* get the 5 dimension vectors and the coefficient */ for(j = 0; j < 6; j++){ if(mni_input_real(file, &tmp_real) == VIO_OK){ kernel->K[i][j] = tmp_real; } else { /* check for end */ if(mni_skip_expected_character(file, (char)';') == VIO_OK){ kernel->nelems = i; if(verbose){ fprintf(stderr, " %dx%d Kernel elements read\n", i, kernel->nelems); } return (VIO_OK); } else { print_error("input_kernel(): error reading kernel [%d,%d]\n", i + 1, j + 1); return (VIO_ERROR); } } } kernel->nelems++; if(verbose){ fprintf(stderr, "."); fflush(stderr); } } /* SHOLDN'T BE REACHED */ print_error("input_kernel(): Glark! Something is amiss in the State of Kansas\n"); return (VIO_ERROR); }
VIOAPI VIO_Status input_tag_points( FILE *file, int *n_volumes_ptr, int *n_tag_points, VIO_Real ***tags_volume1, VIO_Real ***tags_volume2, VIO_Real **weights, int **structure_ids, int **patient_ids, VIO_STR *labels[] ) { VIO_Status status; VIO_Real tags1[VIO_N_DIMENSIONS]; VIO_Real tags2[VIO_N_DIMENSIONS]; VIO_Real weight; int structure_id, patient_id, n_volumes; VIO_STR label; status = initialize_tag_file_input( file, &n_volumes ); if( n_volumes_ptr != NULL ) *n_volumes_ptr = n_volumes; *n_tag_points = 0; while( status == VIO_OK && input_one_tag( file, n_volumes, tags1, tags2, &weight, &structure_id, &patient_id, &label, &status ) ) { if( tags_volume1 != NULL ) { SET_ARRAY_SIZE( *tags_volume1, *n_tag_points, *n_tag_points+1, DEFAULT_CHUNK_SIZE ); ALLOC( (*tags_volume1)[*n_tag_points], 3 ); (*tags_volume1)[*n_tag_points][VIO_X] = tags1[VIO_X]; (*tags_volume1)[*n_tag_points][VIO_Y] = tags1[VIO_Y]; (*tags_volume1)[*n_tag_points][VIO_Z] = tags1[VIO_Z]; } if( n_volumes == 2 && tags_volume2 != NULL ) { SET_ARRAY_SIZE( *tags_volume2, *n_tag_points, *n_tag_points+1, DEFAULT_CHUNK_SIZE ); ALLOC( (*tags_volume2)[*n_tag_points], 3 ); (*tags_volume2)[*n_tag_points][VIO_X] = tags2[VIO_X]; (*tags_volume2)[*n_tag_points][VIO_Y] = tags2[VIO_Y]; (*tags_volume2)[*n_tag_points][VIO_Z] = tags2[VIO_Z]; } if( weights != NULL ) { SET_ARRAY_SIZE( *weights, *n_tag_points, *n_tag_points+1, DEFAULT_CHUNK_SIZE); (*weights)[*n_tag_points] = weight; } if( structure_ids != NULL ) { SET_ARRAY_SIZE( *structure_ids, *n_tag_points, *n_tag_points+1, DEFAULT_CHUNK_SIZE); (*structure_ids)[*n_tag_points] = structure_id; } if( patient_ids != NULL ) { SET_ARRAY_SIZE( *patient_ids, *n_tag_points, *n_tag_points+1, DEFAULT_CHUNK_SIZE); (*patient_ids)[*n_tag_points] = patient_id; } if( labels != NULL ) { SET_ARRAY_SIZE( *labels, *n_tag_points, *n_tag_points+1, DEFAULT_CHUNK_SIZE); (*labels)[*n_tag_points] = label; } else delete_string( label ); ++(*n_tag_points); } return( status ); }
int main( int argc, char *argv[] ) { Volume volume; STRING input_filename, output_filename; int n_slices, n_components; pixels_struct *pixels; nc_type vol_type; BOOLEAN two_d_allowed; initialize_argument_processing( argc, argv ); if( !get_string_argument( NULL, &output_filename ) || !get_int_argument( 0, &n_components ) ) { print( "Usage: %s output.mnc 3|4|23|24 input1.rgb input2.rgb ...\n", argv[0] ); return( 1 ); } if( n_components > 100 ) { vol_type = NC_FLOAT; n_components -= 100; } else vol_type = NC_BYTE; if( n_components > 20 ) { two_d_allowed = TRUE; n_components -= 20; } else { two_d_allowed = FALSE; } n_slices = 0; pixels = NULL; while( get_string_argument( "", &input_filename ) ) { SET_ARRAY_SIZE( pixels, n_slices, n_slices+1, DEFAULT_CHUNK_SIZE ); if( input_rgb_file( input_filename, &pixels[n_slices] ) != OK ) return( 1 ); ++n_slices; } volume = convert_pixels_to_volume( n_components, n_slices, (two_d_allowed && n_slices == 1) ? 2 : 3, vol_type, pixels ); if( volume != NULL ) { (void) output_volume( output_filename, NC_UNSPECIFIED, FALSE, 0.0, 0.0, volume, "Converted from pixels", (minc_output_options *) NULL ); delete_volume( volume ); } return( 0 ); }