/* ----------------------------- MNI Header ----------------------------------- @NAME : handle_normalization @INPUT : reshape_info - information for reshaping volume block_start - start of current block block_count - count for current block minmax_buffer - buffer space for getting min and max values @OUTPUT : fillvalue - pixel fill value to use for this block @RETURNS : (none) @DESCRIPTION: Sets up icv for normalization to ensure that block is internally normalized. Output image-max and min are set. The appropriate pixel fill value is calculated for this min and max (applies to the whole block). @METHOD : @GLOBALS : @CALLS : @CREATED : October 25, 1994 (Peter Neelin) @MODIFIED : ---------------------------------------------------------------------------- */ static void handle_normalization(Reshape_info *reshape_info, long *block_start, long *block_count, double *minmax_buffer, double *fillvalue) { int iloop; int inmincid, inimgid, varid, icvid; long minmax_start[MAX_VAR_DIMS]; double minimum, maximum, *extreme, valid_min, valid_max, denom; char *varname; /* Get input minc id, image id and icv id*/ inmincid = reshape_info->inmincid; inimgid = ncvarid(inmincid, MIimage); icvid = reshape_info->icvid; /* Get input min and max for block */ get_block_min_and_max(reshape_info, block_start, block_count, minmax_buffer, &minimum, &maximum); /* Modify the icv if necessary */ if (reshape_info->do_block_normalization) { (void) miicv_detach(icvid); (void) miicv_setdbl(icvid, MI_ICV_IMAGE_MIN, minimum); (void) miicv_setdbl(icvid, MI_ICV_IMAGE_MAX, maximum); (void) miicv_setint(icvid, MI_ICV_USER_NORM, TRUE); (void) miicv_setint(icvid, MI_ICV_DO_NORM, TRUE); (void) miicv_attach(icvid, inmincid, inimgid); } /* Save the image max and min for the block */ for (iloop=0; iloop < 2; iloop++) { /* Get varid and pointer to min or max value */ switch (iloop) { case 0: varname = MIimagemin; extreme = &minimum; break; case 1: varname = MIimagemax; extreme = &maximum; break; } /* Save the value */ ncopts = 0; varid = ncvarid(reshape_info->outmincid, varname); ncopts = NCOPTS_DEFAULT; if (varid != MI_ERROR) { (void) mitranslate_coords(reshape_info->outmincid, reshape_info->outimgid, block_start, varid, minmax_start); (void) mivarput1(reshape_info->outmincid, varid, minmax_start, NC_DOUBLE, NULL, extreme); } } /* Calculate the pixel fill value */ *fillvalue = ((reshape_info->fillvalue == NOFILL) ? 0.0 : reshape_info->fillvalue); if ((reshape_info->output_datatype != NC_FLOAT) && (reshape_info->output_datatype != NC_DOUBLE) && (*fillvalue != FILL)) { (void) miicv_inqdbl(icvid, MI_ICV_VALID_MIN, &valid_min); (void) miicv_inqdbl(icvid, MI_ICV_VALID_MAX, &valid_max); denom = maximum - minimum; if (denom == 0.0) { *fillvalue = valid_min; } else { *fillvalue = (*fillvalue - minimum) * (valid_max - valid_min) / denom + valid_min; } } }
MNCAPI int minc_save_data(int fd, void *dataptr, int datatype, long st, long sz, long sy, long sx, long ct, long cz, long cy, long cx) { nc_type nctype; char *signstr; int i; int var_id; int var_ndims; int var_dims[MAX_NC_DIMS]; int icv; long start[MI_S_NDIMS]; long count[MI_S_NDIMS]; int old_ncopts; int r; double min, max; long slice_size; long index; int dtbytes; /* Length of datatype in bytes */ old_ncopts =get_ncopts(); set_ncopts(0); var_id = ncvarid(fd, MIimage); ncvarinq(fd, var_id, NULL, NULL, &var_ndims, var_dims, NULL); set_ncopts(old_ncopts); if (var_ndims < 2 || var_ndims > 4) { return (MINC_STATUS_ERROR); } r = minc_simple_to_nc_type(datatype, &nctype, &signstr); if (r == MINC_STATUS_ERROR) { return (MINC_STATUS_ERROR); } dtbytes = nctypelen(nctype); /* Update the image-min and image-max values */ if (ct > 0) { slice_size = cz * cy * cx; index = st; for (i = 0; i < ct; i++) { find_minmax((char *) dataptr + (dtbytes * slice_size * i), slice_size, datatype, &min, &max); mivarput1(fd, ncvarid(fd, MIimagemin), &index, NC_DOUBLE, MI_SIGNED, &min); mivarput1(fd, ncvarid(fd, MIimagemax), &index, NC_DOUBLE, MI_SIGNED, &max); index++; } } else { slice_size = cy * cx; index = sz; for (i = 0; i < cz; i++) { find_minmax((char *) dataptr + (dtbytes * slice_size * i), slice_size, datatype, &min, &max); mivarput1(fd, ncvarid(fd, MIimagemin), &index, NC_DOUBLE, MI_SIGNED, &min); mivarput1(fd, ncvarid(fd, MIimagemax), &index, NC_DOUBLE, MI_SIGNED, &max); index++; } } /* We want the data to wind up in t, x, y, z order. */ icv = miicv_create(); if (icv < 0) { return (MINC_STATUS_ERROR); } r = miicv_setint(icv, MI_ICV_TYPE, nctype); if (r < 0) { return (MINC_STATUS_ERROR); } r = miicv_setstr(icv, MI_ICV_SIGN, signstr); if (r < 0) { return (MINC_STATUS_ERROR); } r = miicv_setint(icv, MI_ICV_DO_NORM, 1); if (r < 0) { return (MINC_STATUS_ERROR); } r = miicv_setint(icv, MI_ICV_DO_FILLVALUE, 1); if (r < 0) { return (MINC_STATUS_ERROR); } r = miicv_attach(icv, fd, var_id); if (r < 0) { return (MINC_STATUS_ERROR); } i = 0; switch (var_ndims) { case 4: count[i] = ct; start[i] = st; i++; /* fall through */ case 3: count[i] = cz; start[i] = sz; i++; /* fall through */ case 2: count[i] = cy; start[i] = sy; i++; count[i] = cx; start[i] = sx; i++; break; } r = miicv_put(icv, start, count, dataptr); if (r < 0) { return (MINC_STATUS_ERROR); } miicv_detach(icv); miicv_free(icv); return (MINC_STATUS_OK); }
int main(int argc, char **argv) { /* NIFTI stuff */ nifti_image *nii_ptr; nifti_image nii_rec; int nii_dimids[MAX_NII_DIMS]; int nii_dir[MAX_NII_DIMS]; int nii_map[MAX_NII_DIMS]; unsigned long nii_lens[MAX_NII_DIMS]; int nii_ndims; static int nifti_filetype; static int nifti_datatype; static int nifti_signed = 1; /* MINC stuff */ int mnc_fd; /* MINC file descriptor */ nc_type mnc_type; /* MINC data type as read */ int mnc_ndims; /* MINC image dimension count */ int mnc_dimids[MAX_VAR_DIMS]; /* MINC image dimension identifiers */ long mnc_dlen; /* MINC dimension length value */ double mnc_dstep; /* MINC dimension step value */ int mnc_icv; /* MINC image conversion variable */ int mnc_vid; /* MINC Image variable ID */ long mnc_start[MAX_VAR_DIMS]; /* MINC data starts */ long mnc_count[MAX_VAR_DIMS]; /* MINC data counts */ int mnc_signed; /* MINC if output voxels are signed */ double real_range[2]; /* MINC real range (min, max) */ double input_valid_range[2]; /* MINC valid range (min, max) */ double output_valid_range[2]; /* Valid range of output data. */ double nifti_slope; /* Slope to be applied to output voxels. */ double nifti_inter; /* Intercept to be applied to output voxels. */ double total_valid_range; /* Overall valid range (max - min). */ double total_real_range; /* Overall real range (max - min). */ /* Other stuff */ char out_str[1024]; /* Big string for filename */ char att_str[1024]; /* Big string for attribute values */ int i; /* Generic loop counter the first */ int j; /* Generic loop counter the second */ char *str_ptr; /* Generic ASCIZ string pointer */ int r; /* Result code. */ static int vflag = 0; /* Verbose flag (default is quiet) */ static ArgvInfo argTable[] = { {NULL, ARGV_HELP, NULL, NULL, "Output voxel data type specification"}, {"-byte", ARGV_CONSTANT, (char *)DT_INT8, (char *)&nifti_datatype, "Write voxel data in 8-bit signed integer format."}, {"-short", ARGV_CONSTANT, (char *)DT_INT16, (char *)&nifti_datatype, "Write voxel data in 16-bit signed integer format."}, {"-int", ARGV_CONSTANT, (char *)DT_INT32, (char *)&nifti_datatype, "Write voxel data in 32-bit signed integer format."}, {"-float", ARGV_CONSTANT, (char *)DT_FLOAT32, (char *)&nifti_datatype, "Write voxel data in 32-bit floating point format."}, {"-double", ARGV_CONSTANT, (char *)DT_FLOAT64, (char *)&nifti_datatype, "Write voxel data in 64-bit floating point format."}, {"-signed", ARGV_CONSTANT, (char *)1, (char *)&nifti_signed, "Write integer voxel data in signed format."}, {"-unsigned", ARGV_CONSTANT, (char *)0, (char *)&nifti_signed, "Write integer voxel data in unsigned format."}, {NULL, ARGV_HELP, NULL, NULL, "Output file format specification"}, {"-dual", ARGV_CONSTANT, (char *)FT_NIFTI_DUAL, (char *)&nifti_filetype, "Write NIfTI-1 two-file format (.img and .hdr)"}, {"-ASCII", ARGV_CONSTANT, (char *)FT_NIFTI_ASCII, (char *)&nifti_filetype, "Write NIfTI-1 ASCII header format (.nia)"}, {"-nii", ARGV_CONSTANT, (char *)FT_NIFTI_SINGLE, (char *)&nifti_filetype, "Write NIfTI-1 one-file format (.nii)"}, {"-analyze", ARGV_CONSTANT, (char *)FT_ANALYZE, (char *)&nifti_filetype, "Write an Analyze two-file format file (.img and .hdr)"}, {NULL, ARGV_HELP, NULL, NULL, "Other options"}, {"-quiet", ARGV_CONSTANT, (char *)0, (char *)&vflag, "Quiet operation"}, {"-verbose", ARGV_CONSTANT, (char *)1, (char *)&vflag, "Quiet operation"}, {NULL, ARGV_END, NULL, NULL, NULL} }; ncopts = 0; /* Clear global netCDF error reporting flag */ /* Default NIfTI file type is "NII", single binary file */ nifti_filetype = FT_UNSPECIFIED; nifti_datatype = DT_UNKNOWN; if (ParseArgv(&argc, argv, argTable, 0) || (argc < 2)) { fprintf(stderr, "Too few arguments\n"); return usage(); } if (!nifti_signed) { switch (nifti_datatype) { case DT_INT8: nifti_datatype = DT_UINT8; break; case DT_INT16: nifti_datatype = DT_UINT16; break; case DT_INT32: nifti_datatype = DT_UINT32; break; } } switch (nifti_datatype){ case DT_INT8: case DT_UINT8: mnc_type = NC_BYTE; break; case DT_INT16: case DT_UINT16: mnc_type = NC_SHORT; break; case DT_INT32: case DT_UINT32: mnc_type = NC_INT; break; case DT_FLOAT32: mnc_type = NC_FLOAT; break; case DT_FLOAT64: mnc_type = NC_DOUBLE; break; } if (argc == 2) { strcpy(out_str, argv[1]); str_ptr = strrchr(out_str, '.'); if (str_ptr != NULL && !strcmp(str_ptr, ".mnc")) { *str_ptr = '\0'; } } else if (argc == 3) { strcpy(out_str, argv[2]); str_ptr = strrchr(out_str, '.'); if (str_ptr != NULL) { /* See if a recognized file extension was specified. If so, * we trim it off and set the output file type if none was * specified. If the extension is not recognized, assume * that we will form the filename by just adding the right * extension for the selected output format. */ if (!strcmp(str_ptr, ".nii")) { if (nifti_filetype == FT_UNSPECIFIED) { nifti_filetype = FT_NIFTI_SINGLE; } *str_ptr = '\0'; } else if (!strcmp(str_ptr, ".img") || !strcmp(str_ptr, ".hdr")) { if (nifti_filetype == FT_UNSPECIFIED) { nifti_filetype = FT_NIFTI_DUAL; } *str_ptr = '\0'; } else if (!strcmp(str_ptr, ".nia")) { if (nifti_filetype == FT_UNSPECIFIED) { nifti_filetype = FT_NIFTI_ASCII; } *str_ptr = '\0'; } } } else { fprintf(stderr, "Filename argument required\n"); return usage(); } /* Open the MINC file. It needs to exist. */ mnc_fd = miopen(argv[1], NC_NOWRITE); if (mnc_fd < 0) { fprintf(stderr, "Can't find input file '%s'\n", argv[1]); return (-1); } /* Find the MINC image variable. If we can't find it, there is no * further processing possible... */ mnc_vid = ncvarid(mnc_fd, MIimage); if (mnc_vid < 0) { fprintf(stderr, "Can't locate the image variable (mnc_vid=%d)\n", mnc_vid); return (-1); } /* Find out about the MINC image variable - specifically, how many * dimensions, and which dimensions. */ r = ncvarinq(mnc_fd, mnc_vid, NULL, NULL, &mnc_ndims, mnc_dimids, NULL); if (r < 0) { fprintf(stderr, "Can't read information from image variable\n"); return (-1); } if (mnc_ndims > MAX_NII_DIMS) { fprintf(stderr, "NIfTI-1 files may contain at most %d dimensions\n", MAX_NII_DIMS); return (-1); } /* Initialize the NIfTI structure */ nii_ptr = &nii_rec; init_nifti_header(nii_ptr); /* For now we just use the mnc2nii command line as the description * field. Probably we should use something better, perhaps a * combination of some other standard MINC fields that might * provide more information. */ str_ptr = nii_ptr->descrip; for (i = 0; i < argc; i++) { char *arg_ptr = argv[i]; if ((str_ptr - nii_ptr->descrip) >= MAX_NII_DESCRIP) { break; } if (i != 0) { *str_ptr++ = ' '; } while (*arg_ptr != '\0' && (str_ptr - nii_ptr->descrip) < MAX_NII_DESCRIP) { *str_ptr++ = *arg_ptr++; } *str_ptr = '\0'; } nii_ptr->fname = malloc(strlen(out_str) + 4 + 1); nii_ptr->iname = malloc(strlen(out_str) + 4 + 1); strcpy(nii_ptr->fname, out_str); strcpy(nii_ptr->iname, out_str); switch (nifti_filetype) { case FT_ANALYZE: strcat(nii_ptr->fname, ".hdr"); strcat(nii_ptr->iname, ".img"); break; case FT_NIFTI_SINGLE: strcat(nii_ptr->fname, ".nii"); strcat(nii_ptr->iname, ".nii"); break; case FT_NIFTI_DUAL: strcat(nii_ptr->fname, ".hdr"); strcat(nii_ptr->iname, ".img"); break; case FT_NIFTI_ASCII: strcat(nii_ptr->fname, ".nia"); strcat(nii_ptr->iname, ".nia"); break; default: fprintf(stderr, "Unknown output file type %d\n", nifti_filetype); return (-1); } /* Get real voxel range for the input file. */ miget_image_range(mnc_fd, real_range); /* Get the actual valid voxel value range. */ miget_valid_range(mnc_fd, mnc_vid, input_valid_range); /* Find the default range for the output type. Our output file * will use the full legal range of the output type if it is * an integer. */ if (nifti_datatype == DT_UNKNOWN) { nii_ptr->datatype = DT_FLOAT32; /* Default */ mnc_type = NC_FLOAT; mnc_signed = 1; } else { nii_ptr->datatype = nifti_datatype; mnc_signed = nifti_signed; } if (vflag) { fprintf(stderr, "MINC type %d signed %d\n", mnc_type, mnc_signed); } miget_default_range(mnc_type, mnc_signed, output_valid_range); total_valid_range = input_valid_range[1] - input_valid_range[0]; total_real_range = real_range[1] - real_range[0]; if ((output_valid_range[1] - output_valid_range[0]) > total_valid_range) { /* Empirically, forcing the valid range to be the nearest power * of two greater than the existing valid range seems to improve * the behavior of the conversion. This is at least in part because * of the limited precision of the NIfTI-1 voxel scaling fields. */ double new_range = nearest_power_of_two(total_valid_range); if (new_range - 1.0 >= total_valid_range) { new_range -= 1.0; } if (output_valid_range[1] > total_valid_range) { output_valid_range[0] = 0; output_valid_range[1] = new_range; } else { output_valid_range[1] = output_valid_range[0] + new_range; } } else { /* The new range can't fully represent the input range. Use the * full available range, and warn the user that they may have a * problem. */ printf("WARNING: Range of input exceeds range of output format.\n"); } if (vflag) { printf("Real range: %f %f Input valid range: %f %f Output valid range: %f %f\n", real_range[0], real_range[1], input_valid_range[0], input_valid_range[1], output_valid_range[0], output_valid_range[1]); } /* If the output type is not floating point, we may need to scale the * voxel values. */ if (mnc_type != NC_FLOAT && mnc_type != NC_DOUBLE) { /* Figure out how to map pixel values into the range of the * output datatype. */ nifti_slope = ((real_range[1] - real_range[0]) / (output_valid_range[1] - output_valid_range[0])); if (nifti_slope == 0.0) { nifti_slope = 1.0; } nifti_inter = real_range[0] - (output_valid_range[0] * nifti_slope); /* One problem with NIfTI-1 is the limited precision of the * scl_slope and scl_inter fields (they are just 32-bits). So * we look for possible issues and warn about that here. */ if (nifti_inter != (float) nifti_inter || nifti_slope != (float) nifti_slope) { double epsilon_i = nifti_inter - (float) nifti_inter; double epsilon_s = nifti_slope - (float) nifti_slope; /* If the loss in precision is more than one part per thousand * of the real range, flag this as a problem! */ if ((epsilon_i > total_real_range / 1.0e3) || (epsilon_s > total_real_range / 1.0e3)) { fprintf(stderr, "ERROR: Slope and intercept cannot be represented in the NIfTI-1 header.\n"); fprintf(stderr, " slope %f (%f), intercept %f (%f)\n", nifti_slope, (float) nifti_slope, nifti_inter, (float) nifti_inter); return (-1); } } } else { nifti_slope = 0.0; } nii_ptr->scl_slope = nifti_slope; nii_ptr->scl_inter = nifti_inter; nii_ptr->nvox = 1; /* Initial value for voxel count */ /* Find all of the dimensions of the MINC file, in the order they * will be listed in the NIfTI-1/Analyze file. We use this to build * a map for restructuring the data according to the normal rules * of NIfTI-1. */ nii_ndims = 0; for (i = 0; i < MAX_NII_DIMS; i++) { if (dimnames[i] == NULL) { nii_dimids[nii_ndims] = -1; continue; } nii_dimids[nii_ndims] = ncdimid(mnc_fd, dimnames[i]); if (nii_dimids[nii_ndims] == -1) { continue; } /* Make sure the dimension is actually used to define the image. */ for (j = 0; j < mnc_ndims; j++) { if (nii_dimids[nii_ndims] == mnc_dimids[j]) { nii_map[nii_ndims] = j; break; } } if (j < mnc_ndims) { mnc_dlen = 1; mnc_dstep = 0; ncdiminq(mnc_fd, nii_dimids[nii_ndims], NULL, &mnc_dlen); ncattget(mnc_fd, ncvarid(mnc_fd, dimnames[i]), MIstep, &mnc_dstep); if (mnc_dstep < 0) { nii_dir[nii_ndims] = -1; mnc_dstep = -mnc_dstep; } else { nii_dir[nii_ndims] = 1; } nii_lens[nii_ndims] = mnc_dlen; nii_ndims++; } nii_ptr->dim[dimmap[i]] = (int) mnc_dlen; nii_ptr->nvox *= mnc_dlen; nii_ptr->pixdim[dimmap[i]] = (float) mnc_dstep; } /* Here we do some "post-processing" of the results. Make certain that * the nt value is never zero, and make certain that ndim is set to * 4 if there is a time dimension and 5 if there is a vector dimension */ if (nii_ptr->dim[3] > 1 && nii_ndims < 4) { nii_ndims = 4; } if (nii_ptr->dim[4] > 1) { nii_ptr->intent_code = NIFTI_INTENT_VECTOR; nii_ndims = 5; } nii_ptr->ndim = nii_ndims; /* Total number of dimensions in file */ nii_ptr->nx = nii_ptr->dim[0]; nii_ptr->ny = nii_ptr->dim[1]; nii_ptr->nz = nii_ptr->dim[2]; nii_ptr->nt = nii_ptr->dim[3]; nii_ptr->nu = nii_ptr->dim[4]; nii_ptr->dx = nii_ptr->pixdim[0]; nii_ptr->dy = nii_ptr->pixdim[1]; nii_ptr->dz = nii_ptr->pixdim[2]; nii_ptr->dt = nii_ptr->pixdim[3]; nii_ptr->du = 1; /* MINC files don't define a sample size for a vector_dimension */ nii_ptr->nifti_type = nifti_filetype; /* Load the direction_cosines and start values into the NIfTI-1 * sform structure. * */ for (i = 0; i < MAX_SPACE_DIMS; i++) { int id = ncvarid(mnc_fd, mnc_spatial_names[i]); double start; double step; double dircos[MAX_SPACE_DIMS]; int tmp; if (id < 0) { continue; } /* Set default values */ start = 0.0; step = 1.0; dircos[DIM_X] = dircos[DIM_Y] = dircos[DIM_Z] = 0.0; dircos[i] = 1.0; miattget(mnc_fd, id, MIstart, NC_DOUBLE, 1, &start, &tmp); miattget(mnc_fd, id, MIstep, NC_DOUBLE, 1, &step, &tmp); miattget(mnc_fd, id, MIdirection_cosines, NC_DOUBLE, MAX_SPACE_DIMS, dircos, &tmp); ncdiminq(mnc_fd, ncdimid(mnc_fd, mnc_spatial_names[i]), NULL, &mnc_dlen); if (step < 0) { step = -step; start = start - step * (mnc_dlen - 1); } nii_ptr->sto_xyz.m[0][i] = step * dircos[0]; nii_ptr->sto_xyz.m[1][i] = step * dircos[1]; nii_ptr->sto_xyz.m[2][i] = step * dircos[2]; nii_ptr->sto_xyz.m[0][3] += start * dircos[0]; nii_ptr->sto_xyz.m[1][3] += start * dircos[1]; nii_ptr->sto_xyz.m[2][3] += start * dircos[2]; miattgetstr(mnc_fd, id, MIspacetype, sizeof(att_str), att_str); /* Try to set the S-transform code correctly. */ if (!strcmp(att_str, MI_TALAIRACH)) { nii_ptr->sform_code = NIFTI_XFORM_TALAIRACH; } else if (!strcmp(att_str, MI_CALLOSAL)) { /* TODO: Not clear what do do here... */ nii_ptr->sform_code = NIFTI_XFORM_SCANNER_ANAT; } else { /* MI_NATIVE or unknown */ nii_ptr->sform_code = NIFTI_XFORM_SCANNER_ANAT; } } /* So the last row is right... */ nii_ptr->sto_xyz.m[3][0] = 0.0; nii_ptr->sto_xyz.m[3][1] = 0.0; nii_ptr->sto_xyz.m[3][2] = 0.0; nii_ptr->sto_xyz.m[3][3] = 1.0; nii_ptr->sto_ijk = nifti_mat44_inverse(nii_ptr->sto_xyz); nifti_datatype_sizes(nii_ptr->datatype, &nii_ptr->nbyper, &nii_ptr->swapsize); if (vflag) { nifti_image_infodump(nii_ptr); } /* Now load the actual MINC data. */ nii_ptr->data = malloc(nii_ptr->nbyper * nii_ptr->nvox); if (nii_ptr->data == NULL) { fprintf(stderr, "Out of memory.\n"); return (-1); } mnc_icv = miicv_create(); miicv_setint(mnc_icv, MI_ICV_TYPE, mnc_type); miicv_setstr(mnc_icv, MI_ICV_SIGN, (mnc_signed) ? MI_SIGNED : MI_UNSIGNED); miicv_setdbl(mnc_icv, MI_ICV_VALID_MAX, output_valid_range[1]); miicv_setdbl(mnc_icv, MI_ICV_VALID_MIN, output_valid_range[0]); miicv_setdbl(mnc_icv, MI_ICV_IMAGE_MAX, real_range[1]); miicv_setdbl(mnc_icv, MI_ICV_IMAGE_MIN, real_range[0]); miicv_setdbl(mnc_icv, MI_ICV_DO_NORM, TRUE); miicv_setdbl(mnc_icv, MI_ICV_USER_NORM, TRUE); miicv_attach(mnc_icv, mnc_fd, mnc_vid); /* Read in the entire hyperslab from the file. */ for (i = 0; i < mnc_ndims; i++) { ncdiminq(mnc_fd, mnc_dimids[i], NULL, &mnc_count[i]); mnc_start[i] = 0; } r = miicv_get(mnc_icv, mnc_start, mnc_count, nii_ptr->data); if (r < 0) { fprintf(stderr, "Read error\n"); return (-1); } /* Shut down the MINC stuff now that it has done its work. */ miicv_detach(mnc_icv); miicv_free(mnc_icv); miclose(mnc_fd); if (vflag) { /* Debugging stuff - just to check the contents of these arrays. */ for (i = 0; i < nii_ndims; i++) { printf("%d: %ld %d %d\n", i, nii_lens[i], nii_map[i], nii_dir[i]); } printf("bytes per voxel %d\n", nii_ptr->nbyper); printf("# of voxels %ld\n", nii_ptr->nvox); } /* Rearrange the data to correspond to the NIfTI dimension ordering. */ restructure_array(nii_ndims, nii_ptr->data, nii_lens, nii_ptr->nbyper, nii_map, nii_dir); if (vflag) { /* More debugging stuff - check coordinate transform. */ test_xform(nii_ptr->sto_xyz, 0, 0, 0); test_xform(nii_ptr->sto_xyz, 10, 0, 0); test_xform(nii_ptr->sto_xyz, 0, 10, 0); test_xform(nii_ptr->sto_xyz, 0, 0, 10); test_xform(nii_ptr->sto_xyz, 10, 10, 10); } if (vflag) { fprintf(stdout, "Writing NIfTI-1 file..."); } nifti_image_write(nii_ptr); if (vflag) { fprintf(stdout, "done.\n"); } return (0); }
MNCAPI int minc_load_data(char *path, void *dataptr, int datatype, long *ct, long *cz, long *cy, long *cx, double *dt, double *dz, double *dy, double *dx, void **infoptr) { int fd; /* MINC file descriptor */ nc_type nctype; /* netCDF type */ char *signstr; /* MI_SIGNED or MI_UNSIGNED */ int length; int dim_id[MI_S_NDIMS]; long dim_len[MI_S_NDIMS]; int i, j; /* Generic loop counters */ int var_id; int var_ndims; int var_dims[MAX_NC_DIMS]; int icv; /* MINC image conversion variable */ long start[MI_S_NDIMS]; long count[MI_S_NDIMS]; size_t ucount[MI_S_NDIMS]; int dir[MI_S_NDIMS]; /* Dimension "directions" */ int map[MI_S_NDIMS]; /* Dimension mapping */ int old_ncopts; /* For storing the old state of ncopts */ double *p_dtmp; long *p_ltmp; struct file_info *p_file; struct att_info *p_att; int r; /* Generic return code */ *infoptr = NULL; fd = miopen(path, NC_NOWRITE); if (fd < 0) { return (MINC_STATUS_ERROR); } old_ncopts =get_ncopts(); set_ncopts(0); for (i = 0; i < MI_S_NDIMS; i++) { dim_id[i] = ncdimid(fd, minc_dimnames[i]); if (dim_id[i] >= 0) { ncdiminq(fd, dim_id[i], NULL, &dim_len[i]); var_id = ncvarid(fd, minc_dimnames[i]); ncattinq(fd, var_id, MIstep, &nctype, &length); switch (i) { case MI_S_T: p_ltmp = ct; p_dtmp = dt; break; case MI_S_X: p_ltmp = cx; p_dtmp = dx; break; case MI_S_Y: p_ltmp = cy; p_dtmp = dy; break; case MI_S_Z: p_ltmp = cz; p_dtmp = dz; break; default: return (MINC_STATUS_ERROR); } if (nctype == NC_DOUBLE && length == 1) { ncattget(fd, var_id, MIstep, p_dtmp); } else { *p_dtmp = 0; /* Unknown/not set */ } *p_ltmp = dim_len[i]; } else { dim_len[i] = 0; } } set_ncopts(old_ncopts); var_id = ncvarid(fd, MIimage); ncvarinq(fd, var_id, NULL, &nctype, &var_ndims, var_dims, NULL); if (var_ndims != 3 && var_ndims != 4) { return (MINC_STATUS_ERROR); } /* We want the data to wind up in t, x, y, z order. */ for (i = 0; i < MI_S_NDIMS; i++) { map[i] = -1; } for (i = 0; i < var_ndims; i++) { if (var_dims[i] == dim_id[MI_S_T]) { map[MI_S_T] = i; } else if (var_dims[i] == dim_id[MI_S_X]) { map[MI_S_X] = i; } else if (var_dims[i] == dim_id[MI_S_Y]) { map[MI_S_Y] = i; } else if (var_dims[i] == dim_id[MI_S_Z]) { map[MI_S_Z] = i; } } icv = miicv_create(); minc_simple_to_nc_type(datatype, &nctype, &signstr); miicv_setint(icv, MI_ICV_TYPE, nctype); miicv_setstr(icv, MI_ICV_SIGN, signstr); miicv_attach(icv, fd, var_id); for (i = 0; i < var_ndims; i++) { start[i] = 0; } for (i = 0; i < MI_S_NDIMS; i++) { if (map[i] >= 0) { count[map[i]] = dim_len[i]; } } r = miicv_get(icv, start, count, dataptr); if (r < 0) { return (MINC_STATUS_ERROR); } if (map[MI_S_T] >= 0) { if (*dt < 0) { dir[MI_S_T] = -1; *dt = -*dt; } else { dir[MI_S_T] = 1; } } if (map[MI_S_X] >= 0) { if (*dx < 0) { dir[MI_S_X] = -1; *dx = -*dx; } else { dir[MI_S_X] = 1; } } if (map[MI_S_Y] >= 0) { if (*dy < 0) { dir[MI_S_Y] = -1; *dy = -*dy; } else { dir[MI_S_Y] = 1; } } if (map[MI_S_Z] >= 0) { if (*dz < 0) { dir[MI_S_Z] = -1; *dz = -*dz; } else { dir[MI_S_Z] = 1; } } if (var_ndims == 3) { for (i = 1; i < MI_S_NDIMS; i++) { map[i-1] = map[i]; dir[i-1] = dir[i]; } } j = 0; for (i = 0; i < MI_S_NDIMS; i++) { if (dim_len[i] > 0) { ucount[j++] = dim_len[i]; } } restructure_array(var_ndims, dataptr, ucount, nctypelen(nctype), map, dir); miicv_detach(icv); miicv_free(icv); old_ncopts =get_ncopts(); set_ncopts(0); /* Generate the complete infoptr array. * This is essentially an in-memory copy of the variables and attributes * in the file. */ p_file = (struct file_info *) malloc(sizeof (struct file_info)); ncinquire(fd, &p_file->file_ndims, &p_file->file_nvars, &p_file->file_natts, NULL); p_file->file_atts = (struct att_info *) malloc(sizeof (struct att_info) * p_file->file_natts); p_file->file_vars = (struct var_info *) malloc(sizeof (struct var_info) * p_file->file_nvars); for (i = 0; i < p_file->file_natts; i++) { p_att = &p_file->file_atts[i]; ncattname(fd, NC_GLOBAL, i, p_att->att_name); ncattinq(fd, NC_GLOBAL, p_att->att_name, &p_att->att_type, &p_att->att_len); p_att->att_val = malloc(p_att->att_len * nctypelen(p_att->att_type)); ncattget(fd, NC_GLOBAL, p_att->att_name, p_att->att_val); } for (i = 0; i < p_file->file_nvars; i++) { struct var_info *p_var = &p_file->file_vars[i]; ncvarinq(fd, i, p_var->var_name, &p_var->var_type, &p_var->var_ndims, p_var->var_dims, &p_var->var_natts); p_var->var_atts = malloc(p_var->var_natts * sizeof (struct att_info)); if (ncdimid(fd, p_var->var_name) >= 0) { /* It's a dimension variable, have to treat it specially... */ } for (j = 0; j < p_var->var_natts; j++) { p_att = &p_var->var_atts[j]; ncattname(fd, i, j, p_att->att_name); ncattinq(fd, i, p_att->att_name, &p_att->att_type, &p_att->att_len); p_att->att_val = malloc(p_att->att_len * nctypelen(p_att->att_type)); ncattget(fd, i, p_att->att_name, p_att->att_val); } } *infoptr = p_file; set_ncopts(old_ncopts); miclose(fd); return (MINC_STATUS_OK); }
int test7(struct testinfo *ip, struct dimdef *dims, int ndims) { size_t total; long coords[3]; long lengths[3]; void *buf_ptr; int *int_ptr; int i, j, k; int stat; int icv; total = 1; for (i = 0; i < ndims; i++) { total *= dims[i].length; } buf_ptr = malloc(total * sizeof (float)); if (buf_ptr == NULL) { fprintf(stderr, "Oops, malloc failed\n"); return (-1); } icv = miicv_create(); if (icv < 0) { FUNC_ERROR("miicv_create"); } /* Test range conversion. */ stat = miicv_setint(icv, MI_ICV_DO_DIM_CONV, 0); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_DO_RANGE, 1); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setstr(icv, MI_ICV_SIGN, MI_UNSIGNED); if (stat < 0) { FUNC_ERROR("miicv_setstr"); } stat = miicv_setint(icv, MI_ICV_TYPE, NC_INT); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_VALID_MAX, 1000); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_VALID_MIN, -1000); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_attach(icv, ip->fd, ip->imgid); if (stat < 0) { FUNC_ERROR("miicv_attach"); } coords[TST_X] = 0; coords[TST_Y] = 0; coords[TST_Z] = 0; lengths[TST_X] = dims[TST_X].length; lengths[TST_Y] = dims[TST_Y].length; lengths[TST_Z] = dims[TST_Z].length; stat = miicv_get(icv, coords, lengths, buf_ptr); if (stat < 0) { FUNC_ERROR("miicv_get"); } int_ptr = (int *) buf_ptr; for (i = 0; i < dims[TST_X].length; i++) { for (j = 0; j < dims[TST_Y].length; j++) { for (k = 0; k < dims[TST_Z].length; k++, int_ptr++) { int tmp = (i * 10000) + (j * 100) + (k); int rng = (XSIZE * 10000) / 1000; /* Round tmp properly. */ tmp = (tmp + (rng / 2)) / rng; if (*int_ptr != tmp) { fprintf(stderr, "5. Data error at (%d,%d,%d) %d != %d\n", i,j,k, *int_ptr, tmp); errors++; } } } } stat = miicv_detach(icv); if (stat < 0) { FUNC_ERROR("miicv_detach"); } /* Free the ICV */ stat = miicv_free(icv); if (stat < 0) { FUNC_ERROR("miicv_free"); } free(buf_ptr); return (0); }
int test6(struct testinfo *ip, struct dimdef *dims, int ndims) { size_t total; long coords[3]; long lengths[3]; void *buf_ptr; int *int_ptr; int i, j, k; int stat; int icv; total = 1; total *= dims[TST_X].length; total *= dims[TST_Y].length - YBOOST; total *= dims[TST_Z].length - ZBOOST; buf_ptr = malloc(total * sizeof (int)); if (buf_ptr == NULL) { fprintf(stderr, "Oops, malloc failed\n"); return (-1); } icv = miicv_create(); if (icv < 0) { FUNC_ERROR("miicv_create"); } /* Now try reading the image with reduced size. */ stat = miicv_setint(icv, MI_ICV_BDIM_SIZE, dims[TST_Y].length - YBOOST); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_ADIM_SIZE, dims[TST_Z].length - ZBOOST); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_DO_DIM_CONV, 1); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_attach(icv, ip->fd, ip->imgid); if (stat < 0) { FUNC_ERROR("miicv_attach"); } coords[TST_X] = 0; coords[TST_Y] = 0; coords[TST_Z] = 0; lengths[TST_X] = dims[TST_X].length; lengths[TST_Y] = dims[TST_Y].length - YBOOST; lengths[TST_Z] = dims[TST_Z].length - ZBOOST; stat = miicv_get(icv, coords, lengths, buf_ptr); if (stat < 0) { FUNC_ERROR("miicv_get"); } int_ptr = (int *) buf_ptr; for (i = 0; i < dims[TST_X].length; i++) { for (j = 0; j < dims[TST_Y].length - YBOOST; j++) { for (k = 0; k < dims[TST_Z].length - ZBOOST; k++, int_ptr++) { int tmp; tmp = (i * 10000) + (j * 100) + (k); if (*int_ptr != (int) tmp) { fprintf(stderr, "4. Data error at (%d,%d,%d) %d != %d\n", i,j,k, *int_ptr, tmp); errors++; } } } } stat = miicv_detach(icv); if (stat < 0) { FUNC_ERROR("miicv_detach"); } stat = miicv_free(icv); if (stat < 0) { FUNC_ERROR("miicv_free"); } free(buf_ptr); return (0); }
int test5(struct testinfo *ip, struct dimdef *dims, int ndims) { /* Get the same variable again, but this time use an ICV to scale it. */ size_t total; long coords[3]; long lengths[3]; void *buf_ptr; int *int_ptr; int i, j, k; int stat; int icv; total = 1; total *= dims[TST_X].length; total *= dims[TST_Y].length + YBOOST; total *= dims[TST_Z].length + ZBOOST; buf_ptr = malloc(total * sizeof (int)); if (buf_ptr == NULL) { fprintf(stderr, "Oops, malloc failed\n"); return (-1); } icv = miicv_create(); if (icv < 0) { FUNC_ERROR("miicv_create"); } /* Now set up a dimension conversion. */ stat = miicv_setint(icv, MI_ICV_DO_NORM, 0); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_DO_RANGE, 0); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_TYPE, NC_INT); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_YDIM_DIR, MI_ICV_NEGATIVE); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_ZDIM_DIR, MI_ICV_NEGATIVE); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_BDIM_SIZE, dims[TST_Y].length + YBOOST); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_ADIM_SIZE, dims[TST_Z].length + ZBOOST); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_DO_DIM_CONV, 1); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_attach(icv, ip->fd, ip->imgid); if (stat < 0) { FUNC_ERROR("miicv_attach"); } coords[TST_X] = 0; coords[TST_Y] = 0; coords[TST_Z] = 0; lengths[TST_X] = dims[TST_X].length; lengths[TST_Y] = dims[TST_Y].length + YBOOST; lengths[TST_Z] = dims[TST_Z].length + ZBOOST; stat = miicv_get(icv, coords, lengths, buf_ptr); if (stat < 0) { FUNC_ERROR("miicv_get"); } int_ptr = (int *) buf_ptr; for (i = 0; i < dims[TST_X].length; i++) { for (j = 0; j < dims[TST_Y].length + YBOOST; j++) { for (k = 0; k < dims[TST_Z].length + ZBOOST; k++, int_ptr++) { int x; int y; int z; int tmp; if (j < YBOOST/2 || j >= dims[TST_Y].length + YBOOST/2) continue; if (k < ZBOOST/2 || k >= dims[TST_Z].length + ZBOOST/2) continue; x = i; y = (YSIZE + YBOOST - 1) - j; z = (ZSIZE + ZBOOST - 1) - k; y -= YBOOST / 2; z -= ZBOOST / 2; tmp = (x * 10000) + (y * 100) + (z); if (*int_ptr != (int) tmp) { fprintf(stderr, "3. Data error at (%d,%d,%d) %d != %d\n", i,j,k, *int_ptr, tmp); errors++; } } } } stat = miicv_detach(icv); if (stat < 0) { FUNC_ERROR("miicv_detach"); } stat = miicv_free(icv); if (stat < 0) { FUNC_ERROR("miicv_free"); } free(buf_ptr); return (0); }
int test4(struct testinfo *ip, struct dimdef *dims, int ndims) { /* Get the same variable again, but this time use an ICV to scale it. */ size_t total; long coords[3]; long lengths[3]; double range[2]; void *buf_ptr; float *flt_ptr; int i, j, k; int stat; int icv; double dbl; total = 1; for (i = 0; i < ndims; i++) { total *= dims[i].length; } buf_ptr = malloc(total * sizeof (float)); if (buf_ptr == NULL) { fprintf(stderr, "Oops, malloc failed\n"); return (-1); } coords[TST_X] = 0; coords[TST_Y] = 0; coords[TST_Z] = 0; lengths[TST_X] = dims[TST_X].length; lengths[TST_Y] = dims[TST_Y].length; lengths[TST_Z] = dims[TST_Z].length; icv = miicv_create(); if (icv < 0) { FUNC_ERROR("miicv_create"); } stat = miicv_setint(icv, MI_ICV_TYPE, NC_FLOAT); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_DO_NORM, 1); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_attach(icv, ip->fd, ip->imgid); if (stat < 0) { FUNC_ERROR("miicv_attach"); } /* This next call _should_ fail, since the ICV has been attached. */ stat = miicv_setint(icv, MI_ICV_DO_NORM, 0); if (stat >= 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_inqdbl(icv, MI_ICV_DO_NORM, &dbl); if (stat < 0) { FUNC_ERROR("miicv_inqdbl"); } if (dbl != 1.0) { fprintf(stderr, "miicv_inqdbl: Bad value returned\n"); errors++; } stat = miicv_get(icv, coords, lengths, buf_ptr); if (stat < 0) { FUNC_ERROR("miicv_get"); } stat = miget_image_range(ip->fd, range); if (stat < 0) { FUNC_ERROR("miget_image_range"); } if (range[0] != -(XSIZE * 100000.0) || range[1] != (XSIZE * 100000.00)) { fprintf(stderr, "miget_image_range: bad result\n"); errors++; } stat = miget_valid_range(ip->fd, ip->imgid, range); if (stat < 0) { FUNC_ERROR("miget_valid_range"); } if (range[0] != -(XSIZE * 10000.0) || range[1] != (XSIZE * 10000.0)) { fprintf(stderr, "miget_valid_range: bad result\n"); errors++; } flt_ptr = (float *) buf_ptr; for (i = 0; i < dims[TST_X].length; i++) { for (j = 0; j < dims[TST_Y].length; j++) { for (k = 0; k < dims[TST_Z].length; k++) { float tmp = (i * 10000) + (j * 100) + k; if (*flt_ptr != (float) tmp * 10.0) { fprintf(stderr, "2. Data error at (%d,%d,%d) %f != %f\n", i,j,k, *flt_ptr, tmp); errors++; } flt_ptr++; } } } stat = miicv_detach(icv); if (stat < 0) { FUNC_ERROR("miicv_detach"); } /* Try it again, to make certain we fail gracefully. */ stat = miicv_detach(icv); if (stat < 0) { FUNC_ERROR("miicv_detach"); } /* Try to detach a completely random number. */ stat = miicv_detach(rand()); if (stat >= 0) { FUNC_ERROR("miicv_detach"); } stat = miicv_free(icv); if (stat < 0) { FUNC_ERROR("miicv_free"); } free(buf_ptr); return (0); }