def get_angle_sector(self, phi_min, phi_max):
        """
        Assuming a classical spherical coordinate system the azimutahl
        angle is the angle between the x- and y- axes. Use this to extract
        a conical section from a sphere that is defined by start and stop azimuth
        angles.

        In the hollow implementation a small slice in the center of the section is
        removed to avoid the effect of resampling when calculating the resolution
        along the lowest resolution axis (z), on images with very isotropic resolution
        (e.g. STED).

        :param phi_min: the angle at which to start the section, in radians
        :param phi_max: the angle at which to stop the section, in radians
        :return:

        """
        # Calculate angular sector
        arr_inf = self.phi >= phi_min
        arr_sup = self.phi < phi_max

        arr_inf_neg = self.phi >= phi_min + np.pi
        arr_sup_neg = self.phi < phi_max + np.pi

        full_section = arr_inf * arr_sup + arr_inf_neg * arr_sup_neg

        axis_pos = converters.degrees_to_radians(90) + self.d_angle / 2
        axis_neg = converters.degrees_to_radians(270) + self.d_angle / 2

        if phi_min <= axis_pos <= phi_max:
            phi_min_ext = axis_pos - self.d_extract_angle
            phi_max_ext = axis_pos + self.d_extract_angle

        elif phi_min <= axis_neg <= phi_max:

            # Calculate part of the section to exclude
            phi_min_ext = axis_neg - self.d_extract_angle
            phi_max_ext = axis_neg + self.d_extract_angle

        else:
            return full_section

        arr_inf_ext = self.phi >= phi_min_ext
        arr_sup_ext = self.phi < phi_max_ext

        arr_inf_neg_ext = self.phi >= phi_min_ext + np.pi
        arr_sup_neg_ext = self.phi < phi_max_ext + np.pi

        extract_section = arr_inf_ext * arr_sup_ext + arr_inf_neg_ext * arr_sup_neg_ext

        return full_section - extract_section
Beispiel #2
0
def rotate_image(image, angle, axis=0, interpolation="linear"):
    """
    Rotate an image around the selected axis

    :param interpolation:
    :param image: a SimpleITK image
    :param angle: rotation angle in degrees
    :param axis:  rotation axis
    :return:
    """

    assert isinstance(image, sitk.Image)

    radians = converters.degrees_to_radians(angle)

    if image.GetDimension() == 3:
        transform = sitk.Euler3DTransform()
        rotation = [0.0, 0.0, 0.0]
        rotation[axis] = radians
        transform.SetRotation(*rotation)
    elif image.GetDimension() == 2:
        transform = sitk.Euler2DTransform()
        transform.SetAngle(radians)
    else:
        raise ValueError(image)

    transform.SetCenter(calculate_center_of_image(image))

    return resample_image(image, transform, interpolation=interpolation)
