/* Convert an mxArray to an Image. mx must have at most IM_NDIMS + 1 * dimensions and be of type single (float). */ int mx2im(const mxArray *const mx, Image *const im) { const mwSize *mxDims; float *mxData; mwIndex mxNDims; int i, x, y, z, c, mxNSpaceDims; // Verify inputs mxNDims = (int) mxGetNumberOfDimensions(mx); if (mxNDims > MX_IM_NDIMS || !mxIsSingle(mx) || mxIsComplex(mx)) return SIFT3D_FAILURE; // Copy the spatial dimensions mxNSpaceDims = SIFT3D_MIN((int) mxNDims, MX_IM_NDIMS - 1); mxDims = mxGetDimensions(mx); for (i = 0; i < mxNSpaceDims; i++) { SIFT3D_IM_GET_DIMS(im)[i] = (int) mxDims[i]; } // Pad the unfilled dimensions with 1 for (i = mxNSpaceDims; i < MX_IM_NDIMS - 1; i++) { SIFT3D_IM_GET_DIMS(im)[i] = 1; } // Copy the number of channels, defaulting to 1 im->nc = mxNDims == MX_IM_NDIMS ? (int) mxDims[MX_IM_NDIMS] : 1; // Resize the output im_default_stride(im); if (im_resize(im)) return SIFT3D_FAILURE; // Get the data if ((mxData = mxGetData(mx)) == NULL) return SIFT3D_FAILURE; // Transpose and copy the data SIFT3D_IM_LOOP_START_C(im, x, y, z, c) mwIndex idx; idx = mxImGetIdx(mx, x, y, z, c); SIFT3D_IM_GET_VOX(im, x, y, z, c) = mxData[idx]; SIFT3D_IM_LOOP_END_C return SIFT3D_SUCCESS; }
/* Helper function to write an image to a directory of DICOM files using C++ */ static int write_dcm_dir_cpp(const char *path, const Image *const im, const Dcm_meta *const meta) { Image slice; // Initialize C intermediates init_im(&slice); // Initialize the metadata to defaults, if it is null Dcm_meta meta_new; set_meta_defaults(meta, &meta_new); // Get the number of leading zeros for the file names const int num_slices = im->nz; const int num_zeros = static_cast<int>(ceil(log10( static_cast<double>(num_slices)))); // Form the printf format string for file names #define BUF_LEN 16 char format[BUF_LEN]; snprintf(format, BUF_LEN, "%%0%dd.%s", num_zeros, ext_dcm); #undef BUF_LEN // Resize the slice buffer slice.nx = im->nx; slice.ny = im->ny; slice.nz = 1; slice.nc = im->nc; im_default_stride(&slice); if (im_resize(&slice)) { im_free(&slice); return SIFT3D_FAILURE; } // Copy the units to the slice memcpy(SIFT3D_IM_GET_UNITS(&slice), SIFT3D_IM_GET_UNITS(im), IM_NDIMS * sizeof(double)); // Get the maximum absolute value of the whole image volume const float max_val = im_max_abs(im); // Write each slice for (int i = 0; i < num_slices; i++) { // Form the slice file name #define BUF_LEN 1024 char buf[BUF_LEN]; snprintf(buf, BUF_LEN, format, i); // Form the full file path std::string fullfile(path + sepStr + buf); // Copy the data to the slice int x, y, z, c; SIFT3D_IM_LOOP_START_C(&slice, x, y, z, c) SIFT3D_IM_GET_VOX(&slice, x, y, z, c) = SIFT3D_IM_GET_VOX(im, x, y, i, c); SIFT3D_IM_LOOP_END_C // Generate a new SOPInstanceUID dcmGenerateUniqueIdentifier(meta_new.instance_uid, SITE_INSTANCE_UID_ROOT); // Set the instance number const unsigned int instance = static_cast<unsigned int>(i + 1); meta_new.instance_num = instance; // Write the slice to a file if (write_dcm(fullfile.c_str(), &slice, &meta_new, max_val)) { im_free(&slice); return SIFT3D_FAILURE; } } // Clean up im_free (&slice); return SIFT3D_SUCCESS; }
/* Helper funciton to read a directory of DICOM files using C++ */ static int read_dcm_dir_cpp(const char *path, Image *const im) { struct stat st; DIR *dir; struct dirent *ent; int i, nx, ny, nz, nc, num_files, off_z; // Verify that the directory exists if (stat(path, &st)) { SIFT3D_ERR("read_dcm_dir_cpp: cannot find file %s \n", path); return SIFT3D_FAILURE; } else if (!S_ISDIR(st.st_mode)) { SIFT3D_ERR("read_dcm_dir_cpp: file %s is not a directory \n", path); return SIFT3D_FAILURE; } // Open the directory if ((dir = opendir(path)) == NULL) { SIFT3D_ERR("read_dcm_dir_cpp: unexpected error opening " "directory %s \n", path); return SIFT3D_FAILURE; } // Get all of the .dcm files in the directory std::vector<Dicom> dicoms; while ((ent = readdir(dir)) != NULL) { // Form the full file path std::string fullfile(std::string(path) + sepStr + ent->d_name); // Check if it is a DICOM file if (im_get_format(fullfile.c_str()) != DICOM) continue; // Read the file Dicom dicom(fullfile); if (!dicom.isValid()) { closedir(dir); return SIFT3D_FAILURE; } // Add the file to the list dicoms.push_back(dicom); } // Release the directory closedir(dir); // Get the number of files num_files = dicoms.size(); // Verify that dicom files were found if (num_files == 0) { SIFT3D_ERR("read_dcm_dir_cpp: no DICOM files found in %s \n", path); return SIFT3D_FAILURE; } // Check that the files are from the same series const Dicom &first = dicoms[0]; for (int i = 1; i < num_files; i++) { const Dicom &dicom = dicoms[i]; if (!first.eqSeries(dicom)) { SIFT3D_ERR("read_dcm_dir_cpp: file %s is from a " "different series than file %s \n", dicom.name().c_str(), first.name().c_str()); return SIFT3D_FAILURE; } } // Initialize the output dimensions nx = first.getNx(); ny = first.getNy(); nc = first.getNc(); // Verify the dimensions of the other files, counting the total // series z-dimension nz = 0; for (i = 0; i < num_files; i++) { // Get a slice const Dicom &dicom = dicoms[i]; // Verify the dimensions if (dicom.getNx() != nx || dicom.getNy() != ny || dicom.getNc() != nc) { SIFT3D_ERR("read_dcm_dir_cpp: slice %s " "(%d, %d, %d) does not match the " "dimensions of slice %s (%d, %d, %d) \n", dicom.name().c_str(), dicom.getNx(), dicom.getNy(), dicom.getNc(), first.name().c_str(), nx, ny, nc); return SIFT3D_FAILURE; } // Count the z-dimension nz += dicom.getNz(); } // Resize the output im->nx = nx; im->ny = ny; im->nz = nz; im->nc = nc; im->ux = first.getUx(); im->uy = first.getUy(); im->uz = first.getUz(); im_default_stride(im); if (im_resize(im)) return SIFT3D_FAILURE; // Sort the slices by z position std::sort(dicoms.begin(), dicoms.end()); // Allocate a temporary image for the slices Image slice; init_im(&slice); // Read the image data off_z = 0; for (i = 0; i < num_files; i++) { int x, y, z, c; const char *slicename = dicoms[i].name().c_str(); // Read the slice if (read_dcm(slicename, &slice)) { im_free(&slice); return SIFT3D_FAILURE; } // Copy the data to the volume SIFT3D_IM_LOOP_START_C(&slice, x, y, z, c) SIFT3D_IM_GET_VOX(im, x, y, z + off_z, c) = SIFT3D_IM_GET_VOX(&slice, x, y, z, c); SIFT3D_IM_LOOP_END_C off_z += slice.nz; } assert(off_z == nz); im_free(&slice); return SIFT3D_SUCCESS; }
/* Helper function to read a DICOM file using C++ */ static int read_dcm_cpp(const char *path, Image *const im) { // Read the image metadata Dicom dicom(path); if (!dicom.isValid()) return SIFT3D_FAILURE; // Load the DicomImage object DicomImage dicomImage(path); if (dicomImage.getStatus() != EIS_Normal) { SIFT3D_ERR("read_dcm_cpp: failed to open image %s (%s)\n", path, DicomImage::getString(dicomImage.getStatus())); return SIFT3D_FAILURE; } // Initialize the image fields im->nx = dicom.getNx(); im->ny = dicom.getNy(); im->nz = dicom.getNz(); im->nc = dicom.getNc(); im->ux = dicom.getUx(); im->uy = dicom.getUy(); im->uz = dicom.getUz(); // Resize the output im_default_stride(im); if (im_resize(im)) return SIFT3D_FAILURE; // Get the bit depth of the image const int bufNBits = 32; const int depth = dicomImage.getDepth(); if (depth > bufNBits) { SIFT3D_ERR("read_dcm_cpp: buffer is insufficiently wide " "for %d-bit data of image %s \n", depth, path); return SIFT3D_FAILURE; } // Get the number of bits by which we need to shift the 32-bit data, to // recover the original resolution (DICOM uses Big-endian encoding) const uint32_t shift = isLittleEndian() ? static_cast<uint32_t>(bufNBits - depth) : 0; // Read each frame for (int i = 0; i < im->nz; i++) { // Get a pointer to the data, rendered as a 32-bit int const uint32_t *const frameData = static_cast<const uint32_t *const>( dicomImage.getOutputData( static_cast<int>(bufNBits), i)); if (frameData == NULL) { SIFT3D_ERR("read_dcm_cpp: could not get data from " "image %s frame %d (%s)\n", path, i, DicomImage::getString(dicomImage.getStatus())); return SIFT3D_FAILURE; } // Copy the frame const int x_start = 0; const int y_start = 0; const int z_start = i; const int x_end = im->nx - 1; const int y_end = im->ny - 1; const int z_end = z_start; int x, y, z; SIFT3D_IM_LOOP_LIMITED_START(im, x, y, z, x_start, x_end, y_start, y_end, z_start, z_end) // Get the voxel and shift it to match the original // magnitude const uint32_t vox = frameData[x + y * im->nx] >> shift; // Convert to float and write to the output image SIFT3D_IM_GET_VOX(im, x, y, z, 0) = static_cast<float>(vox); SIFT3D_IM_LOOP_END } return SIFT3D_SUCCESS; }