Coverage for /usr/local/lib/python3.10/site-packages/spam/filters/movingFilters.py: 100%
64 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-24 17:26 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-24 17:26 +0000
1# Library of SPAM filters.
2# Copyright (C) 2020 SPAM Contributors
3#
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License as published by the Free
6# Software Foundation, either version 3 of the License, or (at your option)
7# any later version.
8#
9# This program is distributed in the hope that it will be useful, but WITHOUT
10# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12# more details.
13#
14# You should have received a copy of the GNU General Public License along with
15# this program. If not, see <http://www.gnu.org/licenses/>.
17import numpy
18import spam.mesh
20# Default structural element
21# 0 0 0
22# 0 1 0
23# 0 0 0
24# 0 1 0
25# 1 2 1
26# 0 1 0
27# 0 0 0
28# 0 1 0
29# 0 0 0
30structEl = spam.mesh.structuringElement(radius=1, order=1).astype("<f4")
31structEl[1, 1, 1] = 2.0
34def average(im, structEl=structEl):
35 """
36 This function calculates the average map of a grey scale image over a structuring element
37 It works for 3D and 2D images
39 Parameters
40 ----------
41 im : 3D or 2D numpy array
42 The grey scale image for which the average map will be calculated
44 structEl : 3D or 2D numpy array, optional
45 The structural element defining the local window-size of the operation
46 Note that the value of each component is considered as a weight (ponderation) for the operation
47 (see `spam.mesh.structured.structuringElement` for details about the structural element)
48 Default = radius = 1 (3x3x3 array), order = 1 (`diamond` shape)
50 Returns
51 -------
52 imFiltered : 3D or 2D numpy array
53 The averaged image
54 """
55 import spambind.filters.filtersToolkit as mft
57 # Detect 2D image:
58 if len(im.shape) == 2:
59 # pad it
60 im = im[numpy.newaxis, ...]
61 structEl = structEl[numpy.newaxis, ...]
63 imFiltered = numpy.zeros_like(im).astype("<f4")
64 mft.average(im, imFiltered, structEl)
66 # Return back 2D image:
67 if im.shape[0] == 1:
68 imFiltered = imFiltered[0, :, :]
70 return imFiltered
73def variance(im, structEl=structEl):
74 """ "
75 This function calculates the variance map of a grey scale image over a structuring element
76 It works for 3D and 2D images
78 Parameters
79 ----------
80 im : 3D or 2D numpy array
81 The grey scale image for which the variance map will be calculated
83 structEl : 3D or 2D numpy array, optional
84 The structural element defining the local window-size of the operation
85 Note that the value of each component is considered as a weight (ponderation) for the operation
86 (see `spam.mesh.structured.structuringElement` for details about the structural element)
87 Default = radius = 1 (3x3x3 array), order = 1 (`diamond` shape)
89 Returns
90 -------
91 imFiltered : 3D or 2D numpy array
92 The variance image
93 """
94 import spambind.filters.filtersToolkit as mft
96 # Detect 2D image:
97 if len(im.shape) == 2:
98 # pad it
99 im = im[numpy.newaxis, ...]
100 structEl = structEl[numpy.newaxis, ...]
102 imFiltered = numpy.zeros_like(im).astype("<f4")
103 mft.variance(im, imFiltered, structEl)
105 # Return back 2D image:
106 if im.shape[0] == 1:
107 imFiltered = imFiltered[0, :, :]
109 return imFiltered
112def hessian(im):
113 """
114 This function computes the hessian matrix of grey values (matrix of second derivatives)
115 and returns eigenvalues and eigenvectors of the hessian matrix for each voxel...
116 I hope you have a lot of memory!
118 Parameters
119 -----------
120 im: 3D numpy array
121 The grey scale image for which the hessian will be calculated
123 Returns
124 --------
125 list containing two lists:
126 List 1: contains 3 different 3D arrays (same size as im):
127 Maximum, Intermediate, Minimum eigenvalues
128 List 2: contains 9 different 3D arrays (same size as im):
129 Components Z, Y, X of Maximum
130 Components Z, Y, X of Intermediate
131 Components Z, Y, X of Minimum eigenvalues
132 """
133 # 2018-10-24 EA OS MCB "double" hessian fracture filter
134 # There is already an imageJ implementation, but it does not output eigenvectors
135 import spambind.filters.filtersToolkit as ftk
137 im = im.astype("<f4")
139 # The hessian matrix in 3D is a 3x3 matrix of gradients embedded in each point...
140 # hessian = numpy.zeros((3,3,im.shape[0],im.shape[1],im.shape[2]), dtype='<f4' )
141 hzz = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
142 hzy = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
143 hzx = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
144 hyz = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
145 hyy = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
146 hyx = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
147 hxz = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
148 hxy = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
149 hxx = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
150 eigValA = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
151 eigValB = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
152 eigValC = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
153 eigVecAz = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
154 eigVecAy = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
155 eigVecAx = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
156 eigVecBz = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
157 eigVecBy = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
158 eigVecBx = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
159 eigVecCz = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
160 eigVecCy = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
161 eigVecCx = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4")
163 # gaussian
164 # gauss = ndi.gaussian_filter(image,sigma=0.5, mode='constant', cval=0)
166 # first greylevel derivative, return Z, Y, X gradients
167 gradient = numpy.gradient(im)
169 # second derivate
170 tmp = numpy.gradient(gradient[0])
171 hzz = tmp[0]
172 hzy = tmp[1]
173 hzx = tmp[2]
174 tmp = numpy.gradient(gradient[1])
175 hyz = tmp[0]
176 hyy = tmp[1]
177 hyx = tmp[2]
178 tmp = numpy.gradient(gradient[2])
179 hxz = tmp[0]
180 hxy = tmp[1]
181 hxx = tmp[2]
183 del tmp, gradient
185 # run eigen solver for each pixel!!!
186 ftk.hessian(hzz, hzy, hzx, hyz, hyy, hyx, hxz, hxy, hxx, eigValA, eigValB, eigValC, eigVecAz, eigVecAy, eigVecAx, eigVecBz, eigVecBy, eigVecBx, eigVecCz, eigVecCy, eigVecCx)
188 return [[eigValA, eigValB, eigValC], [eigVecAz, eigVecAy, eigVecAx, eigVecBz, eigVecBy, eigVecBx, eigVecCz, eigVecCy, eigVecCx]]
191# old equivalent 100% python stuff... way slower
192# def _moving_average( im, struct=default_struct ):
193# """
194# Calculate the average of a grayscale image over a 3x3x3 structuring element
195# The output is float32 since results is sometimes outof the uint bounds during computation
196# PARAMETERS:
197# - im (numpy.array): The grayscale image to be treated
198# - struct (array of int): the structural element.
199# Note that the value of each component is considerred as a weight (ponderation) for the operation
200# RETURNS:
201# - o_im (numpy.array float32): The averaged image
202# HISTORY:
203# 2016-03-24 (JBC): First version of the function
204# 2016-04-05 (ER): generalisation using structural elements
205# 2016-05-03 (ER): add progress bar
206# """
207# # Step 1: init output_image as float 32 bits
208# o_im = numpy.zeros( im.shape, dtype='<f4' )
209# # Step 2: structutral element
210# structural_element_size = int( len( struct )/2 )
211# structural_element_weight = float( struct.sum() )
212# if prlv>5:
213# import progressbar
214# max_values = len( numpy.argwhere( struct ) )
215# bar = progressbar.ProgressBar( maxval=max_values, widgets=['Average filter: ', progressbar.Percentage(), progressbar.Bar('=', '[', ']')] )
216# bar.start()
217# for i, c in enumerate( numpy.argwhere( struct ) ):
218# # convert structural element coordinates into shift to apply
219# shift_to_apply = c-structural_element_size
220# # get the local weight from the structural element value
221# current_voxel_weight = float( struct[c[0], c[1], c[2]] )
222# # if prlv>5: print ' Shift {} of weight {}'.format( shift_to_apply, current_voxel_weight )
223# # output_image = output_image + ( voxel_weight * image / element_weight )
224# o_im += current_voxel_weight*sman.multiple_shifts( im, shifts=shift_to_apply )/structural_element_weight
225# if prlv>5: bar.update( i+1 )
226# if prlv>5: bar.finish()
227# return o_im
228#
229# def _moving_variance( im, struct=default_struct ):
230# """
231# Calculate the variance of a grayscale image over a 3x3x3 structuring element
232# The output is float32 since results is sometimes outof the uint bounds during computation
233# PARAMETERS:
234# - image (numpy.array): The grayscale image to be treat
235# RETURNS:
236# - o_im (numpy.array): The varianced image
237# HISTORY:
238# 2016-04-05 (ER): First version of the function
239# """
240# # Step 1: return E(im**2) - E(im)**2
241# return moving_average( numpy.square( im.astype('<f4') ), struct=struct ) - numpy.square( moving_average( im, struct=struct ) )