def __next__(self):

        rotation_idx = self.current_rotation + 1
        shell_idx = self.current_shell

        if shell_idx <= self.shell_stop:
            shell = self.get_points_on_shell(self.current_shell * self.d_bin,
                                             (self.current_shell + 1) *
                                             self.d_bin)
            self.current_shell += 1

        elif rotation_idx <= self.rotation_stop:

            rotated_plane = itkutils.convert_from_itk_image(
                itkutils.rotate_image(self.plane,
                                      self.angles[rotation_idx],
                                      interpolation='linear'))

            self.rotated_plane = rotated_plane > 0
            self.current_shell = 0
            shell_idx = 0
            self.current_rotation += 1

            shell = self.get_points_on_shell(self.current_shell * self.d_bin,
                                             (self.current_shell + 1) *
                                             self.d_bin)

        else:
            raise StopIteration

        return np.where(shell *
                        self.rotated_plane), shell_idx, self.current_rotation
Example #2
0
def shift(data, transforms):
    """
    Resamples all the images in an ArrayDetectorData structure with the supplied transforms,
    and saves the result in a new ArrayDetectorData structure

    :param data: ArrayDetectorData object with images
    :param transforms: A list of transforms (Simple ITK), one for each image
    :return: ArrayDetectorDAta object with shifted images
    """

    assert isinstance(transforms, list) and len(transforms) == data.ndetectors

    shifted = ArrayDetectorData(data.ndetectors, data.ngates)
    reference = Image(np.zeros(data[0, 0].shape, dtype=np.float64),
                      data[0, 0].spacing)

    for gate in range(data.ngates):
        for i in range(data.ndetectors):
            image = itk.resample_image(
                itk.convert_to_itk_image(data[gate, i]),
                transforms[i],
                reference=itk.convert_to_itk_image(reference))

            shifted[gate, i] = itk.convert_from_itk_image(image)

    return shifted
Example #3
0
    def copy_registration_result(self, from_scale, to_scale):
        """
        With this function it is possible
        to migrate the registration results from one scale to another.

        With very large images it is sometimes easier and faster to perform
        image registration with downsampled versions of the original images.
        The accuracy of the registration result is often very good, even with
        60 percent downsampled images.

        Parameters
        ----------
        :item from_scale    The scale for which there is an existing
                            registration result.
        :item to_scale      The scale for which the new registration results
                            should be calculated.

        Returns
        -------

        """

        # Check that the registration result for the specified scale
        # exists.
        assert from_scale in self.get_scales("registered")
        print("Copying registration results from %i to %i percent scale" % (
              from_scale, to_scale))
        if to_scale not in self.get_scales("original"):
            self.create_rescaled_images("original", to_scale)

        for channel in range(self.channel_count):
            print("Resampling view 0")
            self.set_active_image(0, channel, to_scale, "original")
            self.add_registered_image(self.data[self.active_image][:], to_scale,
                                      0, channel, 0, self.get_voxel_size())
            self.set_active_image(0, channel, to_scale, "registered")
            reference = self.get_itk_image()

            for view in range(1, self.get_number_of_images("original")):
                print("Resampling view %i" % view)
                self.set_active_image(view, channel, from_scale, "registered")
                transform = self.get_transform()
                transform_params = self.get_transform_parameters()
                self.set_active_image(view, channel, to_scale, "original")
                image = self.get_itk_image()
                angle = self.get_rotation_angle(radians=False)
                spacing = self.get_voxel_size()
                result = itkutils.convert_from_itk_image(
                    itkutils.resample_image(image, transform, reference=reference)
                )[0]
                self.add_registered_image(result, to_scale, view, channel, angle,
                                          spacing)
                self.add_transform(to_scale, view, channel, transform_params[0], transform_params[1], transform_params[2])
    def __getitem__(self, limits):
        """
        Get a single conical section of a 3D shell.

        :param shell_start: The start of the shell (0 ... Nyquist)
        :param shell_stop:  The end of the shell
        :param angle:
        """
        (shell_start, shell_stop, angle) = limits
        rotated_plane = itkutils.convert_from_itk_image(
            itkutils.rotate_image(self.plane, angle))

        points_on_plane = rotated_plane > 0
        points_on_shell = self.get_points_on_shell(shell_start, shell_stop)

        return np.where(points_on_plane * points_on_shell)
Example #5
0
def __itk_image(filename, return_itk=True):
    """
    A function for reading image file types typical to ITK (mha & mhd). This is mostly
    of a historical significance, because in the original miplib 1 such files were
    used, mostly for convenience.

    :param filename:     Path to an ITK image
    :param return_itk    Toggle whether to convert the ITK image into Numpy format
    :return:             Image data as a Numpy array, voxel spacing tuple
    """
    assert filename.endswith((".mha", ".mhd"))
    image = sitk.ReadImage(filename)
    if return_itk:
        return image
    else:
        return itkutils.convert_from_itk_image(image)
Example #6
0
    def save_result(self):
        scale = self.options.scale
        channel = self.options.channel
        view = self.moving_index

        # Add registered image
        self.data.set_active_image(view, channel, scale, "original")
        angle = self.data.get_rotation_angle(radians=False)
        spacing = self.data.get_voxel_size()
        registered_image = ops_itk.convert_from_itk_image(
            self.get_resampled_result())
        self.data.add_registered_image(registered_image, scale, view, channel,
                                       angle, spacing)
        # Add transform
        transform = self.get_final_transform()
        tfm_params = ops_itk.get_itk_transform_parameters(transform)
        self.data.add_transform(scale, view, channel, tfm_params[1],
                                tfm_params[2], tfm_params[0])
