Source code for spam.filters.movingFilters

# Library of SPAM filters.
# Copyright (C) 2020 SPAM Contributors
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, see <http://www.gnu.org/licenses/>.

import numpy
import spam.mesh

# Default structural element
#       0 0 0
#       0 1 0
#       0 0 0
#    0 1 0
#    1 2 1
#    0 1 0
# 0 0 0
# 0 1 0
# 0 0 0
structEl = spam.mesh.structuringElement(radius=1, order=1).astype("<f4")
structEl[1, 1, 1] = 2.0


[docs] def average(im, structEl=structEl): """ This function calculates the average map of a grey scale image over a structuring element It works for 3D and 2D images Parameters ---------- im : 3D or 2D numpy array The grey scale image for which the average map will be calculated structEl : 3D or 2D numpy array, optional The structural element defining the local window-size of the operation Note that the value of each component is considered as a weight (ponderation) for the operation (see `spam.mesh.structured.structuringElement` for details about the structural element) Default = radius = 1 (3x3x3 array), order = 1 (`diamond` shape) Returns ------- imFiltered : 3D or 2D numpy array The averaged image """ import spam.filters.filtersToolkit as mft # Detect 2D image: if len(im.shape) == 2: # pad it im = im[numpy.newaxis, ...] structEl = structEl[numpy.newaxis, ...] imFiltered = numpy.zeros_like(im).astype("<f4") mft.average(im, imFiltered, structEl) # Return back 2D image: if im.shape[0] == 1: imFiltered = imFiltered[0, :, :] return imFiltered
[docs] def variance(im, structEl=structEl): """ " This function calculates the variance map of a grey scale image over a structuring element It works for 3D and 2D images Parameters ---------- im : 3D or 2D numpy array The grey scale image for which the variance map will be calculated structEl : 3D or 2D numpy array, optional The structural element defining the local window-size of the operation Note that the value of each component is considered as a weight (ponderation) for the operation (see `spam.mesh.structured.structuringElement` for details about the structural element) Default = radius = 1 (3x3x3 array), order = 1 (`diamond` shape) Returns ------- imFiltered : 3D or 2D numpy array The variance image """ import spam.filters.filtersToolkit as mft # Detect 2D image: if len(im.shape) == 2: # pad it im = im[numpy.newaxis, ...] structEl = structEl[numpy.newaxis, ...] imFiltered = numpy.zeros_like(im).astype("<f4") mft.variance(im, imFiltered, structEl) # Return back 2D image: if im.shape[0] == 1: imFiltered = imFiltered[0, :, :] return imFiltered
[docs] def hessian(im): """ This function computes the hessian matrix of grey values (matrix of second derivatives) and returns eigenvalues and eigenvectors of the hessian matrix for each voxel... I hope you have a lot of memory! Parameters ----------- im: 3D numpy array The grey scale image for which the hessian will be calculated Returns -------- list containing two lists: List 1: contains 3 different 3D arrays (same size as im): Maximum, Intermediate, Minimum eigenvalues List 2: contains 9 different 3D arrays (same size as im): Components Z, Y, X of Maximum Components Z, Y, X of Intermediate Components Z, Y, X of Minimum eigenvalues """ # 2018-10-24 EA OS MCB "double" hessian fracture filter # There is already an imageJ implementation, but it does not output eigenvectors import spam.filters.filtersToolkit as ftk im = im.astype("<f4") # The hessian matrix in 3D is a 3x3 matrix of gradients embedded in each point... # hessian = numpy.zeros((3,3,im.shape[0],im.shape[1],im.shape[2]), dtype='<f4' ) hzz = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") hzy = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") hzx = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") hyz = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") hyy = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") hyx = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") hxz = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") hxy = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") hxx = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") eigValA = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") eigValB = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") eigValC = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") eigVecAz = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") eigVecAy = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") eigVecAx = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") eigVecBz = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") eigVecBy = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") eigVecBx = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") eigVecCz = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") eigVecCy = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") eigVecCx = numpy.zeros((im.shape[0], im.shape[1], im.shape[2]), dtype="<f4") # gaussian # gauss = ndi.gaussian_filter(image,sigma=0.5, mode='constant', cval=0) # first greylevel derivative, return Z, Y, X gradients gradient = numpy.gradient(im) # second derivate tmp = numpy.gradient(gradient[0]) hzz = tmp[0] hzy = tmp[1] hzx = tmp[2] tmp = numpy.gradient(gradient[1]) hyz = tmp[0] hyy = tmp[1] hyx = tmp[2] tmp = numpy.gradient(gradient[2]) hxz = tmp[0] hxy = tmp[1] hxx = tmp[2] del tmp, gradient # run eigen solver for each pixel!!! ftk.hessian(hzz, hzy, hzx, hyz, hyy, hyx, hxz, hxy, hxx, eigValA, eigValB, eigValC, eigVecAz, eigVecAy, eigVecAx, eigVecBz, eigVecBy, eigVecBx, eigVecCz, eigVecCy, eigVecCx) return [[eigValA, eigValB, eigValC], [eigVecAz, eigVecAy, eigVecAx, eigVecBz, eigVecBy, eigVecBx, eigVecCz, eigVecCy, eigVecCx]]
# old equivalent 100% python stuff... way slower # def _moving_average( im, struct=default_struct ): # """ # Calculate the average of a grayscale image over a 3x3x3 structuring element # The output is float32 since results is sometimes outof the uint bounds during computation # PARAMETERS: # - im (numpy.array): The grayscale image to be treated # - struct (array of int): the structural element. # Note that the value of each component is considerred as a weight (ponderation) for the operation # RETURNS: # - o_im (numpy.array float32): The averaged image # HISTORY: # 2016-03-24 (JBC): First version of the function # 2016-04-05 (ER): generalisation using structural elements # 2016-05-03 (ER): add progress bar # """ # # Step 1: init output_image as float 32 bits # o_im = numpy.zeros( im.shape, dtype='<f4' ) # # Step 2: structutral element # structural_element_size = int( len( struct )/2 ) # structural_element_weight = float( struct.sum() ) # if prlv>5: # import progressbar # max_values = len( numpy.argwhere( struct ) ) # bar = progressbar.ProgressBar( maxval=max_values, widgets=['Average filter: ', progressbar.Percentage(), progressbar.Bar('=', '[', ']')] ) # bar.start() # for i, c in enumerate( numpy.argwhere( struct ) ): # # convert structural element coordinates into shift to apply # shift_to_apply = c-structural_element_size # # get the local weight from the structural element value # current_voxel_weight = float( struct[c[0], c[1], c[2]] ) # # if prlv>5: print ' Shift {} of weight {}'.format( shift_to_apply, current_voxel_weight ) # # output_image = output_image + ( voxel_weight * image / element_weight ) # o_im += current_voxel_weight*sman.multiple_shifts( im, shifts=shift_to_apply )/structural_element_weight # if prlv>5: bar.update( i+1 ) # if prlv>5: bar.finish() # return o_im # # def _moving_variance( im, struct=default_struct ): # """ # Calculate the variance of a grayscale image over a 3x3x3 structuring element # The output is float32 since results is sometimes outof the uint bounds during computation # PARAMETERS: # - image (numpy.array): The grayscale image to be treat # RETURNS: # - o_im (numpy.array): The varianced image # HISTORY: # 2016-04-05 (ER): First version of the function # """ # # Step 1: return E(im**2) - E(im)**2 # return moving_average( numpy.square( im.astype('<f4') ), struct=struct ) - numpy.square( moving_average( im, struct=struct ) )