From 9a6042602fb6540dda802fa22cc943c90aeeaf4b Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Mon, 20 Mar 2023 09:32:42 -0400 Subject: [PATCH 1/3] Allow whiten to take an estimator directly --- src/aspire/source/image.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/aspire/source/image.py b/src/aspire/source/image.py index 569a38eade..3ec94ad620 100644 --- a/src/aspire/source/image.py +++ b/src/aspire/source/image.py @@ -17,9 +17,10 @@ Multiply, Pipeline, ) -from aspire.noise import WhiteNoiseEstimator +from aspire.noise import NoiseEstimator, WhiteNoiseEstimator from aspire.operators import ( CTFFilter, + Filter, IdentityFilter, MultiplicativeFilter, PowerFilter, @@ -454,14 +455,29 @@ def downsample(self, L): self.L = L - def whiten(self, noise_filter): + def whiten(self, noise_estimate): """ Modify the `ImageSource` in-place by appending a whitening filter to the generation pipeline. - :param noise_filter: The noise psd of the images as a `Filter` object. Typically determined by a - NoiseEstimator class, and available as its `filter` attribute. + :param noise_estimate: `NoiseEstimator` or `Filter`. When + passed a `NoiseEstimator` the `filter` attribute will be + queried. Alternatively, the noise PSD may be passed + directly as a `Filter` object. :return: On return, the `ImageSource` object has been modified in place. """ + + if isinstance(noise_estimate, NoiseEstimator): + # Any NoiseEstimator instance should have a `filter`. + noise_filter = noise_estimate.filter + elif isinstance(noise_estimate, Filter): + # We were given a `Filter` object. + noise_filter = noise_estimate + else: + raise TypeError( + f"Whiten passed {noise_estimate}" + " instead of `NoiseEstimator` or `Filter`." + ) + logger.info("Whitening source object") whiten_filter = PowerFilter(noise_filter, power=-0.5) From 8b84e4f8986f2c41349d3135e79411a277017b38 Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Mon, 20 Mar 2023 10:28:51 -0400 Subject: [PATCH 2/3] Update `whiten()` usage --- gallery/experiments/cov2d_experiment.py.dontrun | 2 +- gallery/experiments/cov3d_experiment.dontrun | 2 +- gallery/experiments/experimental_abinitio_pipeline.py | 2 +- gallery/experiments/preprocess_imgs_exp.py.dontrun | 2 +- gallery/experiments/simulated_abinitio_pipeline.py | 4 ++-- gallery/tutorials/basic_image_array.py | 2 +- gallery/tutorials/lecture_feature_demo.py | 4 ++-- gallery/tutorials/preprocess_imgs_sim.py | 2 +- gallery/tutorials/starfile.py | 2 +- src/aspire/commands/denoise.py | 2 +- src/aspire/commands/extract_particles.py | 2 +- src/aspire/commands/preprocess.py | 2 +- tests/test_coordinate_source.py | 2 +- tests/test_preprocess_pipeline.py | 6 ++++-- 14 files changed, 19 insertions(+), 17 deletions(-) diff --git a/gallery/experiments/cov2d_experiment.py.dontrun b/gallery/experiments/cov2d_experiment.py.dontrun index 80d784d41d..7d58217d95 100755 --- a/gallery/experiments/cov2d_experiment.py.dontrun +++ b/gallery/experiments/cov2d_experiment.py.dontrun @@ -47,7 +47,7 @@ logger.info(f"var_noise before whitening {var_noise}") # Whiten the noise of images logger.info(f"Whiten the noise of images from the noise estimator") -source.whiten(noise_estimator.filter) +source.whiten(noise_estimator) # Note this changes the noise variance, # flattening spectrum and converging towards 1. # Noise variance will be recomputed in DenoiserCov2D by default. diff --git a/gallery/experiments/cov3d_experiment.dontrun b/gallery/experiments/cov3d_experiment.dontrun index 5cad831943..e0c11d088b 100644 --- a/gallery/experiments/cov3d_experiment.dontrun +++ b/gallery/experiments/cov3d_experiment.dontrun @@ -40,7 +40,7 @@ noise_estimator = AnisotropicNoiseEstimator(source, batchSize=512) # Whiten the noise of images print("Whiten the noise of images from the noise estimator") -source.whiten(noise_estimator.filter) +source.whiten(noise_estimator) # Estimate the noise variance. This is needed for the covariance estimation step below. noise_variance = noise_estimator.estimate() print(f"Noise Variance = {noise_variance}") diff --git a/gallery/experiments/experimental_abinitio_pipeline.py b/gallery/experiments/experimental_abinitio_pipeline.py index 883485838d..92d0f53fc4 100644 --- a/gallery/experiments/experimental_abinitio_pipeline.py +++ b/gallery/experiments/experimental_abinitio_pipeline.py @@ -78,7 +78,7 @@ # Estimate the noise and `Whiten` based on the estimated noise aiso_noise_estimator = AnisotropicNoiseEstimator(src) -src.whiten(aiso_noise_estimator.filter) +src.whiten(aiso_noise_estimator) # Plot the noise profile for inspection if interactive: diff --git a/gallery/experiments/preprocess_imgs_exp.py.dontrun b/gallery/experiments/preprocess_imgs_exp.py.dontrun index b4ae7e7d70..d2b28e1b87 100644 --- a/gallery/experiments/preprocess_imgs_exp.py.dontrun +++ b/gallery/experiments/preprocess_imgs_exp.py.dontrun @@ -45,7 +45,7 @@ imgs_nb = source.images[:nimgs_ext] print('Whiten noise of images') noise_estimator = WhiteNoiseEstimator(source) -source.whiten(noise_estimator.filter) +source.whiten(noise_estimator) imgs_wt = source.images[:nimgs_ext] print('Invert global density contrast') diff --git a/gallery/experiments/simulated_abinitio_pipeline.py b/gallery/experiments/simulated_abinitio_pipeline.py index 59820cfffc..b071399b89 100644 --- a/gallery/experiments/simulated_abinitio_pipeline.py +++ b/gallery/experiments/simulated_abinitio_pipeline.py @@ -118,11 +118,11 @@ def noise_function(x, y): # Estimate the noise and `Whiten` based on the estimated noise aiso_noise_estimator = AnisotropicNoiseEstimator(src) -src.whiten(aiso_noise_estimator.filter) +src.whiten(aiso_noise_estimator) # Plot the noise profile for inspection if interactive: - plt.imshow(aiso_noise_estimator.filter.evaluate_grid(L)) + plt.imshow(aiso_noise_estimator.evaluate_grid(L)) plt.show() # Peek, what do the whitened images look like... diff --git a/gallery/tutorials/basic_image_array.py b/gallery/tutorials/basic_image_array.py index 08364d2870..a7dc56e7ef 100644 --- a/gallery/tutorials/basic_image_array.py +++ b/gallery/tutorials/basic_image_array.py @@ -139,7 +139,7 @@ def noise_function(x, y): # Once we have the estimator instance, # we can use it in a transform applied to our Source. -imgs_src.whiten(noise_estimator.filter) +imgs_src.whiten(noise_estimator) # Peek at two whitened images and their corresponding spectrum. diff --git a/gallery/tutorials/lecture_feature_demo.py b/gallery/tutorials/lecture_feature_demo.py index 80f6fa94f2..5acf3573a0 100644 --- a/gallery/tutorials/lecture_feature_demo.py +++ b/gallery/tutorials/lecture_feature_demo.py @@ -272,14 +272,14 @@ def noise_function(x, y): # Noise Whitening # --------------- # -# Applying the ``Simulation.whiten()`` method just requires passing the filter corresponding to the estimated noise instance. +# Applying the ``Simulation.whiten()`` method just requires passing a `NoiseEstimator` instance. # Then we can inspect some of the whitened images. While noise is still present, we can see a dramatic change. # Estimate noise. aiso_noise_estimator = AnisotropicNoiseEstimator(sim4) # Whiten based on the estimated noise -sim4.whiten(aiso_noise_estimator.filter) +sim4.whiten(aiso_noise_estimator) # What do the whitened images look like... sim4.images[:10].show() diff --git a/gallery/tutorials/preprocess_imgs_sim.py b/gallery/tutorials/preprocess_imgs_sim.py index a2e80cddb8..7f874d691d 100644 --- a/gallery/tutorials/preprocess_imgs_sim.py +++ b/gallery/tutorials/preprocess_imgs_sim.py @@ -97,7 +97,7 @@ logger.info("Whiten noise of images") noise_estimator = WhiteNoiseEstimator(source) -source.whiten(noise_estimator.filter) +source.whiten(noise_estimator) imgs_wt = source.images[0].asnumpy() logger.info("Invert the global density contrast if need") diff --git a/gallery/tutorials/starfile.py b/gallery/tutorials/starfile.py index 819accb1ac..8e65a3607f 100644 --- a/gallery/tutorials/starfile.py +++ b/gallery/tutorials/starfile.py @@ -37,7 +37,7 @@ # Estimate noise in the ImageSource instance noise_estimator = AnisotropicNoiseEstimator(source) # Apply whitening to ImageSource -source.whiten(noise_estimator.filter) +source.whiten(noise_estimator) # Display subset of the images images = source.images[:10] diff --git a/src/aspire/commands/denoise.py b/src/aspire/commands/denoise.py index 91dfb09e26..9f0f32c06d 100644 --- a/src/aspire/commands/denoise.py +++ b/src/aspire/commands/denoise.py @@ -96,7 +96,7 @@ def denoise( # Whiten the noise of images logger.info("Whiten the noise of images from the noise estimator") - source.whiten(noise_estimator.filter) + source.whiten(noise_estimator) if denoise_method == "CWF": logger.info("Denoise the images using CWF cov2D method.") diff --git a/src/aspire/commands/extract_particles.py b/src/aspire/commands/extract_particles.py index 8bceb4d685..6fd3946275 100644 --- a/src/aspire/commands/extract_particles.py +++ b/src/aspire/commands/extract_particles.py @@ -148,7 +148,7 @@ def extract_particles( src.normalize_background() if whiten: estimator = WhiteNoiseEstimator(src) - src.whiten(estimator.filter) + src.whiten(estimator) if invert_contrast: src.invert_contrast() diff --git a/src/aspire/commands/preprocess.py b/src/aspire/commands/preprocess.py index d9404cba17..474ae29359 100644 --- a/src/aspire/commands/preprocess.py +++ b/src/aspire/commands/preprocess.py @@ -110,7 +110,7 @@ def preprocess( if whiten: logger.info("Whiten noise of images") noise_estimator = WhiteNoiseEstimator(source) - source.whiten(noise_estimator.filter) + source.whiten(noise_estimator) if invert_contrast: logger.info("Invert global density contrast") diff --git a/tests/test_coordinate_source.py b/tests/test_coordinate_source.py index ec0dc05b63..a2c1edb83a 100644 --- a/tests/test_coordinate_source.py +++ b/tests/test_coordinate_source.py @@ -515,7 +515,7 @@ def testPreprocessing(self): src.downsample(60) src.normalize_background() noise_estimator = WhiteNoiseEstimator(src) - src.whiten(noise_estimator.filter) + src.whiten(noise_estimator) src.invert_contrast() # call .images() to ensure the filters are applied # and not just added to pipeline diff --git a/tests/test_preprocess_pipeline.py b/tests/test_preprocess_pipeline.py index c63102d07b..109f532b40 100644 --- a/tests/test_preprocess_pipeline.py +++ b/tests/test_preprocess_pipeline.py @@ -94,7 +94,7 @@ def testWhiten(dtype): L = 64 sim = get_sim_object(L, dtype) noise_estimator = AnisotropicNoiseEstimator(sim) - sim.whiten(noise_estimator.filter) + sim.whiten(noise_estimator) imgs_wt = sim.images[:num_images].asnumpy() # calculate correlation between two neighboring pixels from background @@ -110,8 +110,10 @@ def testWhiten(dtype): def testWhiten2(dtype): # Excercises missing cases using odd image resolutions with filter. # Relates to GitHub issue #401. - # Otherwise this is the same as testWhiten, though the accuracy + # Otherwise this is the similar to testWhiten, though the accuracy # (atol) for odd resolutions seems slightly worse. + # Note, we also use this test to excercise calling `whiten` + # directly with a `Filter`. L = 63 sim = get_sim_object(L, dtype) noise_estimator = AnisotropicNoiseEstimator(sim) From 17094d66c59e757fba9c26f697fb2879e7184689 Mon Sep 17 00:00:00 2001 From: Garrett Wright Date: Thu, 23 Mar 2023 11:22:24 -0400 Subject: [PATCH 3/3] Revert incorrect string replacement. --- gallery/experiments/simulated_abinitio_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gallery/experiments/simulated_abinitio_pipeline.py b/gallery/experiments/simulated_abinitio_pipeline.py index b071399b89..296541c022 100644 --- a/gallery/experiments/simulated_abinitio_pipeline.py +++ b/gallery/experiments/simulated_abinitio_pipeline.py @@ -122,7 +122,7 @@ def noise_function(x, y): # Plot the noise profile for inspection if interactive: - plt.imshow(aiso_noise_estimator.evaluate_grid(L)) + plt.imshow(aiso_noise_estimator.filter.evaluate_grid(L)) plt.show() # Peek, what do the whitened images look like...