fix(v5): average noisy copies from clean source
This commit is contained in:
@@ -165,6 +165,8 @@ def image_state_apply_operation(*, state, operation, params):
|
|||||||
return image_state_fft_spectrum_create(state=state, params=params or {})
|
return image_state_fft_spectrum_create(state=state, params=params or {})
|
||||||
if operation == "inverse_fft_reconstruction":
|
if operation == "inverse_fft_reconstruction":
|
||||||
return image_state_inverse_fft_create(state=state, params=params or {})
|
return image_state_inverse_fft_create(state=state, params=params or {})
|
||||||
|
if operation == "average_noisy_copies":
|
||||||
|
return image_state_average_noisy_copies_create(state=state, params=params or {})
|
||||||
|
|
||||||
source = load_image_array(state.image)
|
source = load_image_array(state.image)
|
||||||
result = apply_registered_operation(source, operation, params or {})
|
result = apply_registered_operation(source, operation, params or {})
|
||||||
@@ -180,6 +182,40 @@ def image_state_apply_operation(*, state, operation, params):
|
|||||||
return image_state_payload(state=new_state, include_image=True)
|
return image_state_payload(state=new_state, include_image=True)
|
||||||
|
|
||||||
|
|
||||||
|
def image_state_average_noisy_copies_create(*, state, params):
|
||||||
|
"""Create averaged noisy copies from the clean source behind a Gaussian-noise state.
|
||||||
|
|
||||||
|
If the active state is already a Gaussian-noisy image, the averaging must regenerate independent
|
||||||
|
noisy copies from its parent image, not from the already-noisy pixels.
|
||||||
|
"""
|
||||||
|
|
||||||
|
source_state = state
|
||||||
|
if (
|
||||||
|
state.operation == "noise_filter"
|
||||||
|
and isinstance(state.params, dict)
|
||||||
|
and state.params.get("kind", "gaussian") == "gaussian"
|
||||||
|
and state.parent is not None
|
||||||
|
):
|
||||||
|
source_state = state.parent
|
||||||
|
|
||||||
|
operation_params = dict(params or {})
|
||||||
|
if source_state.id != state.id:
|
||||||
|
operation_params["source_state_id"] = str(source_state.id)
|
||||||
|
|
||||||
|
source = load_image_array(source_state.image)
|
||||||
|
result = apply_registered_operation(source, "average_noisy_copies", operation_params)
|
||||||
|
new_state = image_state_create(
|
||||||
|
session=state.session,
|
||||||
|
parent=state,
|
||||||
|
image=result,
|
||||||
|
operation="average_noisy_copies",
|
||||||
|
params=operation_params,
|
||||||
|
label=None,
|
||||||
|
prefix="state-average_noisy_copies",
|
||||||
|
)
|
||||||
|
return image_state_payload(state=new_state, include_image=True)
|
||||||
|
|
||||||
|
|
||||||
def image_state_fft_spectrum_create(*, state, params):
|
def image_state_fft_spectrum_create(*, state, params):
|
||||||
"""Create an FFT visualization state and persist the actual complex spectrum.
|
"""Create an FFT visualization state and persist the actual complex spectrum.
|
||||||
|
|
||||||
|
|||||||
@@ -233,6 +233,29 @@ class ApiTests(TestCase):
|
|||||||
self.assertEqual(result.ndim, 2)
|
self.assertEqual(result.ndim, 2)
|
||||||
self.assertEqual(int(result[0, 0]), 96)
|
self.assertEqual(int(result[0, 0]), 96)
|
||||||
|
|
||||||
|
def test_average_noisy_copies_uses_clean_parent_after_gaussian_noise_state(self):
|
||||||
|
upload = self.client.post("/api/images/", {"image": grayscale_png_upload(value=96)}, format="multipart")
|
||||||
|
s0_id = upload.data["states"][0]["state_id"]
|
||||||
|
noisy = self.client.post(
|
||||||
|
f"/api/states/{s0_id}/operations/",
|
||||||
|
{"operation": "noise_filter", "params": {"kind": "gaussian", "mean": 0.2, "variance": 0}},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
noisy_image = load_image_array(ImageState.objects.get(id=noisy.data["state_id"]).image)
|
||||||
|
self.assertGreater(int(noisy_image[0, 0]), 96)
|
||||||
|
|
||||||
|
averaged = self.client.post(
|
||||||
|
f"/api/states/{noisy.data['state_id']}/operations/",
|
||||||
|
{"operation": "average_noisy_copies", "params": {"N": 10, "kind": "gaussian", "mean": 0, "variance": 0}},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(averaged.status_code, 201)
|
||||||
|
self.assertEqual(averaged.data["parent_state_id"], noisy.data["state_id"])
|
||||||
|
self.assertEqual(averaged.data["params"]["source_state_id"], s0_id)
|
||||||
|
result = load_image_array(ImageState.objects.get(id=averaged.data["state_id"]).image)
|
||||||
|
self.assertEqual(int(result[0, 0]), 96)
|
||||||
|
|
||||||
def test_periodic_noise_preserves_grayscale_and_zero_amplitude(self):
|
def test_periodic_noise_preserves_grayscale_and_zero_amplitude(self):
|
||||||
upload = self.client.post("/api/images/", {"image": grayscale_png_upload(value=96)}, format="multipart")
|
upload = self.client.post("/api/images/", {"image": grayscale_png_upload(value=96)}, format="multipart")
|
||||||
s0_id = upload.data["states"][0]["state_id"]
|
s0_id = upload.data["states"][0]["state_id"]
|
||||||
|
|||||||
Reference in New Issue
Block a user