def _multiframe_to_block(multiframe_dicom): """ Generate a full datablock containing all stacks """ # Calculate the amount of stacks and slices in the stack number_of_stack_slices = int(common.get_ss_value(multiframe_dicom[Tag(0x2001, 0x105f)][0][Tag(0x2001, 0x102d)])) number_of_stacks = int(int(multiframe_dicom.NumberOfFrames) / number_of_stack_slices) # We create a numpy array size_x = multiframe_dicom.pixel_array.shape[2] size_y = multiframe_dicom.pixel_array.shape[1] size_z = number_of_stack_slices size_t = number_of_stacks # get the format format_string = common.get_numpy_type(multiframe_dicom) # get header info needed for ordering frame_info = multiframe_dicom[0x5200, 0x9230] data_4d = numpy.zeros((size_z, size_y, size_x, size_t), dtype=format_string) # loop over each slice and insert in datablock t_location_index = _get_t_position_index(multiframe_dicom) for slice_index in range(0, size_t * size_z): z_location = frame_info[slice_index].FrameContentSequence[0].InStackPositionNumber - 1 if t_location_index is None: t_location = frame_info[slice_index].FrameContentSequence[0].TemporalPositionIndex - 1 else: t_location = frame_info[slice_index].FrameContentSequence[0].DimensionIndexValues[t_location_index] - 1 block_data = multiframe_dicom.pixel_array[slice_index, :, :] # apply scaling rescale_intercept = frame_info[slice_index].PixelValueTransformationSequence[0].RescaleIntercept rescale_slope = frame_info[slice_index].PixelValueTransformationSequence[0].RescaleSlope block_data = common.do_scaling(block_data, rescale_slope, rescale_intercept) # switch to float if needed if block_data.dtype != data_4d.dtype: data_4d = data_4d.astype(block_data.dtype) data_4d[z_location, :, :, t_location] = block_data full_block = numpy.zeros((size_x, size_y, size_z, size_t), dtype=data_4d.dtype) # loop over each stack and reorganize the data for t_index in range(0, size_t): # transpose the block so the directions are correct data_3d = numpy.transpose(data_4d[:, :, :, t_index], (2, 1, 0)) # add the block the the full data full_block[:, :, :, t_index] = data_3d return full_block
def _mosaic_to_block(mosaic): """ Convert a mosaic slice to a block of data by reading the headers, splitting the mosaic and appending """ # get the mosaic type mosaic_type = _get_mosaic_type(mosaic) # get the size of one tile format is 64p*64 or 80*80 or something similar matches = re.findall(r'(\d+)\D+(\d+)\D*', str(mosaic[Tag(0x0051, 0x100b)].value))[0] ascconv_headers = _get_asconv_headers(mosaic) size = [int(matches[0]), int(matches[1]), int(re.findall(r'sSliceArray\.lSize\s*=\s*(\d+)', ascconv_headers)[0])] # get the number of rows and columns number_x = int(mosaic.Rows / size[0]) number_y = int(mosaic.Columns / size[1]) # get the format format_string = common.get_numpy_type(mosaic) # reshape the 1d array to 3d data_1d = numpy.fromstring(mosaic.PixelData, dtype=format_string) # recreate 2d slice data_2d = numpy.reshape(data_1d, (size[1] * number_y, size[0] * number_x)) # create 3d block data_3d = numpy.zeros((size[2], size[1], size[0]), dtype=format_string) # fill 3d block by taking the correct portions of the slice z_index = 0 for y_index in range(0, number_y): if z_index >= size[2]: break for x_index in range(0, number_x): if mosaic_type == MosaicType.ASCENDING: data_3d[z_index, :, :] = data_2d[size[1] * y_index:size[1] * (y_index + 1), size[0] * x_index:size[0] * (x_index + 1)] else: data_3d[size[2] - (z_index + 1), :, :] = data_2d[size[1] * y_index:size[1] * (y_index + 1), size[0] * x_index:size[0] * (x_index + 1)] z_index += 1 if z_index >= size[2]: break # reorient the block of data data_3d = numpy.transpose(data_3d, (2, 1, 0)) return data_3d
def shrink_multiframe(input_file, output_file=None, slice_count=8, timepoint_count=4): if output_file is None: output_file = input_file # Load dicom_file_in dicom_in = compressed_dicom.read_file(input_file) if _is_multiframe_diffusion_imaging([dicom_in]) or _is_multiframe_4d([dicom_in]): number_of_stack_slices = int(common.get_ss_value(dicom_in[(0x2001, 0x105f)][0][(0x2001, 0x102d)])) number_of_stacks = int(int(dicom_in.NumberOfFrames) / number_of_stack_slices) # We create a numpy array size_x = dicom_in.pixel_array.shape[2] size_y = dicom_in.pixel_array.shape[1] size_t = number_of_stacks frame_info = dicom_in.PerFrameFunctionalGroupsSequence data_4d = numpy.zeros((slice_count * timepoint_count, size_x, size_y), dtype=common.get_numpy_type(dicom_in)) new_frame_info = [None] * slice_count * timepoint_count for index_z in range(0, slice_count): for index_t in range(0, timepoint_count): slice_index = int(size_t * index_z + index_t) new_slice_index = int(timepoint_count * index_z + index_t) z_location = frame_info[slice_index].FrameContentSequence[0].InStackPositionNumber - 1 new_frame_info[new_slice_index] = frame_info[slice_index] logging.info('Importing slice on position %s %s %s' % (slice_index, z_location, index_t)) data_4d[new_slice_index, :, :] = dicom_in.pixel_array[slice_index, :, :] dicom_in.PixelData = data_4d.tostring() common.set_ss_value(dicom_in[(0x2001, 0x105f)][0][(0x2001, 0x102d)], slice_count) setattr(dicom_in, 'NumberOfFrames', slice_count * timepoint_count) setattr(dicom_in, 'PerFrameFunctionalGroupsSequence', new_frame_info) else: # truncate the data dicom_in.PixelData = dicom_in.pixel_array[:slice_count, :, :].tostring() # set number of frames common.set_ss_value(dicom_in[(0x2001, 0x105f)][0][(0x2001, 0x102d)], slice_count) setattr(dicom_in, 'NumberOfFrames', slice_count) # truncate the pre frame groups sequence setattr(dicom_in, 'PerFrameFunctionalGroupsSequence', dicom_in.PerFrameFunctionalGroupsSequence[:slice_count]) # Save the file dicom_in.save_as(output_file)
def shrink_multiframe(input_file, output_file=None, slice_count=8, timepoint_count=4): if output_file is None: output_file = input_file # Load dicom_file_in dicom_in = compressed_dicom.read_file(input_file) if _is_multiframe_diffusion_imaging([dicom_in]) or _is_multiframe_4d( [dicom_in]): number_of_stack_slices = int( common.get_ss_value(dicom_in[(0x2001, 0x105f)][0][(0x2001, 0x102d)])) number_of_stacks = int( int(dicom_in.NumberOfFrames) / number_of_stack_slices) # We create a numpy array size_x = dicom_in.pixel_array.shape[2] size_y = dicom_in.pixel_array.shape[1] size_t = number_of_stacks frame_info = dicom_in.PerFrameFunctionalGroupsSequence data_4d = numpy.zeros((slice_count * timepoint_count, size_x, size_y), dtype=common.get_numpy_type(dicom_in)) new_frame_info = [None] * slice_count * timepoint_count for index_z in range(0, slice_count): for index_t in range(0, timepoint_count): slice_index = int(size_t * index_z + index_t) new_slice_index = int(timepoint_count * index_z + index_t) z_location = frame_info[slice_index].FrameContentSequence[ 0].InStackPositionNumber - 1 new_frame_info[new_slice_index] = frame_info[slice_index] logging.info('Importing slice on position %s %s %s' % (slice_index, z_location, index_t)) data_4d[new_slice_index, :, :] = dicom_in.pixel_array[ slice_index, :, :] dicom_in.PixelData = data_4d.tostring() common.set_ss_value(dicom_in[(0x2001, 0x105f)][0][(0x2001, 0x102d)], slice_count) setattr(dicom_in, 'NumberOfFrames', slice_count * timepoint_count) setattr(dicom_in, 'PerFrameFunctionalGroupsSequence', new_frame_info) else: # truncate the data dicom_in.PixelData = dicom_in.pixel_array[:slice_count, :, :].tostring( ) # set number of frames common.set_ss_value(dicom_in[(0x2001, 0x105f)][0][(0x2001, 0x102d)], slice_count) setattr(dicom_in, 'NumberOfFrames', slice_count) # truncate the pre frame groups sequence setattr(dicom_in, 'PerFrameFunctionalGroupsSequence', dicom_in.PerFrameFunctionalGroupsSequence[:slice_count]) # Save the file dicom_in.save_as(output_file)