Exemple #1
0
def test_radon_dtype():
    img = convert_to_float(PHANTOM, False)
    img32 = img.astype(np.float32)

    assert radon(img).dtype == img.dtype
    assert radon(img32).dtype == img32.dtype
def radon(image, theta=None):
    """
    Calculates the radon transform of an image given specified
    projection angles.
    Parameters
    ----------
    image : array_like
        Input image. The rotation axis will be located in the pixel with
        indices ``(image.shape[0] // 2, image.shape[1] // 2)``.
    theta : array_like, optional
        Projection angles (in degrees). If `None`, the value is set to
        np.arange(180).
    circle : boolean, optional
        Assume image is zero outside the inscribed circle, making the
        width of each projection (the first dimension of the sinogram)
        equal to ``min(image.shape)``.
    preserve_range : bool, optional
        Whether to keep the original range of values. Otherwise, the input
        image is converted according to the conventions of `img_as_float`.
        Also see https://scikit-image.org/docs/dev/user_guide/data_types.html
    Returns
    -------
    radon_image : ndarray
        Radon transform (sinogram).  The tomography rotation axis will lie
        at the pixel index ``radon_image.shape[0] // 2`` along the 0th
        dimension of ``radon_image``.
    References
    ----------
    .. [1] AC Kak, M Slaney, "Principles of Computerized Tomographic
           Imaging", IEEE Press 1988.
    .. [2] B.R. Ramesh, N. Srinivasa, K. Rajgopal, "An Algorithm for Computing
           the Discrete Radon Transform With Some Applications", Proceedings of
           the Fourth IEEE Region 10 International Conference, TENCON '89, 1989
    Notes
    -----
    Based on code of Justin K. Romberg
    (https://www.clear.rice.edu/elec431/projects96/DSP/bpanalysis.html)
    """
    
    image = convert_to_float(image, None)
    theta = np.linspace(0., 180., max(image.shape), endpoint=False)

    with tf.compat.v1.Session() as sess:
        diagonal = tf.sqrt(2.0) * max(image.shape)
        pad = [tf.dtypes.cast(tf.math.ceil(diagonal - s), tf.int32) for s in image.shape]
        new_center = [(s + p) // 2 for s, p in zip(image.shape, pad)]
        old_center = [s // 2 for s in image.shape]
        pad_before = [nc - oc for oc, nc in zip(old_center, new_center)]
        pad_width = [(pb, p - pb) for pb, p in zip(pad_before, pad)]
        padded_image = tf.pad(image, pad_width, mode='constant', constant_values=0)

        # padded_image is always square
        if padded_image.shape[0] != padded_image.shape[1]:
            raise ValueError('padded_image must be a square')

        center = padded_image.shape[0] // 2

        radon_image = np.zeros((padded_image.shape[0], len(theta)))

        # convert degree to radian

        for i, angle in enumerate(np.deg2rad(theta)):
            cos_a, sin_a = tf.math.cos(angle), tf.math.sin(angle)

            R = tf.Variable(list([[cos_a, sin_a, -center * (cos_a + sin_a - 1)],
                          [-sin_a, cos_a, -center * (cos_a - sin_a - 1)],
                          [0, 0, 1]]))

            init_op = tf.compat.v1.global_variables_initializer()

            sess.run(init_op)

            rotated = wp.warp(padded_image.eval(), R.eval(), clip=False)

            # update transformed image
            radon_image[:, i] = rotated.sum(0)

    return radon_image