Mercurial > hg > minc-tools
view libsrc2/m2util.c @ 1635:46f087c96c53
Latest rounds of changes
author | bert <bert> |
---|---|
date | Mon, 26 Jan 2004 23:25:46 +0000 |
parents | defcdf5993a8 |
children | 507fd776b022 |
line wrap: on
line source
/** \file m2util.c * \brief MINC 2.0 Private utility functions * \author Leila Baghdadi, Bert Vincent * ************************************************************************/ #include <stdlib.h> #include <math.h> #include <hdf5.h> #include <minc.h> #include <limits.h> #include "minc2.h" #include "minc2_private.h" /*! Convert a MINC 2 datatype into a HDF5 datatype. Actually returns a copy * of the datatype, so the returned value must be explicitly freed with a * call to H5Tclose(). * \param mitype The MINC 2 data type to convert */ hid_t mitype_to_hdftype(mitype_t mitype) { hid_t type_id; switch (mitype) { case MI_TYPE_BYTE: type_id = H5Tcopy(H5T_NATIVE_SCHAR); break; case MI_TYPE_CHAR: type_id = H5Tcopy(H5T_NATIVE_SCHAR); break; case MI_TYPE_SHORT: type_id = H5Tcopy(H5T_NATIVE_SHORT); break; case MI_TYPE_INT: type_id = H5Tcopy(H5T_NATIVE_INT); break; case MI_TYPE_FLOAT: type_id = H5Tcopy(H5T_NATIVE_FLOAT); break; case MI_TYPE_DOUBLE: type_id = H5Tcopy(H5T_NATIVE_DOUBLE); break; case MI_TYPE_UBYTE: type_id = H5Tcopy(H5T_NATIVE_UCHAR); break; case MI_TYPE_USHORT: type_id = H5Tcopy(H5T_NATIVE_USHORT); break; case MI_TYPE_UINT: type_id = H5Tcopy(H5T_NATIVE_UINT); break; case MI_TYPE_SCOMPLEX: type_id = H5Tcreate(H5T_COMPOUND, 4); H5Tinsert(type_id, "real", 0, H5T_NATIVE_SHORT); H5Tinsert(type_id, "imag", 2, H5T_NATIVE_SHORT); break; case MI_TYPE_ICOMPLEX: type_id = H5Tcreate(H5T_COMPOUND, 8); H5Tinsert(type_id, "real", 0, H5T_NATIVE_INT); H5Tinsert(type_id, "imag", 4, H5T_NATIVE_INT); break; case MI_TYPE_FCOMPLEX: type_id = H5Tcreate(H5T_COMPOUND, 8); H5Tinsert(type_id, "real", 0, H5T_NATIVE_FLOAT); H5Tinsert(type_id, "imag", 4, H5T_NATIVE_FLOAT); break; case MI_TYPE_DCOMPLEX: type_id = H5Tcreate(H5T_COMPOUND, 16); H5Tinsert(type_id, "real", 0, H5T_NATIVE_DOUBLE); H5Tinsert(type_id, "imag", 8, H5T_NATIVE_DOUBLE); break; default: type_id = H5Tcopy(mitype); /* Else it is a standard HDF type handle */ break; } return (type_id); } /*! Convert a MINC 2 datatype into a NetCDF datatype. * \param mitype The MINC 2 data type to convert * \param is_signed Set to TRUE if the data type is signed, FALSE if unsigned. */ int mitype_to_nctype(mitype_t mitype, int *is_signed) { int nctype; *is_signed = 1; /* Assume signed by default. */ switch (mitype) { case MI_TYPE_BYTE: nctype = NC_BYTE; break; case MI_TYPE_SHORT: nctype = NC_SHORT; break; case MI_TYPE_INT: nctype = NC_INT; break; case MI_TYPE_FLOAT: nctype = NC_FLOAT; break; case MI_TYPE_DOUBLE: nctype = NC_DOUBLE; break; case MI_TYPE_UBYTE: nctype = NC_BYTE; *is_signed = 0; break; case MI_TYPE_USHORT: nctype = NC_SHORT; *is_signed = 0; break; case MI_TYPE_UINT: nctype = NC_INT; *is_signed = 1; break; default: nctype = -1; /* ERROR!! */ break; } return (nctype); } /*! Return the group or dataset ID of the last item in a "path", * specified like a UNIX pathname /black/white/red etc. * \param file_id The HDF5 handle of the file (or group) at which to start * the search. * \param path A string consisting of a slash-separated list of * HDF5 groupnames */ hid_t midescend_path(hid_t file_id, const char *path) { hid_t tmp_id; /* Put H5E_BEGIN_TRY/H5E_END_TRY around this to avoid the overzealous * automatic error reporting of HDF5. */ H5E_BEGIN_TRY { tmp_id = H5Gopen(file_id, path); /* If the group open fails, try opening the object as a dataset. */ if (tmp_id < 0) { tmp_id = H5Dopen(file_id, path); } } H5E_END_TRY; return (tmp_id); } /** Get the number of voxels in the file - this is the total number, * not just spatial dimensions */ mi_i64_t miget_voxel_count(int mincid) { int imgid; int dim[MI2_MAX_VAR_DIMS]; int idim; int ndims; mi_i64_t nvoxels; long length; /* Get the dimension ids for the image variable */ imgid = ncvarid(mincid, MIimage); (void)ncvarinq(mincid, imgid, NULL, NULL, &ndims, dim, NULL); /* Loop over them to get the total number of voxels */ nvoxels = 1; for (idim = 0; idim < ndims; idim++) { (void)ncdiminq(mincid, dim[idim], NULL, &length); nvoxels *= length; } return (nvoxels); } int miset_attr_at_loc(hid_t hdf_loc, const char *name, mitype_t data_type, int length, const void *values) { hid_t hdf_type; hid_t hdf_space; hid_t hdf_attr; hsize_t hdf_len; H5E_BEGIN_TRY { hdf_attr = H5Aopen_name(hdf_loc, name); } H5E_END_TRY; /* Delete the existing attribute. */ if (hdf_attr >= 0) { H5Adelete(hdf_loc, name); } switch (data_type) { case MI_TYPE_INT: hdf_type = H5Tcopy(H5T_NATIVE_INT); break; case MI_TYPE_FLOAT: hdf_type = H5Tcopy(H5T_NATIVE_FLOAT); break; case MI_TYPE_DOUBLE: hdf_type = H5Tcopy(H5T_NATIVE_DOUBLE); break; case MI_TYPE_STRING: hdf_type = H5Tcopy(H5T_C_S1); H5Tset_size(hdf_type, length); length = 1; /* Apparent length is one. */ break; default: return (MI_ERROR); } if (length == 1) { hdf_space = H5Screate(H5S_SCALAR); } else { hdf_len = (hsize_t) length; hdf_space = H5Screate_simple(1, &hdf_len, NULL); } if (hdf_space < 0) { return (MI_ERROR); } hdf_attr = H5Acreate(hdf_loc, name, hdf_type, hdf_space, H5P_DEFAULT); if (hdf_attr < 0) { return (MI_ERROR); } H5Awrite(hdf_attr, hdf_type, values); H5Aclose(hdf_attr); H5Tclose(hdf_type); H5Sclose(hdf_space); return (MI_NOERROR); } /** Set an attribute from a minc file */ int miset_attribute(mihandle_t volume, const char *path, const char *name, mitype_t data_type, int length, const void *values) { hid_t hdf_file; hid_t hdf_loc; /* Get a handle to the actual HDF file */ hdf_file = volume->hdf_id; if (hdf_file < 0) { return (MI_ERROR); } /* Search through the path, descending into each group encountered. */ hdf_loc = midescend_path(hdf_file, path); if (hdf_loc < 0) { return (MI_ERROR); } miset_attr_at_loc(hdf_loc, name, data_type, length, values); /* The hdf_loc identifier could be a group or a dataset. */ if (H5Iget_type(hdf_loc) == H5I_GROUP) { H5Gclose(hdf_loc); } else { H5Dclose(hdf_loc); } return (MI_NOERROR); } /** Get a double attribute from a minc file */ int miget_attribute(mihandle_t volume, const char *path, const char *name, mitype_t data_type, int length, void *values) { hid_t hdf_file; hid_t hdf_loc; hid_t hdf_type; hid_t hdf_space; hid_t hdf_attr; /* Get a handle to the actual HDF file */ hdf_file = volume->hdf_id; if (hdf_file < 0) { return (MI_ERROR); } /* Search through the path, descending into each group encountered. */ hdf_loc = midescend_path(hdf_file, path); if (hdf_loc < 0) { return (MI_ERROR); } H5E_BEGIN_TRY { hdf_attr = H5Aopen_name(hdf_loc, name); } H5E_END_TRY; if (hdf_attr < 0) { return (MI_ERROR); } switch (data_type) { case MI_TYPE_INT: hdf_type = H5Tcopy(H5T_NATIVE_INT); break; case MI_TYPE_UINT: hdf_type = H5Tcopy(H5T_NATIVE_ULONG); break; case MI_TYPE_FLOAT: hdf_type = H5Tcopy(H5T_NATIVE_FLOAT); break; case MI_TYPE_DOUBLE: hdf_type = H5Tcopy(H5T_NATIVE_DOUBLE); break; case MI_TYPE_STRING: hdf_type = H5Tcopy(H5T_C_S1); H5Tset_size(hdf_type, length); break; default: return (MI_ERROR); } hdf_space = H5Aget_space(hdf_attr); if (hdf_space < 0) { return (MI_ERROR); } /* If we're retrieving a vector, make certain the length passed into this * function is sufficient. */ if (H5Sget_simple_extent_ndims(hdf_space) == 1) { hsize_t hdf_dims[1]; H5Sget_simple_extent_dims(hdf_space, hdf_dims, NULL); if (length < hdf_dims[0]) { return (MI_ERROR); } } H5Aread(hdf_attr, hdf_type, values); H5Aclose(hdf_attr); H5Tclose(hdf_type); H5Sclose(hdf_space); /* The hdf_loc identifier could be a group or a dataset. */ if (H5Iget_type(hdf_loc) == H5I_GROUP) { H5Gclose(hdf_loc); } else { H5Dclose(hdf_loc); } return (MI_NOERROR); } /* Get the mapping from spatial dimension - x, y, z - to file dimensions * and vice-versa. */ void mifind_spatial_dims(int mincid, int space_to_dim[], int dim_to_space[]) { int imgid, dim[MI2_MAX_VAR_DIMS]; int idim, ndims, world_index; char dimname[MAX_NC_NAME]; /* Set default values */ for (idim = 0; idim < 3; idim++) space_to_dim[idim] = -1; for (idim = 0; idim < MI2_MAX_VAR_DIMS; idim++) dim_to_space[idim] = -1; /* Get the dimension ids for the image variable */ imgid = ncvarid(mincid, MIimage); (void)ncvarinq(mincid, imgid, NULL, NULL, &ndims, dim, NULL); /* Loop over them to find the spatial ones */ for (idim = 0; idim < ndims; idim++) { /* Get the name and check that this is a spatial dimension */ (void)ncdiminq(mincid, dim[idim], dimname, NULL); if (!strcmp(dimname, MIxspace)) { world_index = MI2_X; } else if (!strcmp(dimname, MIyspace)) { world_index = MI2_Y; } else if (!strcmp(dimname, MIzspace)) { world_index = MI2_Z; } else { continue; } space_to_dim[world_index] = idim; dim_to_space[idim] = world_index; } } /** Get the voxel to world transform (for column vectors) */ void miget_voxel_to_world(mihandle_t volume, mi_lin_xfm_t voxel_to_world) { int i; int j; double dircos[MI2_3D]; double step; double start; static char *dimensions[] = { "/minc-2.0/dimensions/" MIxspace, "/minc-2.0/dimensions/" MIyspace, "/minc-2.0/dimensions/" MIzspace }; /* Zero the matrix */ for (i = 0; i < MI2_LIN_XFM_SIZE; i++) { for (j = 0; j < MI2_LIN_XFM_SIZE; j++) { voxel_to_world[i][j] = 0.0; } voxel_to_world[i][i] = 1.0; } for (j = 0; j < MI2_3D; j++) { /* Set default values */ step = 1.0; start = 0.0; for (i = 0; i < MI2_3D; i++) dircos[i] = 0.0; dircos[j] = 1.0; /* Get the attributes */ H5E_BEGIN_TRY { miget_attribute(volume, dimensions[j], MIstart, MI_TYPE_DOUBLE, 1, &start); miget_attribute(volume, dimensions[j], MIstep, MI_TYPE_DOUBLE, 1, &step); miget_attribute(volume, dimensions[j], MIdirection_cosines, MI_TYPE_DOUBLE, MI2_3D, dircos); } H5E_END_TRY; minormalize_vector(dircos); /* Put them in the matrix */ for (i = 0; i < MI2_3D; i++) { voxel_to_world[i][j] = step * dircos[i]; voxel_to_world[i][MI2_3D] += start * dircos[i]; } } } /** Normalize a 3 element vector */ void minormalize_vector(double vector[MI2_3D]) { int i; double magnitude; magnitude = 0.0; for (i = 0; i < MI2_3D; i++) { magnitude += (vector[i] * vector[i]); } magnitude = sqrt(magnitude); if (magnitude > 0.0) { for (i = 0; i < MI2_3D; i++) { vector[i] /= magnitude; } } } /** Transforms a coordinate through a linear transform */ void mitransform_coord(double out_coord[], mi_lin_xfm_t transform, const double in_coord[]) { int i, j; double in_homogeneous[MI2_3D + 1]; double out_homogeneous[MI2_3D + 1]; for (i = 0; i < MI2_3D; i++) { in_homogeneous[i] = in_coord[i]; } in_homogeneous[MI2_3D] = 1.0; for (i = 0; i < MI2_3D + 1; i++) { out_homogeneous[i] = 0.0; for (j = 0; j < MI2_3D + 1; j++) { out_homogeneous[i] += transform[i][j] * in_homogeneous[j]; } } #if 0 printf("W = %f\n", out_homogeneous[3]); #endif /* 0 */ for (i = 0; i < MI2_3D; i++) { out_coord[i] = out_homogeneous[i]; } } /** Generic HDF5 integer-to-double converter. */ static herr_t mi2_int_to_dbl(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, hsize_t nelements, size_t buf_stride, size_t bkg_stride, void *buf_ptr, void *bkg_ptr, hid_t dset_xfer_plist) { unsigned char *dst_ptr; unsigned char *src_ptr; int src_nb; int dst_nb; H5T_sign_t src_sg; double t; int dst_cnt; int src_cnt; switch (cdata->command) { case H5T_CONV_INIT: cdata->need_bkg = H5T_BKG_NO; src_nb = H5Tget_size(src_id); if (src_nb != 1 && src_nb != 2 && src_nb != 4) { return (-1); } dst_nb = H5Tget_size(dst_id); if (dst_nb != 8) { return (-1); } break; case H5T_CONV_CONV: src_nb = H5Tget_size(src_id); src_sg = H5Tget_sign(src_id); dst_nb = H5Tget_size(dst_id); if (buf_stride == 0) { dst_cnt = dst_nb; src_cnt = src_nb; } else { dst_cnt = buf_stride; src_cnt = buf_stride; } /* Convert starting from "far side" of buffer... (Hope this works!) */ dst_ptr = ((unsigned char *) buf_ptr) + ((nelements - 1) * dst_nb); src_ptr = ((unsigned char *) buf_ptr) + ((nelements - 1) * src_nb); if (src_sg == H5T_SGN_2) { switch (src_nb) { case 4: while (nelements-- > 0) { t = *(int *)src_ptr; *(double *)dst_ptr = t; src_ptr -= src_cnt; dst_ptr -= dst_cnt; } break; case 2: while (nelements-- > 0) { t = *(short *)src_ptr; *(double *)dst_ptr = t; src_ptr -= src_cnt; dst_ptr -= dst_cnt; } break; case 1: while (nelements-- > 0) { t = *(char *)src_ptr; *(double *)dst_ptr = t; src_ptr -= src_cnt; dst_ptr -= dst_cnt; } break; default: /* Should not happen! */ break; } } else { switch (src_nb) { case 4: while (nelements-- > 0) { t = *(unsigned int *)src_ptr; *(double *)dst_ptr = t; src_ptr -= src_cnt; dst_ptr -= dst_cnt; } break; case 2: while (nelements-- > 0) { t = *(unsigned short *)src_ptr; *(double *)dst_ptr = t; src_ptr -= src_cnt; dst_ptr -= dst_cnt; } break; case 1: while (nelements-- > 0) { t = *(unsigned char *)src_ptr; *(double *)dst_ptr = t; src_ptr -= src_cnt; dst_ptr -= dst_cnt; } break; default: /* Should not happen! */ break; } } break; case H5T_CONV_FREE: break; default: /* Unknown command */ return (-1); } return (0); } /** Generic HDF5 double-to-integer converter. */ static herr_t mi2_dbl_to_int(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, hsize_t nelements, size_t buf_stride, size_t bkg_stride, void *buf_ptr, void *bkg_ptr, hid_t dset_xfer_plist) { unsigned char *dst_ptr; unsigned char *src_ptr; int src_nb; int dst_nb; H5T_sign_t dst_sg; double t; int dst_cnt; int src_cnt; switch (cdata->command) { case H5T_CONV_INIT: cdata->need_bkg = H5T_BKG_NO; /* Verify that we can handle this conversion. */ src_nb = H5Tget_size(src_id); if (src_nb != 8) { return (-1); } dst_nb = H5Tget_size(dst_id); if (dst_nb != 4 && dst_nb != 2 && dst_nb != 1) { return (-1); } break; case H5T_CONV_CONV: dst_nb = H5Tget_size(dst_id); dst_sg = H5Tget_sign(dst_id); src_nb = H5Tget_size(src_id); dst_ptr = (unsigned char *) buf_ptr; src_ptr = (unsigned char *) buf_ptr; /* The logic of HDF5 seems to be that if a stride is specified, * both the source and destination pointers should advance by that * amount. This seems wrong to me, but I've examined the HDF5 sources * and that's what their own type converters do. */ if (buf_stride == 0) { dst_cnt = dst_nb; src_cnt = src_nb; } else { dst_cnt = buf_stride; src_cnt = buf_stride; } if (dst_sg == H5T_SGN_2) { switch (dst_nb) { case 4: while (nelements-- > 0) { t = rint(*(double *) src_ptr); if (t > INT_MAX) { t = INT_MAX; } else if (t < INT_MIN) { t = INT_MIN; } *((int *)dst_ptr) = (int) t; dst_ptr += dst_cnt; src_ptr += src_cnt; } break; case 2: while (nelements-- > 0) { t = rint(*(double *) src_ptr); if (t > SHRT_MAX) { t = SHRT_MAX; } else if (t < SHRT_MIN) { t = SHRT_MIN; } *((short *)dst_ptr) = (short) t; dst_ptr += dst_cnt; src_ptr += src_cnt; } break; case 1: while (nelements-- > 0) { t = rint(*(double *) src_ptr); if (t > CHAR_MAX) { t = CHAR_MAX; } else if (t < CHAR_MIN) { t = CHAR_MIN; } *((char *)src_ptr) = (char) t; dst_ptr += dst_cnt; src_ptr += src_cnt; } break; default: /* Can't handle this! */ break; } } else { switch (dst_nb) { case 4: while (nelements-- > 0) { t = rint(*(double *)src_ptr); if (t > UINT_MAX) { t = UINT_MAX; } else if (t < 0) { t = 0; } *((unsigned int *)dst_ptr) = (unsigned int) t; dst_ptr += dst_cnt; src_ptr += src_cnt; } break; case 2: while (nelements-- > 0) { t = rint(*(double *)src_ptr); if (t > USHRT_MAX) { t = USHRT_MAX; } else if (t < 0) { t = 0; } *((unsigned short *)dst_ptr) = (unsigned short) t; dst_ptr += dst_cnt; src_ptr += src_cnt; } break; case 1: while (nelements-- > 0) { t = rint(*(double *)src_ptr); if (t > UCHAR_MAX) { t = UCHAR_MAX; } else if (t < 0) { t = 0; } *((unsigned char *)dst_ptr) = (unsigned char) t; dst_ptr += dst_cnt; src_ptr += src_cnt; } break; default: /* Can't handle any other values */ break; } } break; case H5T_CONV_FREE: break; default: /* Unknown command */ return (-1); } return (0); } /** Initialize some critical pieces of the library. For now all this does is install the double-to-integer and integer-to-double conversion functions. */ void miinit(void) { H5Tregister(H5T_PERS_SOFT, "i2d", H5T_NATIVE_INT, H5T_NATIVE_DOUBLE, mi2_int_to_dbl); H5Tregister(H5T_PERS_SOFT, "d2i", H5T_NATIVE_DOUBLE, H5T_NATIVE_INT, mi2_dbl_to_int); } /** HDF5 type conversion function for converting an arbitrary integer type to * an arbitrary enumerated type. The beauty part of this is that it is * not necessary to actually perform any real conversion! */ herr_t mi2_null_conv(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, hsize_t nelements, size_t buf_stride, size_t bkg_stride, void *buf_ptr, void *bkg_ptr, hid_t dset_xfer_plist) { switch (cdata->command) { case H5T_CONV_INIT: case H5T_CONV_CONV: case H5T_CONV_FREE: break; default: /* Unknown command */ return (-1); } return (0); } /** This function should be called when a labeled volume is created or opened in order to facilitate conversions from the integer to the enumerated type. */ void miinit_enum(hid_t type_id) { H5Tregister(H5T_PERS_SOFT, "i2e", H5T_NATIVE_INT, type_id, mi2_null_conv); H5Tregister(H5T_PERS_SOFT, "e2i", type_id, H5T_NATIVE_INT, mi2_null_conv); H5Tregister(H5T_PERS_SOFT, "d2e", H5T_NATIVE_DOUBLE, type_id, mi2_dbl_to_int); H5Tregister(H5T_PERS_SOFT, "e2d", type_id, H5T_NATIVE_DOUBLE, mi2_int_to_dbl); } int minc_create_thumbnail(hid_t file_id, int grp) { char path[MI2_MAX_PATH]; hid_t grp_id; /* Don't handle negative or overly large numbers! */ if (grp <= 0 || grp > MAX_RESOLUTION_GROUP) { return (MI_ERROR); } sprintf(path, "/minc-2.0/image/%d", grp); grp_id = H5Gcreate(file_id, path, 0); if (grp_id < 0) { return (MI_ERROR); } H5Gclose(grp_id); return (MI_NOERROR); } /** Function to downsample a single slice of an image. * \param in_ptr the 3D input slice, scale x isize[1] x isize[2] * \param out_ptr the 2D output slice, osize[1] x osize[2] */ void midownsample_slice(double *in_ptr, double *out_ptr, hsize_t isize[], hsize_t osize[], int scale) { int j, k; int x, y, z; double d; hsize_t total; total = scale * scale * scale; /* These two loops iterate over all of the voxels in the 2D output * image. */ for (j = 0; j < osize[1]; j++) { for (k = 0; k < osize[2]; k++) { /* The three inner loops iterate all scale^3 * voxels in the input image which will be averaged * to form the output image. */ d = 0; for (x = 0; x < scale; x++) { for (y = 0; y < scale; y++) { for (z = 0; z < scale; z++) { int x1,y1,z1; double t; x1 = x; y1 = y + (j * scale); z1 = z + (k * scale); t = in_ptr[((x1 * isize[1]) + y1) * isize[2] + z1]; d += t; } } } d /= total; out_ptr[(j * osize[1]) + k] = d; } } } int minc_update_thumbnail(hid_t loc_id, int igrp, int ogrp) { hsize_t isize[MI2_MAX_VAR_DIMS]; hsize_t osize[MI2_MAX_VAR_DIMS]; hsize_t count[MI2_MAX_VAR_DIMS]; hsize_t start[MI2_MAX_VAR_DIMS]; hid_t idst_id; /* Input dataset */ hid_t odst_id; /* Output dataset */ hid_t ifspc_id; /* Input "file" dataspace */ hid_t ofspc_id; /* Output "file" dataspace */ hid_t typ_id; /* Type ID */ hid_t imspc_id; hid_t omspc_id; char path[MI2_MAX_PATH]; int ndims; int scale; int i; double *in_ptr; double *out_ptr; int slice; int in_bytes; int out_bytes; miinit(); /* Calculate scale factor (always a power of 2) */ for (i = igrp, scale = 1; i < ogrp; i++, scale <<= 1) ; /* Open the input path. */ sprintf(path, "%d/image", igrp); idst_id = H5Dopen(loc_id, path); if (idst_id < 0) { return (MI_ERROR); } /* Get the input type. */ typ_id = H5Dget_type(idst_id); /* Get the input dataspace. */ ifspc_id = H5Dget_space(idst_id); ndims = H5Sget_simple_extent_ndims(ifspc_id); H5Sget_simple_extent_dims(ifspc_id, isize, NULL); /* Calculate the size of the new thumbnail. */ for (i = 0; i < ndims; i++) { osize[i] = isize[i] / scale; if (osize[i] == 0) { /* Too small? */ return (MI_ERROR); } } ofspc_id = H5Screate_simple(ndims, osize, NULL); sprintf(path, "%d/image", ogrp); /* TODO: Non-default properties */ odst_id = H5Dcreate(loc_id, path, typ_id, ofspc_id, H5P_DEFAULT); if (odst_id < 0) { odst_id = H5Dopen(loc_id, path); } /* Calculate the input buffer size - scale slices. */ in_bytes = scale * isize[1] * isize[2] * sizeof(double); in_ptr = malloc(in_bytes); out_bytes = osize[1] * osize[2] * sizeof(double); out_ptr = malloc(out_bytes); count[0] = scale; count[1] = isize[1]; count[2] = isize[2]; imspc_id = H5Screate_simple(ndims, count, NULL); count[0] = 1; count[1] = osize[1]; count[2] = osize[2]; omspc_id = H5Screate_simple(ndims, count, NULL); // // read image & TODO: convert to "real" range. // for (slice = 0; slice < osize[0]; slice++) { fprintf(stderr, "Slice # %d\n", slice); start[0] = slice * scale; start[1] = 0; start[2] = 0; count[0] = scale; count[1] = isize[1]; count[2] = isize[2]; H5Sselect_hyperslab(ifspc_id, H5S_SELECT_SET, start, NULL, count, NULL); H5Dread(idst_id, H5T_NATIVE_DOUBLE, imspc_id, ifspc_id, H5P_DEFAULT, in_ptr); midownsample_slice(in_ptr, out_ptr, isize, osize, scale); start[0] = slice; start[1] = 0; start[2] = 0; count[0] = 1; count[1] = osize[1]; count[2] = osize[2]; H5Sselect_hyperslab(ofspc_id, H5S_SELECT_SET, start, NULL, count, NULL); H5Dwrite(odst_id, H5T_NATIVE_DOUBLE, omspc_id, ofspc_id, H5P_DEFAULT, out_ptr); } free(in_ptr); free(out_ptr); H5Sclose(omspc_id); H5Sclose(imspc_id); H5Dclose(odst_id); H5Tclose(typ_id); H5Sclose(ofspc_id); H5Sclose(ifspc_id); return (MI_NOERROR); } int minc_update_thumbnails(hid_t file_id) { int grp_no, prv_grp_no; hid_t grp_id; hsize_t n; hsize_t i; char name[128]; size_t length; grp_id = H5Gopen(file_id, "/minc-2.0/image"); if (grp_id >= 0) { if (H5Gget_num_objs(grp_id, &n) != 0) { for (i = 0; i < n; i++) { length = sizeof(name); H5Gget_objname_by_idx(grp_id, i, name, length); fprintf(stderr, "Found group %s\n", name); prv_grp_no = grp_no; grp_no = atoi(name); if (grp_no != 0) { fprintf(stderr, "Updating group #%d from #%d\n", grp_no, prv_grp_no); minc_update_thumbnail(grp_id, prv_grp_no, grp_no); } } } else { fprintf(stderr, "error getting object count?\n"); } H5Gclose(grp_id); } else { fprintf(stderr, "error opening group?\n"); } return (MI_NOERROR); } /** Performs scaled maximal pivoting gaussian elimination as a numerically robust method to solve systems of linear equations. */ static int scaled_maximal_pivoting_gaussian_elimination(int row[4], double a[4][4], double solution[4][4] ) { int i, j, k, p, v, tmp; double s[4], val, best_val, m, scale_factor; int result; for ( i = 0; i < 4; i++) { row[i] = i; } for ( i = 0; i < 4; i++) { s[i] = fabs( a[i][0] ); for ( j = 1; j < 4; j++ ) { if ( fabs(a[i][j]) > s[i] ) { s[i] = fabs(a[i][j]); } } if ( s[i] == 0.0 ) { return ( MI_ERROR ); } } result = MI_NOERROR; for ( i = 0; i < 4 - 1; i++ ) { p = i; best_val = a[row[i]][i] / s[row[i]]; best_val = fabs( best_val ); for ( j = i + 1; j < 4; j++ ) { val = a[row[j]][i] / s[row[j]]; val = fabs( val ); if( val > best_val ) { best_val = val; p = j; } } if ( a[row[p]][i] == 0.0 ) { result = MI_ERROR; break; } if ( i != p ) { tmp = row[i]; row[i] = row[p]; row[p] = tmp; } for ( j = i + 1; j < 4; j++ ) { if ( a[row[i]][i] == 0.0 ) { result = MI_ERROR; break; } m = a[row[j]][i] / a[row[i]][i]; for ( k = i + 1; k < 4; k++ ) a[row[j]][k] -= m * a[row[i]][k]; for( v = 0; v < 4; v++ ) solution[row[j]][v] -= m * solution[row[i]][v]; } if (result != MI_NOERROR) break; } if ( result == MI_NOERROR && a[row[4-1]][4-1] == 0.0 ) result = MI_ERROR; if ( result == MI_NOERROR ) { for ( i = 4-1; i >= 0; --i ) { for ( j = i+1; j < 4; j++) { scale_factor = a[row[i]][j]; for ( v = 0; v < 4; v++ ) solution[row[i]][v] -= scale_factor * solution[row[j]][v]; } for( v = 0; v < 4; v++ ) solution[row[i]][v] /= a[row[i]][i]; } } return (result); } static int scaled_maximal_pivoting_gaussian_elimination_real(double coefs[4][4], double values[4][4]) { int i, j, v, row[4]; double a[4][4], solution[4][4]; int result; for ( i = 0; i < 4; i++) { for (j = 0; j < 4; j++) a[i][j] = coefs[i][j]; for ( v = 0; v < 4; v++ ) solution[i][v] = values[v][i]; } result = scaled_maximal_pivoting_gaussian_elimination(row, a, solution); if ( result == MI_NOERROR ) { for ( i = 0; i < 4; i++ ) { for ( v = 0; v < 4; v++ ) values[v][i] = solution[row[i]][v]; } } return ( result ); } /** Computes the inverse of a square matrix. */ static int invert_4x4_matrix(double matrix[4][4], /**< Input matrix */ double inverse[4][4]) /**< Output (inverted) matrix */ { double tmp; int result; int i, j; /* Start off with the identity matrix. */ for ( i = 0; i < 4; i++ ) { for ( j = 0; j < 4; j++ ) { inverse[i][j] = 0.0; } inverse[i][i] = 1.0; } result = scaled_maximal_pivoting_gaussian_elimination_real( matrix, inverse ); if ( result == MI_NOERROR ) { for ( i = 0; i < 4 - 1; i++) { for ( j = i + 1; j < 4; j++ ) { tmp = inverse[i][j]; inverse[i][j] = inverse[j][i]; inverse[j][i] = tmp; } } } return (result); } /** Fills in the transform with the identity matrix. */ static void mimake_identity_transform(mi_lin_xfm_t transform) { int i, j; for (i = 0; i < MI2_LIN_XFM_SIZE; i++) { for (j = 0; j < MI2_LIN_XFM_SIZE; j++) { transform[i][j] = 0.0; } transform[i][i] = 1.0; } } /** Function for inverting a MINC linear transform. */ int miinvert_transform(mi_lin_xfm_t transform, mi_lin_xfm_t inverse ) { int result; result = invert_4x4_matrix( transform, inverse ); if (result != MI_NOERROR) { mimake_identity_transform(inverse); } return ( result ); } /** Function to read a scalar variable. */ miget_scalar(hid_t loc_id, hid_t type_id, const char *path, void *data) { hid_t dset_id; hid_t spc_id; int result = MI_ERROR; dset_id = H5Dopen(loc_id, path); if (dset_id >= 0) { spc_id = H5Dget_space(dset_id); if (spc_id >= 0) { if (H5Sget_simple_extent_ndims(spc_id) == 0) { if (H5Dread(dset_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) >= 0) { result = MI_NOERROR; } } H5Sclose(spc_id); } H5Dclose(dset_id); } return (result); }