void Mosaic::execute () { const std::vector<File::Entry>& files (H.get_files()); if (files.empty()) throw Exception ("no files specified in header for image \"" + H.name() + "\""); assert (H.datatype().bits() > 1); segsize = H.dim (0) * H.dim (1) * H.dim (2); assert (segsize * files.size() == DataSet::voxel_count (H)); size_t bytes_per_segment = H.datatype().bytes() * segsize; if (files.size() * bytes_per_segment > std::numeric_limits<size_t>::max()) throw Exception ("image \"" + H.name() + "\" is larger than maximum accessible memory"); debug ("loading mosaic image \"" + H.name() + "\"..."); addresses.resize (1); addresses[0] = new uint8_t [files.size() * bytes_per_segment]; if (!addresses[0]) throw Exception ("failed to allocate memory for image \"" + H.name() + "\""); ProgressBar progress ("reformatting DICOM mosaic images...", slices*files.size()); uint8_t* data = addresses[0]; for (size_t n = 0; n < files.size(); n++) { File::MMap file (files[n], false, m_xdim * m_ydim * H.datatype().bytes()); size_t nx = 0, ny = 0; for (size_t z = 0; z < slices; z++) { size_t ox = nx*xdim; size_t oy = ny*ydim; for (size_t y = 0; y < ydim; y++) { memcpy (data, file.address() + H.datatype().bytes() * (ox + m_xdim* (y+oy)), xdim * H.datatype().bytes()); data += xdim * H.datatype().bytes(); } nx++; if (nx >= m_xdim / xdim) { nx = 0; ny++; } ++progress; } } segsize = std::numeric_limits<size_t>::max(); }
void Default::copy_to_mem (const Header& header) { DEBUG ("loading image \"" + header.name() + "\"..."); addresses.resize (files.size() > 1 && header.datatype().bits() *segsize != 8*size_t (bytes_per_segment) ? files.size() : 1); addresses[0].reset (new uint8_t [files.size() * bytes_per_segment]); if (!addresses[0]) throw Exception ("failed to allocate memory for image \"" + header.name() + "\""); if (is_new) memset (addresses[0].get(), 0, files.size() * bytes_per_segment); else { for (size_t n = 0; n < files.size(); n++) { File::MMap file (files[n], false, false, bytes_per_segment); memcpy (addresses[0].get() + n*bytes_per_segment, file.address(), bytes_per_segment); } } if (addresses.size() > 1) for (size_t n = 1; n < addresses.size(); n++) addresses[n].reset (addresses[0].get() + n*bytes_per_segment); else segsize = std::numeric_limits<size_t>::max(); }
void Mosaic::load () { if (files.empty()) throw Exception ("no files specified in header for image \"" + name + "\""); assert (datatype.bits() > 1); size_t bytes_per_segment = datatype.bytes() * segsize; if (files.size() * bytes_per_segment > std::numeric_limits<size_t>::max()) throw Exception ("image \"" + name + "\" is larger than maximum accessible memory"); DEBUG ("loading mosaic image \"" + name + "\"..."); addresses.resize (1); addresses[0].reset (new uint8_t [files.size() * bytes_per_segment]); if (!addresses[0]) throw Exception ("failed to allocate memory for image \"" + name + "\""); ProgressBar progress ("reformatting DICOM mosaic images...", slices*files.size()); uint8_t* data = addresses[0].get(); for (size_t n = 0; n < files.size(); n++) { File::MMap file (files[n], false, false, m_xdim * m_ydim * datatype.bytes()); size_t nx = 0, ny = 0; for (size_t z = 0; z < slices; z++) { size_t ox = nx*xdim; size_t oy = ny*ydim; for (size_t y = 0; y < ydim; y++) { memcpy (data, file.address() + datatype.bytes() * (ox + m_xdim* (y+oy)), xdim * datatype.bytes()); data += xdim * datatype.bytes(); } nx++; if (nx >= m_xdim / xdim) { nx = 0; ny++; } ++progress; } } segsize = std::numeric_limits<size_t>::max(); }
void dicom_to_mapper ( MR::Image::Mapper& dmap, MR::Image::Header& H, std::vector< RefPtr<Series> >& series_list) { assert (series_list.size() > 0); H.format = FormatDICOM; Patient* patient (series_list[0]->study->patient); String sbuf = ( patient->name.size() ? patient->name : "unnamed" ); sbuf += " " + format_ID (patient->ID); if (series_list[0]->modality.size()) sbuf += String (" [") + series_list[0]->modality + "]"; if (series_list[0]->name.size()) sbuf += String (" ") + series_list[0]->name; H.comments.push_back (sbuf); H.name = sbuf; // build up sorted list of frames: std::vector<Frame*> frames; // loop over series list: for (std::vector< RefPtr<Series> >::const_iterator series_it = series_list.begin(); series_it != series_list.end(); ++series_it) { Series& series (**series_it); try { series.read(); } catch (Exception) { throw Exception ("error reading series " + str (series.number) + " of DICOM image \"" + H.name + "\""); } std::sort (series.begin(), series.end()); // loop over images in each series: for (Series::const_iterator image_it = series.begin(); image_it != series.end(); ++image_it) { Image& image (**image_it); // if multi-frame, loop over frames in image: if (image.frames.size()) { std::sort (image.frames.begin(), image.frames.end()); for (std::vector< RefPtr<Frame> >::const_iterator frame_it = image.frames.begin(); frame_it != image.frames.end(); ++frame_it) frames.push_back (&**frame_it); } // otherwise add image frame: else frames.push_back (&image); } } std::vector<guint> dim = Frame::count (frames); if (dim[0] > 1) { // switch axes so slice dim is inner-most: std::vector<Frame*> list (frames); std::vector<Frame*>::iterator it = frames.begin(); for (guint k = 0; k < dim[2]; ++k) for (guint i = 0; i < dim[0]; ++i) for (guint j = 0; j < dim[1]; ++j) *(it++) = list[i+dim[0]*(j+dim[1]*k)]; } gfloat slice_separation = Frame::get_slice_separation (frames, dim[1]); if (series_list[0]->study->name.size()) { sbuf = "study: " + series_list[0]->study->name; H.comments.push_back (sbuf); } if (patient->DOB.size()) { sbuf = "DOB: " + format_date (patient->DOB); H.comments.push_back (sbuf); } if (series_list[0]->date.size()) { sbuf = "DOS: " + format_date (series_list[0]->date); if (series_list[0]->time.size()) sbuf += " " + format_time (series_list[0]->time); H.comments.push_back (sbuf); } MR::Image::Axes& axes (H.axes); const Image& image (*(*series_list[0])[0]); guint nchannels = image.frames.size() ? 1 : image.data_size / (image.dim[0] * image.dim[1] * (image.bits_alloc/8)); if (nchannels > 1) info ("data segment is larger than expected from image dimensions - interpreting as multi-channel data"); axes.set_ndim (3 + (dim[0]*dim[2]>1) + (nchannels>1)); guint current_axis = 3; guint current_stride = 0; add_axis ("channel", axes, current_axis, current_stride, nchannels); axes.axis[0] = current_stride++; axes.dim[0] = image.dim[0]; axes.vox[0] = image.pixel_size[0]; axes.desc[0] = MR::Image::Axis::left_to_right; axes.units[0] = MR::Image::Axis::millimeters; axes.axis[1] = current_stride++; axes.dim[1] = image.dim[1]; axes.vox[1] = image.pixel_size[1]; axes.desc[1] = MR::Image::Axis::posterior_to_anterior; axes.units[1] = MR::Image::Axis::millimeters; axes.axis[2] = current_stride++; axes.dim[2] = dim[1]; axes.vox[2] = slice_separation; axes.desc[2] = MR::Image::Axis::inferior_to_superior; axes.units[2] = MR::Image::Axis::millimeters; add_axis ("volume", axes, current_axis, current_stride, dim[0]*dim[2]); if (image.bits_alloc == 8) H.data_type = DataType::UInt8; else if (image.bits_alloc == 16) { H.data_type = DataType::UInt16; if (image.is_BE) H.data_type.set_flag (DataType::BigEndian); else H.data_type.set_flag (DataType::LittleEndian); } else throw Exception ("unexpected number of allocated bits per pixel (" + str (image.bits_alloc) + ") in file \"" + H.name + "\""); H.offset = image.scale_intercept; H.scale = image.scale_slope; Math::Matrix M(4,4); M(0,0) = -image.orientation_x[0]; M(1,0) = -image.orientation_x[1]; M(2,0) = image.orientation_x[2]; M(3,0) = 0.0; M(0,1) = -image.orientation_y[0]; M(1,1) = -image.orientation_y[1]; M(2,1) = image.orientation_y[2]; M(3,1) = 0.0; M(0,2) = -image.orientation_z[0]; M(1,2) = -image.orientation_z[1]; M(2,2) = image.orientation_z[2]; M(3,2) = 0.0; M(0,3) = -image.position_vector[0]; M(1,3) = -image.position_vector[1]; M(2,3) = image.position_vector[2]; M(3,3) = 1.0; H.set_transform (M); H.DW_scheme = Frame::get_DW_scheme (frames, dim[1], M); for (guint n = 1; n < frames.size(); ++n) // check consistency of data scaling: if (frames[n]->scale_intercept != frames[n-1]->scale_intercept || frames[n]->scale_slope != frames[n-1]->scale_slope) throw Exception ("unable to load series due to inconsistent data scaling between DICOM images"); if (image.frames.size()) { // need to preload and re-arrange: ProgressBar::init (frames.size(), "DICOM image contains multiple frames - reformating..."); guint8* mem = NULL; try { mem = new guint8 [H.memory_footprint()]; if (!mem) throw; } catch (...) { throw Exception ("failed to allocate memory for image data!"); } guint8* dest = mem; const guint row_stride = nchannels * frames[0]->row_stride * (frames[0]->bits_alloc/8); const guint row_size = nchannels * frames[0]->dim[0] * (frames[0]->bits_alloc/8); File::MMap mmap; for (guint n = 0; n < frames.size(); ++n) { mmap.init (frames[n]->filename); mmap.map(); const guint8* src = (guint8*) mmap.address() + frames[n]->data; for (guint row = 0; row < frames[n]->dim[1]; ++row) { memcpy (dest, src, row_size); dest += row_size; src += row_stride; } ProgressBar::inc(); } ProgressBar::done(); dmap.add (mem); } else { // use standard backend: for (guint n = 0; n < frames.size(); ++n) { const Image* image = static_cast<const Image*> (frames[n]); dmap.add (image->filename, image->data); } } }