1
+ """Python API for the mode and empirical null filter - GPU ONLY
2
+
3
+ The empirical null filter normalises an image using the empirical null mean
4
+ filter (also known as the mode filter) and the empirical null std filter.
5
+ The mode filter is an edge-preserving smoothing filter by taking the local mode
6
+ of the empirical density. The empirical null std filter takes the local standard
7
+ deviation of the empirical density.
8
+
9
+ This code uses CuPy to interact with the cuda implementation of the empirical
10
+ null filter. It requires the CUDA code to be compiled into a .ptx file
11
+ beforehand. See PTX_FILE_PATH in this code and Makefile in the repo.
12
+
13
+ To use, instantiate from EmpiricalNullFilter() or ModeFilter() and modify their
14
+ options if needed. Then call filter(image) to filter the image.
15
+
16
+ The GPU is used in the following filters:
17
+ - counting the number of finite elements in the kernel using the custom cuda
18
+ module (see _get_prerequisite_images() and d_count)
19
+ - std filter using the custom cuda module (see _get_prerequisite_images())
20
+ - median filter of the image using cupyx.scipy.ndimage (see
21
+ _get_prerequisite_images())
22
+ - quartile filter of the image using cupyx.scipy.ndimage (see
23
+ _get_prerequisite_images())
24
+ - empirical null filter of the image using the custom module (see
25
+ _call_cuda_kernel())
26
+
27
+ Example:
28
+
29
+ import cupy
30
+ import matplotlib.pyplot as plt
31
+ import numpy as np
32
+ import numpy.random
33
+ import skimage.data
34
+
35
+ import modefilter
36
+
37
+ image = skimage.data.coffee()[:, :, 0]
38
+
39
+ plt.figure()
40
+ plt.imshow(image)
41
+ plt.show()
42
+
43
+ filter = modefilter.ModeFilter(30)
44
+ filter.set_n_initial(100)
45
+ filtered = filter.filter(image)
46
+
47
+ plt.figure()
48
+ plt.imshow(filtered)
49
+ plt.show()
50
+ """
51
+
1
52
import ctypes
2
53
from importlib .resources import files
3
54
import math
@@ -23,6 +74,24 @@ class EmpiricalNullFilter:
23
74
- call filter.filter(image) which returns the filtered image
24
75
- call filter.get_null_mean() or filter.get_null_std() to get the
25
76
the null mean or null std image
77
+
78
+ Attributes:
79
+ _radius (float): radius of the kernel
80
+ _n_initial (int): number of initial points for the Newton method
81
+ _n_step (int): number of steps for the Newton method
82
+ _bandwidth_parameter_a (float): bandwidth parameter A for density
83
+ estimate
84
+ _bandwidth_parameter_b (float): bandwidth parameter B for density
85
+ estimate
86
+ _block_dim_x (int): x block dimension for GPU
87
+ _block_dim_y (int): y block dimension for GPU
88
+ _std_for_zero (float): value to replace zero value pixels when doing
89
+ std filtering
90
+ _null_mean (numpy.ndarray): the resulting empirical null mean or mode
91
+ filter after calling filter()
92
+ _null_std (numpy.ndarray): the resulting empirical null std after
93
+ calling filter()
94
+ _kernel (_Kernel): the kernel used in filtering
26
95
"""
27
96
28
97
def __init__ (self , radius ):
@@ -47,7 +116,7 @@ def set_n_initial(self, n_initial):
47
116
self ._n_initial = n_initial
48
117
49
118
def set_n_step (self , n_step ):
50
- """Set the number of stepsfor the Newton method
119
+ """Set the number of steps for the Newton method
51
120
52
121
Args:
53
122
n_step (int): Number of steps for Newton method
@@ -405,6 +474,22 @@ def _get_d_kernel_pointer(self):
405
474
return cupy .asarray (self ._kernel .get_pointer (), cupy .int32 )
406
475
407
476
477
+ class ModeFilter (EmpiricalNullFilter ):
478
+ """Mode filter using GPU
479
+
480
+ Get the mode filtered image
481
+
482
+ How to use:
483
+ - construct the filter filter = Modefilter(radius)
484
+ - set optional parameters, for example, filter.set_n_initial(100)
485
+ - call filter.filter(image) which returns the mode image
486
+ """
487
+
488
+ def filter (self , image ):
489
+ super ().filter (image )
490
+ return self .get_null_mean ()
491
+
492
+
408
493
class _Kernel :
409
494
"""A circular kernel which captures the local pixels
410
495
0 commit comments