def test_add_noise_filter_with_mock_data_mag_image_reference_same_domain(
    image_container, ):
    """ Test the add noise filter with an image and reference image, both in the same domain """
    np.random.seed(RANDOM_SEED)
    # calculate manually
    image_with_noise = add_noise_function(image_container.image, SNR_VALUE,
                                          image_container.image)
    # calculate using the filter
    add_noise_filter = AddNoiseFilter()
    add_noise_filter.add_input("image", image_container)
    add_noise_filter.add_input("snr", SNR_VALUE)
    add_noise_filter.add_input("reference_image", image_container)
    np.random.seed(RANDOM_SEED)  # set seed so RNG is in the same state
    add_noise_filter.run()

    image_with_noise_container = add_noise_filter.outputs["image"].clone()

    # image_with_noise and image_with_noise_container.image should be equal
    numpy.testing.assert_array_equal(image_with_noise,
                                     image_with_noise_container.image)

    # Run again and then check the SNR
    add_noise_filter = AddNoiseFilter()
    add_noise_filter.add_input("image", image_container)
    add_noise_filter.add_input("snr", SNR_VALUE)
    add_noise_filter.add_input("reference_image", image_container)
    add_noise_filter.run()

    measured_snr = calculate_snr_function(
        image_with_noise_container.image,
        add_noise_filter.outputs["image"].image,
    )
    print(f"calculated snr = {measured_snr}, desired snr = {SNR_VALUE}")
    # This should be almost equal to the desired snr
    numpy.testing.assert_array_almost_equal(measured_snr, SNR_VALUE, 0)
def test_add_noise_filter_with_mock_data_complex_image_spatial_reference_inverse(
    complex_image_container,
    ft_complex_image_container,
):
    """Test the add noise filter with a complex image SPATIAL_DOMAIN,
    complex reference in the INVERSE_DOMAIN
    """
    np.random.seed(RANDOM_SEED)
    # calculate manually
    image_with_noise = add_noise_function(
        complex_image_container.image,
        SNR_VALUE,
        ft_complex_image_container.image,
        1.0 / np.sqrt(ft_complex_image_container.image.size),
    )
    image_with_noise_2 = add_noise_function(
        complex_image_container.image,
        SNR_VALUE,
        ft_complex_image_container.image,
        1.0 / np.sqrt(ft_complex_image_container.image.size),
    )
    print(
        f"manual snr = {calculate_snr_function(image_with_noise,image_with_noise_2)}"
    )

    # calculate using the filter
    add_noise_filter = AddNoiseFilter()
    add_noise_filter.add_input("image", complex_image_container)
    add_noise_filter.add_input("snr", SNR_VALUE)
    add_noise_filter.add_input("reference_image", ft_complex_image_container)
    np.random.seed(RANDOM_SEED)  # set seed so RNG is in the same state
    add_noise_filter.run()

    image_with_noise_container = add_noise_filter.outputs["image"].clone()

    # image_with_noise and image_with_noise_container.image should be equal
    numpy.testing.assert_array_equal(image_with_noise,
                                     image_with_noise_container.image)

    # Run again and then check the SNR
    add_noise_filter = AddNoiseFilter()
    add_noise_filter.add_input("image", complex_image_container)
    add_noise_filter.add_input("snr", SNR_VALUE)
    add_noise_filter.add_input("reference_image", ft_complex_image_container)
    add_noise_filter.run()

    measured_snr = calculate_snr_function(
        image_with_noise_container.image,
        add_noise_filter.outputs["image"].image,
    )
    print(f"calculated snr = {measured_snr}, desired snr = {SNR_VALUE}")
    # This isn't equal to the desired SNR
    with numpy.testing.assert_raises(AssertionError):
        numpy.testing.assert_array_almost_equal(measured_snr, SNR_VALUE, 0)