Example #7
0
def shift_and_sum(data,
                  transforms,
                  photosensor=0,
                  detectors=None,
                  supersampling=1.0):
    """
    Adaptive ISM pixel reassignment. Please use one of the functions above to figure out
    the shifts first, if you haven't already.

    :param supersampling: Insert a number != 1, if you want to rescale the result image to
    a different size. This might make sense, if you the original sampling has been sampled
    sparsely
    :param data: ArrayDetectorData object with all the individual images
    :param transforms: ITK spatial transformation that are to be used for the resampling
    :param photosensor: The photosensor index, if more than one
    :param detectors: a list of detectors to be included in the reconstruction. If None given (default),
    all the images will be used
    :return: reconstruction result Image
    """
    assert isinstance(data, ArrayDetectorData)
    assert isinstance(transforms, list) and len(transforms) == data.ndetectors

    if supersampling != 1.0:
        new_shape = list(
            int(i * supersampling) for i in data[photosensor, 0].shape)
        new_spacing = list(i / supersampling
                           for i in data[photosensor, 0].spacing)
        output = Image(np.zeros(new_shape, dtype=np.float64), new_spacing)
    else:
        output = Image(np.zeros(data[photosensor, 0].shape, dtype=np.float64),
                       data[photosensor, 0].spacing)

    if detectors is None:
        detectors = list(range(data.ndetectors))

    for i in detectors:
        image = itk.resample_image(itk.convert_to_itk_image(data[photosensor,
                                                                 i]),
                                   transforms[i],
                                   reference=itk.convert_to_itk_image(output))

        output += itk.convert_from_itk_image(image)

    return output
Example #8
0
def main():
    options = miplib_entry_point_options.get_import_script_options(sys.argv[1:])
    directory = options.data_dir_path

    # Create a new HDF5 file. If a file exists, new data will be appended.
    file_name = input("Give a name for the HDF5 file: ")
    file_name += ".hdf5"
    data_path = os.path.join(directory, file_name)
    data = image_data.ImageData(data_path)

    # Add image files that have been named according to the correct format
    for image_name in os.listdir(directory):
        full_path = os.path.join(directory, image_name)

        if full_path.endswith((".tiff", ".tif", ".mhd", ".mha")):
            images = read.get_image(full_path)
            spacing = images.spacing
        else:
            continue

        if options.normalize_inputs:
            images = (images * (255.0/images.max())).astype(numpy.uint8)

        if not all(x in image_name for x in params_c) or not any(x in image_name for x in image_types_c):
            print("Unrecognized image name %s. Skipping it." % image_name)
            continue

        image_type = image_name.split("_scale")[0]
        scale = image_name.split("scale_")[-1].split("_index")[0]
        index = image_name.split("index_")[-1].split("_channel")[0]
        channel = image_name.split("channel_")[-1].split("_angle")[0]
        angle = image_name.split("angle_")[-1].split(".")[0]

        assert all(x.isdigit() for x in (scale, index, channel, angle))
        # data, angle, spacing, index, scale, channel, chunk_size=None

        if image_type == "original":
            data.add_original_image(images, scale, index, channel, angle, spacing)
        elif image_type == "registered":
            data.add_registered_image(images, scale, index, channel, angle, spacing)
        elif image_type == "psf":
            data.add_psf(images, scale, index, channel, angle, spacing)

    # Calculate resampled images
    if options.scales is not None:
        for scale in options.scales:
            print("Creating %s percent downsampled versions of the original images" % scale)
            data.create_rescaled_images("original", scale)

    # Add transforms for registered images.
    for transform_name in os.listdir(directory):
        if not transform_name.endswith(".txt"):
            continue

        if not all(x in transform_name for x in params_c) or not "transform" in transform_name:
            print("Unrecognized transform name %s. Skipping it." % transform_name)
            continue

        scale = transform_name.split("scale_")[-1].split("_index")[0]
        index = transform_name.split("index_")[-1].split("_channel")[0]
        channel = transform_name.split("channel_")[-1].split("_angle")[0]
        angle = transform_name.split("angle_")[-1].split(".")[0]

        full_path = os.path.join(directory, transform_name)

        # First calculate registered image if not in the data structure
        if not data.check_if_exists("registered", index, channel, scale):
            print("Resampling registered image for image nr. ", index)
            data.set_active_image(0, channel, scale, "original")
            reference = data.get_itk_image()
            data.set_active_image(index, channel, scale, "original")
            moving = data.get_itk_image()

            transform = read.__itk_transform(full_path, return_itk=True)

            registered = itkutils.resample_image(moving, transform, reference=reference)
            registered = itkutils.convert_from_itk_image(registered)
            spacing = registered.spacing

            data.add_registered_image(registered, scale, index, channel, angle, spacing)

        # The add it's transform
        transform_type, params, fixed_params = read.__itk_transform(full_path)
        data.add_transform(scale, index, channel, params, fixed_params, transform_type)

    # Calculate missing PSFs
    if options.calculate_psfs:
        data.calculate_missing_psfs()

    if options.copy_registration_result != -1:
        from_scale = options.copy_registration_result[0]
        to_scale = options.copy_registration_result[1]
        data.copy_registration_result(from_scale, to_scale)

    data.close()