nl_means_layered#

Applies the non-local means filter to each 2D layer of a 3D image (stack of 2D images) in parallel. This function is applicable in removing noise from SEM images.

import matplotlib.pyplot as plt
import numpy as np
import porespy as ps
from skimage.util import random_noise
import inspect
ps.visualization.set_mpl_style()
inspect.signature(ps.filters.nl_means_layered)
<Signature (im, cores=None, axis=0, patch_size=5, patch_distance=15, h=4)>

im#

The input image is a greyscale image with noise to be removed. Let’s create a test image:

np.random.seed(10)
im = ps.generators.blobs(shape=[75, 75, 75])
im2 = random_noise(im, mode='gaussian', mean=0.24, var=0.05)
fig, ax = plt.subplots(1, 2, figsize=[12, 6])
ax[0].imshow(im2[:, :, 15])
ax[0].axis(False)
ax[1].hist(im2.flatten(), bins=25, edgecolor='k');
../../../_images/309fd005532605156b779d0fce73da82babf77dd89f41341e79115c5a5e22991.png
filtered_im = ps.filters.nl_means_layered(im2, axis=2)
fig, ax = plt.subplots(1, 3, figsize=[15, 5])
ax[0].imshow(filtered_im[..., 15])
ax[0].axis(False)
ax[1].hist(filtered_im.flatten(), bins=25, edgecolor='k')
ax[2].imshow(filtered_im[..., 15] > 0.6)
ax[2].axis(False);
../../../_images/bae4ec3492b07a0206e85a6b487a4da8f364fbb6752fd23f24716ceeb109f446.png

cores#

The number of cores to use for the processing. The default is all cores. Let’s change it to a smaller number (this will slow down the processing time):

filtered_im = ps.filters.nl_means_layered(im2, axis=2, cores=1)
fig, ax = plt.subplots(1, 1, figsize=[6, 6])
ax.imshow(filtered_im[:, :, 15])
ax.axis(False);
../../../_images/50a96c5a2be86713b69023c296f7a47ecf33105773c04d39ac6e96bf10c7b9e0.png

axis#

The axis along which 2D slices for the filtering process should be taken. This can be 0,1, or 2 corresponding to x, y, and z axis. By default the slices are taken along x axis. When using tomography images, this should correspond to the axis of rotation of the tomography stage.

im_x = ps.filters.nl_means_layered(im2, axis=0)
im_y = ps.filters.nl_means_layered(im2, axis=1)
im_z = ps.filters.nl_means_layered(im2, axis=2)
fig, ax = plt.subplots(1, 4, figsize=[15, 5])
ax[0].imshow(im2[..., 15])
ax[0].axis(False);
ax[1].imshow(im_x[..., 15])
ax[1].axis(False);
ax[2].imshow(im_y[..., 15])
ax[2].axis(False);
ax[3].imshow(im_z[..., 15])
ax[3].axis(False);
../../../_images/d456587baccf80e1f0983b8bd2de8c565e55ca6112bd027a9a3a0194c018cfeb.png

patch_size#

The size of patches used for denoising filter. The default is 5.

im_1 = ps.filters.nl_means_layered(im2, patch_size=1)
im_2 = ps.filters.nl_means_layered(im2, patch_size=3)
im_3 = ps.filters.nl_means_layered(im2, patch_size=8)
fig, ax = plt.subplots(1, 4, figsize=[15, 5])
ax[0].imshow(im2[..., 15])
ax[0].axis(False);
ax[1].imshow(im_1[..., 15])
ax[1].axis(False);
ax[2].imshow(im_2[..., 15])
ax[2].axis(False);
ax[3].imshow(im_3[..., 15])
ax[3].axis(False);
../../../_images/850e3c8d8061efbaa51903677f4e2bc3d5aae208678bfc2b572dbc324dffaae0.png

patch_distance#

Maximal distance in pixels where to search patches used for denoising. The default is 15.

im_1 = ps.filters.nl_means_layered(im2, patch_distance=10)
im_2 = ps.filters.nl_means_layered(im2)
im_3 = ps.filters.nl_means_layered(im2, patch_distance=20)
fig, ax = plt.subplots(1, 4, figsize=[15, 5])
ax[0].imshow(im2[..., 15])
ax[0].axis(False);
ax[1].imshow(im_1[..., 15])
ax[1].axis(False);
ax[2].imshow(im_2[..., 15])
ax[2].axis(False);
ax[3].imshow(im_3[..., 15])
ax[3].axis(False);
../../../_images/b1008cfe17fb56b3dab206b56d42ab88dcc20f46de75b57e9349d533e94f8999.png

h#

Cut-off distance (in gray levels). The higher h, the more permissive one is in accepting patches. A higher h results in a smoother image, at the expense of blurring features. For a Gaussian noise of standard deviation sigma, a rule of thumb is to choose the value of h to be sigma of slightly less. The default is 4.

im_1 = ps.filters.nl_means_layered(im2, h=2)
im_2 = ps.filters.nl_means_layered(im2)
im_3 = ps.filters.nl_means_layered(im2, h=6)
fig, ax = plt.subplots(1, 4, figsize=[15, 5])
ax[0].imshow(im2[..., 15])
ax[0].axis(False);
ax[1].imshow(im_1[..., 15])
ax[1].axis(False);
ax[2].imshow(im_2[..., 15])
ax[2].axis(False);
ax[3].imshow(im_3[..., 15])
ax[3].axis(False);
../../../_images/989baed504ecb568e8340990c7962a69c4905ab1a7651649205ccb77e4b5be68.png