def test_add_noise_filter_snr_zero(image_container):
    """ Checks that the output image is equal to the input image when snr=0 """
    # calculate using the filter
    add_noise_filter = AddNoiseFilter()
    add_noise_filter.add_input("image", image_container)
    add_noise_filter.add_input("snr", 0.0)
    np.random.seed(RANDOM_SEED)  # set seed so RNG is in the same state
    add_noise_filter.run()

    # image_with_noise and image_with_noise_container.image should be equal
    numpy.testing.assert_array_equal(image_container.image,
                                     add_noise_filter.outputs["image"].image)
    def _create_filter_block(self):
        """Fourier transforms the input and reference images, calculates
        the noise amplitude, adds this to the FT of the input image, then
        inverse fourier transforms to obtain the output image"""

        input_image: BaseImageContainer = self.inputs[self.KEY_IMAGE]

        # if self.inputs["snr"] == 0  then the input image should just be
        # passed through to the output.
        # Because this is a filter block it needs to be done by another filter - fortunately
        # the AddNoiseFilter does just this when AddNoiseFilter.inputs["snr"] = 0
        if self.inputs[self.KEY_SNR] == 0:

            add_noise_filter = AddNoiseFilter()
            add_noise_filter.add_input(self.KEY_IMAGE, input_image)
            add_noise_filter.add_input(self.KEY_SNR, self.inputs[self.KEY_SNR])
            return add_noise_filter
        # snr is greater than 0 so run the filter block normally
        # Fourier transform the input image
        image_fft_filter = FftFilter()
        image_fft_filter.add_input(self.KEY_IMAGE, input_image)

        # Create the noise filter
        add_noise_filter = AddNoiseFilter()
        add_noise_filter.add_parent_filter(image_fft_filter)
        add_noise_filter.add_input(self.KEY_SNR, self.inputs[self.KEY_SNR])

        # If present load the reference image, if not, copy the input_image
        if self.KEY_REF_IMAGE in self.inputs:
            add_noise_filter.add_input(
                self.KEY_REF_IMAGE, self.inputs[self.KEY_REF_IMAGE]
            )
        else:
            add_noise_filter.add_input(self.KEY_REF_IMAGE, self.inputs[self.KEY_IMAGE])

        # Inverse Fourier Transform and set the output
        ifft_filter = IfftFilter()
        ifft_filter.add_parent_filter(add_noise_filter)
        return ifft_filter
def test_add_noise_filter_validate_inputs():
    """Check a FilterInputValidationError is raised when the inputs
    to the add commplex noise filter are incorrect or missing"""
    noise_filter = AddNoiseFilter()
    noise_filter.add_input("snr", 1)
    with pytest.raises(FilterInputValidationError):
        noise_filter.run()  # image not defined
    noise_filter.add_input("image", 1)
    with pytest.raises(FilterInputValidationError):
        noise_filter.run()  # image wrong type

    noise_filter = AddNoiseFilter()
    noise_filter.add_input("image",
                           NumpyImageContainer(image=np.zeros((32, 32, 32))))
    with pytest.raises(FilterInputValidationError):
        noise_filter.run()  # snr not defined
    noise_filter.add_input("snr", "str")
    with pytest.raises(FilterInputValidationError):
        noise_filter.run()  # snr wrong type

    noise_filter = AddNoiseFilter()
    noise_filter.add_input("image",
                           NumpyImageContainer(image=np.zeros((32, 32, 32))))
    noise_filter.add_input("snr", 1)
    noise_filter.add_input("reference_image", 1)
    with pytest.raises(FilterInputValidationError):
        noise_filter.run()  # reference_image wrong type

    noise_filter = AddNoiseFilter()
    noise_filter.add_input("image",
                           NumpyImageContainer(image=np.zeros((32, 32, 32))))
    noise_filter.add_input("snr", 1)
    noise_filter.add_input("reference_image",
                           NumpyImageContainer(image=np.zeros((32, 32, 31))))
    with pytest.raises(FilterInputValidationError):
        noise_filter.run()  # reference_image wrong shape