Beispiel #3
0
def fsc_polar_plot(ax, data):
    """ Generate a polar plot from SFSC data. This is mainly used to overlay several plots
    with ...

   :param ax: pyplot ax instance that is to be used for the plotting
   :param data: FourierCorrelationDataCollection instance that includes the data to plot.
   :return: returns the same ax instance for further modifications
   """

    angles = list()
    radii = list()

    for dataset in data:
        angles.append(degrees_to_radians(float(dataset[0])))
        radii.append(dataset[1].resolution["resolution"])

    angles, radii = zip(*sorted(zip(angles, radii)))
    angles = list(angles)
    radii = list(radii)
    angles.append(angles[0])
    radii.append(radii[0])

    ax.plot(angles, radii)

    ax.set_rlabel_position(-80)  # get radial labels away from plotted line

    return ax
    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_min:   The start of the cone (degrees 0-360)
        :param angle_max:   The end of the cone
        :return:            Returns the coordinates of the points that are located inside
                            the portion of a shell that intersects with the points on the
                            cone.
        """
        (shell_start, shell_stop, angle_min, angle_max) = limits
        angle_min = converters.degrees_to_radians(angle_min)
        angle_max = converters.degrees_to_radians(angle_max)

        shell = self.get_points_on_shell(shell_start, shell_stop)
        cone = self.get_angle_sector(angle_min, angle_max)

        return np.where(shell * cone)
Beispiel #5
0
    def plot_polar_to_file(self, filename, size=(2, 2)):
        """
        Show the resolution as a 2D polar plot in which the resolution values are plotted
        as a function of rotatino angle.
        """

        angles = list()
        radii = list()

        for dataset in self.data:
            angles.append(degrees_to_radians(float(dataset[0])))
            radii.append(dataset[1].resolution["resolution"])

        angles, radii = list(zip(*sorted(zip(angles, radii))))
        angles = list(angles)
        radii = list(radii)
        angles.append(angles[0])
        radii.append(radii[0])

        radii_norm = list(i / max(radii) for i in radii)
        plt.figure(figsize=size)
        ax = plt.subplot(111, projection="polar")
        ax.plot(angles, radii_norm, color='#61a2da')
        ax.set_rmax(1.2)
        r_ticks = np.linspace(0.1, 1.0, 5)
        r_ticks_scale = r_ticks * max(radii)

        print(r_ticks_scale)
        print(max(radii))

        x_labels = ['%.2f' % n for n in r_ticks_scale]

        print(x_labels)
        ax.set_rticks(r_ticks)
        ax.set_yticklabels(x_labels)
        ax.set_rlabel_position(-80)  # get radial labels away from plotted line
        # ax.grid(True)

        # ax.set_title("The image resolution as a function of rotation angle")

        # ax.set_xlabel("XY")
        # ax.set_ylabel("Z")

        file_name = os.path.join(self.path, "{}.eps".format(filename))

        plt.savefig(file_name,
                    dpi=1200,
                    bbox_inches='tight',
                    pad_inches=0,
                    transparent=True)
Beispiel #6
0
    def plot_polar(self):
        """
        Show the resolution as a 2D polar plot in which the resolution values are plotted
        as a function of rotatino angle.
        """

        angles = list()
        radii = list()

        for dataset in self.data:
            angles.append(degrees_to_radians(float(dataset[0])))
            radii.append(dataset[1].resolution["resolution"])

        angles, radii = list(zip(*sorted(zip(angles, radii))))
        angles = list(angles)
        radii = list(radii)
        angles.append(angles[0])
        radii.append(radii[0])

        radii_norm = list(i / max(radii) for i in radii)
        fig = plt.figure(figsize=(4, 4))
        ax = plt.subplot(111, projection="polar")
        ax.plot(angles, radii_norm, color='#61a2da')
        ax.set_rmax(1.2)
        r_ticks = np.linspace(0.1, 1.0, 5)
        r_ticks_scale = r_ticks * max(radii)

        x_labels = ['%.2f' % n for n in r_ticks_scale]

        ax.set_rticks(r_ticks)
        ax.set_yticklabels(x_labels)
        ax.set_rlabel_position(-80)  # get radial labels away from plotted line
        # ax.grid(True)

        # ax.set_title("The image resolution as a function of rotation angle")

        # ax.set_xlabel("XY")
        # ax.set_ylabel("Z")

        return ax
Beispiel #7
0
    def __init__(self, shape, d_bin, d_angle):
        """
        :param shape: Shape of the data
        :param d_bin: The radius increment size (pixels)
        :param d_angle: The angle increment size (degrees)
        """

        FourierRingIterator.__init__(self, shape, d_bin)

        self.d_angle = converters.degrees_to_radians(d_angle)

        y, x = self.meshgrid

        # Create inclination and azimuth angle arrays
        self.phi = np.arctan2(y, x) + np.pi

        self.phi += self.d_angle / 2
        self.phi[self.phi >= 2 * np.pi] -= 2 * np.pi

        self._angle = 0

        self.angle_sector = self.get_angle_sector(0, d_bin)
Beispiel #8
0
    def draw_contour_3d(data, image, spacing):
        angles = list()
        radii = list()

        for dataset in data:
            angles.append(degrees_to_radians(float(dataset[0])))
            radii.append(image.shape[0] *
                         (spacing / dataset[1].resolution["resolution"]))

        angles, radii = zip(*sorted(zip(angles, radii)))
        angles = list(angles)
        radii = list(radii)
        angles.append(angles[0])
        radii.append(radii[0])

        center = list(i / 2 for i in image.shape)
        xs = list(radius * np.cos(angle) + center[1]
                  for radius, angle in zip(radii, angles))
        ys = list(radius * np.sin(angle) + center[0]
                  for radius, angle in zip(radii, angles))
        image[draw.polygon_perimeter(ys, xs)] = 255

        return image
    def __init__(self, shape, d_bin, d_angle):
        """
        :param shape: Shape of the data
        :param d_bin: The radius increment size (pixels)
        :param d_angle: The angle increment size (degrees)
        """

        FourierShellIterator.__init__(self, shape, d_bin)

        self.d_angle = converters.degrees_to_radians(d_angle)

        z, y, x = self.meshgrid

        # Create inclination and azimuth angle arrays
        self.phi = np.arctan2(y, z) + np.pi

        self.phi += self.d_angle / 2
        self.phi[self.phi >= 2 * np.pi] -= 2 * np.pi

        self.rotation_start = 0
        self.rotation_stop = 360 / d_angle - 1
        self.current_rotation = self.rotation_start

        self.angles = np.arange(0, 360, d_angle, dtype=int)
    def __init__(self, shape, d_bin, d_angle, d_extract_angle=5):

        ConicalFourierShellIterator.__init__(self, shape, d_bin, d_angle)

        self.d_extract_angle = converters.degrees_to_radians(d_extract_angle)
Beispiel #11
0
 def angle(self, value):
     angle = converters.degrees_to_radians(value)
     self._angle = angle
     self.angle_sector = self.get_angle_sector(angle, angle + self.d_angle)
Beispiel #12
0
    def execute(self, z_correction=1):
        """
        Calculate the spatial resolution as a cross-section of the FRC and Two-sigma curves.

        :return: Returns the calculation results. They are also saved inside the class.
                 The return value is just for convenience.
        """

        criterion = self.args.resolution_threshold_criterion
        threshold = self.args.resolution_threshold_value
        snr = self.args.resolution_snr_value
        tolerance = self.args.resolution_point_sigma
        degree = self.args.frc_curve_fit_degree
        fit_type = self.args.frc_curve_fit_type
        verbose = self.args.verbose

        def pdiff1(x):
            return abs(frc_eq(x) - two_sigma_eq(x))

        def pdiff2(x):
            return abs(frc_eq(x) - threshold)

        def first_guess(x, y, threshold):
            #y_smooth = savgol_filter(y, 5, 2)
            #return x[np.argmin(np.abs(y_smooth - threshold))]

            difference = y - threshold

            return x[np.where(difference <= 0)[0][0] - 1]
            #return x[np.argmin(np.abs(y - threshold))]

        for key, data_set in self.data_collection:

            if verbose:
                print(
                    "Calculating resolution point for dataset {}".format(key))
            frc_eq = fit_frc_curve(data_set, degree, fit_type)
            two_sigma_eq = calculate_resolution_threshold_curve(
                data_set, criterion, threshold, snr)
            """
            Todo: Make the first quess adaptive. For example find the data point at which FRC
            value is closest to the mean of the threshold
            """

            # Find intersection
            fit_start = first_guess(data_set.correlation["frequency"],
                                    data_set.correlation["correlation"],
                                    np.mean(data_set.resolution["threshold"]))
            if self.args.verbose:
                print("Fit starts at {}".format(fit_start))
                disp = 1
            else:
                disp = 0
            root = optimize.fmin(pdiff2 if criterion == 'fixed' else pdiff1,
                                 fit_start,
                                 disp=disp)[0]
            data_set.resolution["resolution-point"] = (frc_eq(root), root)
            data_set.resolution["criterion"] = criterion

            angle = converters.degrees_to_radians(int(key))
            z_correction_multiplier = (
                1 + (z_correction - 1) * np.abs(np.sin(angle)))
            resolution = z_correction_multiplier * (2 * self.spacing / root)

            data_set.resolution["resolution"] = resolution
            data_set.resolution[
                "spacing"] = self.spacing * z_correction_multiplier

            self.data_collection[int(key)] = data_set

            # # # Find intersection
            # root, result = optimize.brentq(
            #     pdiff2 if criterion == 'fixed' else pdiff1,
            #     0.0, 1.0, xtol=tolerance, full_output=True)
            #
            # # Save result, if intersection was found
            # if result.converged is True:
            #     data_set.resolution["resolution-point"] = (frc_eq(root), root)
            #     data_set.resolution["criterion"] = criterion
            #     resolution = 2 * self.spacing / root
            #     data_set.resolution["resolution"] = resolution
            #     self.data_collection[int(key)] = data_set
            # else:
            #     print "Could not find an intersection for the curves for the dataset %s." % key

        return self.data_collection