mirror of
https://github.com/c-sooyoung/fold_slice.git
synced 2026-09-17 21:39:08 +09:00
467 lines
20 KiB
Python
467 lines
20 KiB
Python
import numpy as np
|
|
from numpy import *
|
|
from scipy import ndimage
|
|
import scipy.ndimage
|
|
import pyfftw
|
|
from numpy.fft import *
|
|
import pyfftw
|
|
|
|
import zipfile as zp
|
|
import os
|
|
import warnings
|
|
|
|
def readraw(filename):
|
|
scanx = int(filename.rstrip('.raw').split('_')[-1].lstrip('abcdefghijklmnopqrstuvwxyz'))
|
|
scany = int(filename.rstrip('.raw').split('_')[-2].lstrip('abcdefghijklmnopqrstuvwxyz'))
|
|
contents = np.fromfile(filename, dtype = 'float32')
|
|
data_arr = np.reshape(contents, (125, 125, scany, scanx), order = 'C')
|
|
return data_arr
|
|
|
|
##############################################################################################
|
|
def shift(input,dx,px,py):
|
|
N_image = input.shape[0]
|
|
|
|
dk= 1.0/(dx*N_image)
|
|
kx = np.linspace(-np.floor(N_image/2.0),np.ceil(N_image/2.0)-1,N_image)
|
|
[kX,kY] = np.meshgrid(kx,kx)
|
|
kX = kX*dk; kY = kY*dk;
|
|
|
|
f = np.fft.fftshift(np.fft.fft2(np.fft.ifftshift(input)))
|
|
f = f*np.exp(-2*np.pi*1j*px*kX)*np.exp(-2*np.pi*1j*py*kY)
|
|
f = np.fft.fftshift(np.fft.ifft2(np.fft.ifftshift(f)))
|
|
|
|
return f
|
|
|
|
##############################################################################################
|
|
def convertADUtoElectronCount(input, ADU_electronCount_ratio, directory = ""):
|
|
print("converting ADU to # of electrons:", ADU_electronCount_ratio)
|
|
output = input/ADU_electronCount_ratio
|
|
directory = directory + "_ADUtoElectron" + str(ADU_electronCount_ratio)
|
|
return output, directory
|
|
|
|
##############################################################################################
|
|
def partition_scan(N_scan_x, N_scan_y, partion_x, partion_y):
|
|
scan_partition = np.zeros((N_scan_y, N_scan_x), dtype=np.int)
|
|
delta_x = int(np.ceil(N_scan_x / partion_x))
|
|
delta_y = int(np.ceil(N_scan_y / partion_y))
|
|
value = 0
|
|
for i in xrange(partion_y):
|
|
for j in xrange(partion_x):
|
|
index_x_lb = delta_x*j
|
|
index_x_ub = min(delta_x*(j+1), N_scan_x)
|
|
index_y_lb = delta_y*i
|
|
index_y_ub = min(delta_y*(i+1), N_scan_y)
|
|
scan_partition[index_y_lb:index_y_ub,index_x_lb:index_x_ub] = value
|
|
value = value + 1
|
|
return scan_partition
|
|
|
|
##############################################################################################
|
|
def shift_cbed(input, px, py, directory = ""):
|
|
N_cbed = input.shape[0]
|
|
N_tot = N_cbed*N_cbed
|
|
dx = 1.0
|
|
dk= 1.0/(dx*N_cbed)
|
|
kx = np.linspace(-np.floor(N_cbed/2.0),np.ceil(N_cbed/2.0)-1,N_cbed)
|
|
kx = ifftshift(kx)
|
|
[kX,kY] = np.meshgrid(kx,kx)
|
|
kX = kX*dk; kY = kY*dk;
|
|
output = zeros(input.shape)
|
|
for i in range(input.shape[2]):
|
|
for j in range(input.shape[3]):
|
|
f = np.fft.fft2(input[:,:,i,j]);
|
|
f = f*exp(-2*pi*1j*px*kX)*exp(-2*pi*1j*py*kY)
|
|
output[:,:,i,j] = abs(np.fft.ifft2(f)); #fix normalization
|
|
directory = directory + "_shift_sx" + str(px)+"_sy" + str(py)
|
|
return output, directory
|
|
|
|
##############################################################################################
|
|
def lowpassfilter(input, dx,cutoff):
|
|
N = input.shape[0]
|
|
dk= 1.0/(dx*N)
|
|
kx = np.linspace(-np.floor(N/2.0),np.ceil(N/2.0)-1,N)
|
|
[kX,kY] = np.meshgrid(kx,kx)
|
|
kR = np.sqrt(kX**2 + kY**2)
|
|
|
|
a = np.fft.fftshift(np.fft.fft2(np.fft.ifftshift(input)))
|
|
a[kR>(N/2*cutoff)] = 0
|
|
output = np.fft.fftshift(np.fft.ifft2(np.fft.ifftshift(a)))
|
|
|
|
return output
|
|
|
|
##############################################################################################
|
|
def lowpassfilter_alpha(input, cutoff, dk_x, dk_y, alpha_max, voltage):
|
|
N = input.shape[0]
|
|
print("applying low pass filter to image")
|
|
print("mask cutoff =",cutoff ,'alpha')
|
|
kx = linspace(-floor(N/2.0),ceil(N/2.0)-1, N)
|
|
[kX,kY] = meshgrid(kx,kx)
|
|
kX = kX*dk_x; kY = kY*dk_y;
|
|
kR = np.sqrt(kX**2+ kY**2)
|
|
|
|
wavelength = 12.398/np.sqrt((2*511.0 + voltage) * voltage) #angstrom
|
|
|
|
k_cutoff = cutoff * alpha_max *1e-3 / wavelength
|
|
|
|
f = fftshift(fft2(ifftshift(input)))
|
|
f[kR > k_cutoff] = 0
|
|
output = real(fftshift(ifft2(ifftshift(f))))
|
|
|
|
return output
|
|
##############################################################################################
|
|
def propagtor_function(N, dk_x, dk_y,dz, wavelength):
|
|
kx = np.linspace(-np.floor(N/2.0),np.ceil(N/2.0)-1,N)
|
|
[kX,kY] = np.meshgrid(kx,kx)
|
|
kX = kX*dk_x; kY = kY*dk_y;
|
|
|
|
kR = np.sqrt(kX**2 + kY**2)
|
|
cutoff = (np.ceil(N/2.0)-1)*min(dk_x,dk_y)*2/3
|
|
|
|
P = zeros((dz.size,N,N), dtype=np.complex128)
|
|
for i in range(dz.size):
|
|
temp = np.exp(-1j*np.pi*wavelength*kR**2*dz[i])
|
|
temp[kR>cutoff] = 0 #apply a low pass filter to keep 2/3 of maximum spatial frequency
|
|
P[i,:,:] = ifftshift(temp)
|
|
|
|
'''
|
|
x = np.linspace(-np.floor(N/2.0),np.ceil(N/2.0)-1,N)*dx
|
|
[X,Y] = np.meshgrid(x,x)
|
|
R = np.sqrt(X**2 + Y**2)
|
|
p = 1/(1j*wavelength*dz)*np.exp(1j*np.pi/(wavelength*dz)*R**2)
|
|
'''
|
|
return P
|
|
|
|
##############################################################################################
|
|
def recenter(input):
|
|
N = input.shape[0]
|
|
center_index = N // 2
|
|
[yy,xx] = where(abs(input) == np.max(abs(input)))
|
|
|
|
output = roll(input,int(-(yy[0]-center_index)), axis = 0)
|
|
output = roll(output,int(-(xx[0]-center_index)), axis = 1)
|
|
|
|
return output
|
|
|
|
##############################################################################################
|
|
def upsample_cbed_ff(dp, dk_x, dk_y, resizeFactor = 2, directory = ""):
|
|
print("upsample cbed using free float ptychography")
|
|
print("old dk_x=", dk_x, "old dk_y=", dk_y)
|
|
|
|
#resize data
|
|
output = np.zeros((int(dp.shape[0]*resizeFactor), int(dp.shape[1]*resizeFactor), dp.shape[2], dp.shape[3]))
|
|
output[0:-1:resizeFactor,0:-1:resizeFactor,:,:] = dp
|
|
mask = np.ones((int(dp.shape[0]*resizeFactor), int(dp.shape[1]*resizeFactor)))
|
|
print(mask.shape)
|
|
mask[0:-1:2,0:-1:2] = 0
|
|
dk_x_r = dk_x/resizeFactor
|
|
dk_y_r = dk_y/resizeFactor
|
|
print("new dk_x=", dk_x_r, "new dk_y=", dk_y_r)
|
|
directory = directory + "_upsampleCBED" + str(resizeFactor)
|
|
#output[output<0] = 0
|
|
return output, mask, dk_x_r, dk_y_r, directory
|
|
|
|
|
|
##############################################################################################
|
|
def resize_cbed(dp, resizeFactor, dk_x, dk_y, directory = "", order = 1):
|
|
print("resize cbed")
|
|
print("old dk_x=", dk_x, "old dk_y=", dk_y)
|
|
|
|
#resize data
|
|
output = np.zeros((int(dp.shape[0]*resizeFactor),int(dp.shape[1]*resizeFactor),dp.shape[2],dp.shape[3]))
|
|
for i in range(0,dp.shape[2]):
|
|
for j in range(0,dp.shape[3]):
|
|
scipy.ndimage.interpolation.zoom(dp[:,:,i,j],[resizeFactor,resizeFactor],output[:,:,i,j], order)
|
|
dk_x_r = dk_x/resizeFactor
|
|
dk_y_r = dk_y/resizeFactor
|
|
print("new dk_x=", dk_x_r, "new dk_y=", dk_y_r)
|
|
directory = directory + "_resizeCBED" + str(resizeFactor)
|
|
#output[output<0] = 0
|
|
return output, dk_x_r, dk_y_r, directory
|
|
|
|
##############################################################################################
|
|
def resample_cbed(dp, Npix, dk_x, dk_y, directory = ""):
|
|
print("resample cbed using every ", str(Npix), 'pixels...')
|
|
print("old dk_x=", dk_x, "old dk_y=", dk_y)
|
|
output = dp[0:-1:Npix,0:-1:Npix,:,:]
|
|
if Npix>1: directory = directory + "_resampleCBED" + str(Npix)
|
|
dk_x_new = dk_x*Npix; dk_y_new = dk_y*Npix
|
|
print("new dk_x=", dk_x_new, "new dk_y=", dk_y_new)
|
|
return output, dk_x_new, dk_y_new, directory
|
|
|
|
##############################################################################################
|
|
def crop_cbed(dp, N_dp_x_new, N_dp_y_new, directory = ""):
|
|
print("crop cbed to ", str(N_dp_y_new), 'x', str(N_dp_x_new))
|
|
cen_x = floor(dp.shape[1]/2.0)
|
|
cen_y = floor(dp.shape[0]/2.0)
|
|
index_x_lb = (cen_x - floor(N_dp_x_new/2.0)).astype(np.int)
|
|
index_x_ub = (cen_x + ceil(N_dp_x_new/2.0)).astype(np.int)
|
|
index_y_lb = (cen_y - floor(N_dp_y_new/2.0)).astype(np.int)
|
|
index_y_ub = (cen_y + ceil(N_dp_y_new/2.0)).astype(np.int)
|
|
|
|
#crop data
|
|
output = np.zeros((N_dp_x_new, N_dp_y_new,dp.shape[2],dp.shape[3]))
|
|
for i in range(0,dp.shape[2]):
|
|
for j in range(0,dp.shape[3]):
|
|
output[:,:,i,j] = dp[index_y_lb:index_y_ub,index_x_lb:index_x_ub,i,j]
|
|
directory = directory + "_crop_Ndpx" + str(N_dp_x_new) + "_Ndpy" + str(N_dp_y_new)
|
|
return output, directory
|
|
|
|
##############################################################################################
|
|
def pad_cbed(input, N_pad_x, N_pad_y, value = 0, directory = ""):
|
|
print("pad " + str(value) + "s to cbed patterns...")
|
|
Ny = input.shape[0]; Nx = input.shape[1];
|
|
pad_pre_y = int(np.ceil((N_pad_y - Ny) / 2.0))
|
|
pad_post_y = int(np.floor((N_pad_y - Ny) / 2.0))
|
|
pad_pre_x = int(np.ceil((N_pad_x - Nx) / 2.0))
|
|
pad_post_x = int(np.floor((N_pad_x - Nx) / 2.0))
|
|
|
|
output = np.pad(input, ((pad_pre_y, pad_post_y), (pad_pre_x, pad_post_x), (0,0), (0,0)), 'constant', constant_values=value)
|
|
directory = directory + "_padCBED" + str(value) + "_" + str(N_pad_x)
|
|
return output, directory
|
|
|
|
##############################################################################################
|
|
def apply_circular_mask(input, radius, offset_x=0, offset_y=0, directory = ""):
|
|
N_dp = input.shape[0]
|
|
print("applying circullar mask to cbed")
|
|
print("mask radius =",radius)
|
|
print("mask offset_x =",offset_x, "mask offset_y =",offset_y)
|
|
|
|
x = np.linspace(-np.floor(N_dp/2.0),np.ceil(N_dp/2.0)-1,N_dp)
|
|
[X,Y] = np.meshgrid(x,x)
|
|
mask_disk = np.sqrt(X**2+ Y**2)
|
|
|
|
output = input.copy()
|
|
|
|
for i in range(input.shape[2]):
|
|
for j in range(input.shape[3]):
|
|
temp = input[:,:,i,j].copy()
|
|
temp = np.roll(temp, offset_y, axis=0)
|
|
temp = np.roll(temp, offset_x, axis=1)
|
|
if radius>0:
|
|
temp[mask_disk>radius] = 0
|
|
output[:,:,i,j] = temp.copy()
|
|
if radius>0: directory = directory + "_lowPassFilter" + str(radius)
|
|
if offset_x!= 0: directory = directory + "_sx" + str(offset_x)
|
|
if offset_y!= 0: directory = directory + "_sy" + str(offset_y)
|
|
|
|
return output, directory, mask_disk
|
|
|
|
##############################################################################################
|
|
def apply_circular_mask_alpha(dp, cutoff, dk_x, dk_y, alpha_max, voltage, offset_x=0, offset_y=0, directory = ""):
|
|
if cutoff>0:
|
|
N_dp = dp.shape[0]
|
|
print("applying circullar mask to cbed")
|
|
print("mask cutoff =",cutoff ,'alpha')
|
|
print("mask offset_x =",offset_x, "mask offset_y =",offset_y)
|
|
kx = linspace(-floor(N_dp/2.0),ceil(N_dp/2.0)-1, N_dp)
|
|
|
|
[kX,kY] = meshgrid(kx,kx)
|
|
kX = kX*dk_x; kY = kY*dk_y;
|
|
kR = np.sqrt(kX**2+ kY**2)
|
|
|
|
wavelength = 12.398/np.sqrt((2*511.0 + voltage) * voltage) #angstrom
|
|
|
|
k_cutoff = cutoff * alpha_max *1e-3 / wavelength
|
|
output = dp.copy()
|
|
for i in range(dp.shape[2]):
|
|
for j in range(dp.shape[3]):
|
|
temp = dp[:,:,i,j].copy()
|
|
temp = np.roll(temp, offset_y, axis=0)
|
|
temp = np.roll(temp, offset_x, axis=1)
|
|
#np.roll(dp[:,:,i,j], offset_y, axis=0)
|
|
#np.roll(dp[:,:,i,j], offset_x, axis=1)
|
|
if cutoff > 0:
|
|
#dp[kR > k_cutoff,i,j]= 0
|
|
temp[kR > k_cutoff] = 0
|
|
output[:,:,i,j] = temp.copy()
|
|
directory = directory + "_cutoff" + str(cutoff)+"alpha"
|
|
if offset_x!= 0: directory = directory + "_sx" + str(offset_x)
|
|
if offset_y!= 0: directory = directory + "_sy" + str(offset_y)
|
|
|
|
return output, directory
|
|
##############################################################################################
|
|
def add_poisson_noise(input, current, readOutTime, directory = ""):
|
|
N_dp_tot = input.shape[0] * input.shape[1]
|
|
print("applying poisson noise to cbed")
|
|
print("beam current =", current, 'pA')
|
|
Nc_avg = current*1e-12*readOutTime/(1.6e-19)/N_dp_tot
|
|
print("average count per pixel = ", Nc_avg)
|
|
print("snr = ", sqrt(Nc_avg))
|
|
|
|
output = input.copy()
|
|
snr = zeros((input.shape[2],input.shape[3]))
|
|
for i in range(input.shape[2]):
|
|
for j in range(input.shape[3]):
|
|
cbed_noise = input[:,:,i,j].copy()
|
|
cbed_noise = cbed_noise/np.sum(input[:,:,i,j])*(N_dp_tot*Nc_avg*1.0)
|
|
cbed_noise = random.poisson(cbed_noise)
|
|
cbed_noise = cbed_noise*np.sum(input[:,:,i,j])/(N_dp_tot*Nc_avg*1.0)
|
|
output[:,:,i,j] = cbed_noise
|
|
snr[i,j] = np.mean(input[:,:,i,j])/np.std(input[:,:,i,j] - cbed_noise)
|
|
directory = directory + "_poissonNoise" + str(current) + "pA"
|
|
return output, snr, directory
|
|
|
|
##############################################################################################
|
|
def average_cbed(input, windowSize, scanStepSize_x, scanStepSize_y, directory = ""):
|
|
print("average cbed patterns... window size =",windowSize)
|
|
|
|
if windowSize==1:
|
|
output = input
|
|
else:
|
|
output = zeros((input.shape[0],input.shape[1],input.shape[2]//windowSize,input.shape[3]//windowSize))
|
|
for i in range(output.shape[2]):
|
|
for j in range(output.shape[3]):
|
|
temp = np.sum(input[:,:,i*windowSize:(i+1)*windowSize,j*windowSize:(j+1)*windowSize], axis=(2,3))/windowSize**2
|
|
output[:,:,i,j] = temp.copy()
|
|
directory = directory + "_averageCBED"+str(windowSize)
|
|
scanStepSize_x = scanStepSize_x * windowSize
|
|
scanStepSize_y = scanStepSize_y * windowSize
|
|
|
|
return output, scanStepSize_x, scanStepSize_y, directory
|
|
|
|
##############################################################################################
|
|
def resample_scan(input, windowSize, scanStepSize_x, scanStepSize_y, directory = ""):
|
|
print("resample scans ... window size =",windowSize)
|
|
|
|
if windowSize==1:
|
|
output = input
|
|
else:
|
|
output = input[:,:,::windowSize,::windowSize]
|
|
|
|
scanStepSize_x = scanStepSize_x * windowSize
|
|
scanStepSize_y = scanStepSize_y * windowSize
|
|
|
|
directory = directory + "_resampleScan"+str(windowSize)
|
|
|
|
return output, scanStepSize_x, scanStepSize_y, directory
|
|
|
|
##############################################################################################
|
|
def transpose_cbed(input, directory = ""):
|
|
print("transpose cbed patterns")
|
|
output = zeros((input.shape[1],input.shape[0],input.shape[2],input.shape[3]))
|
|
|
|
for i in range(input.shape[2]):
|
|
for j in range(input.shape[3]):
|
|
output[:,:,i,j] = input[:,:,i,j].T
|
|
directory = directory + "_transpose"
|
|
return output, directory
|
|
|
|
##############################################################################################
|
|
def rot90_cbed(input, k, directory = ""):
|
|
print("rotate cbed patterns by", 90*k, "degrees...")
|
|
output = zeros((input.shape[1],input.shape[0],input.shape[2],input.shape[3]))
|
|
for i in range(input.shape[2]):
|
|
for j in range(input.shape[3]):
|
|
output[:,:,i,j] = rot90(input[:,:,i,j], k)
|
|
directory = directory + "_rotate90_"+str(k)
|
|
return output, directory
|
|
|
|
##############################################################################################
|
|
def transpose_scan_positions(input, directory = ""):
|
|
print("transpose scan positions...")
|
|
output = zeros((input.shape[0],input.shape[1],input.shape[3],input.shape[2]))
|
|
|
|
for i in range(output.shape[2]):
|
|
for j in range(output.shape[3]):
|
|
output[:,:,i,j] = input[:,:,j,i]
|
|
|
|
directory = directory + "_transposeScanPos"
|
|
return output, directory
|
|
|
|
##############################################################################################
|
|
def flip_scan_positions(input, flipType, directory = ""):
|
|
assert flipType in ['lr','ud'], "Flip type %s not known!" % flipType
|
|
if flipType=="ud":
|
|
print("flip scan positions up and down (y-axis, third dimension)")
|
|
output = input[:,:,::-1,:]
|
|
if flipType=="lr":
|
|
print("flip scan positions left and right (x-axis, forth dimension)")
|
|
output = input[:,:,:,::-1]
|
|
|
|
directory = directory + "_flipScanPos_" + flipType
|
|
return output, directory
|
|
##############################################################################################
|
|
def normalize_wave_function(input, dx):
|
|
output = input.copy()
|
|
c = sqrt( 1.0/ ( np.sum(np.abs(input)**2 * dx**2 ) ))
|
|
output = output * c
|
|
return output
|
|
|
|
##############################################################################################
|
|
def normalize_cbed(input, dk, directory = ""):
|
|
print("normalizing cbed patterns: sum(dp) = 1")
|
|
|
|
for i in range(input.shape[2]):
|
|
for j in range(input.shape[3]):
|
|
c = 1.0/(sum(abs(input[:,:,i,j])))
|
|
input[:,:,i,j] = input[:,:,i,j] * c
|
|
directory = directory + "_normCBED"
|
|
return input, directory
|
|
|
|
##############################################################################################
|
|
def background_removal(input, bg_level, directory = ""):
|
|
print("removing background: threshold=", bg_level)
|
|
output = input.copy()
|
|
output[output<=bg_level] = 0
|
|
directory = directory + "_bgRemoval"+str(bg_level)
|
|
return output, directory
|
|
|
|
##############################################################################################
|
|
def background_subtraction(input, bg_level, directory = ""):
|
|
print("subtracting background: threshold=", bg_level)
|
|
|
|
output = input - bg_level
|
|
output[output<0] = 0
|
|
|
|
directory = directory + "_bgSubtraction"+str(bg_level)
|
|
return output, directory
|
|
|
|
##############################################################################################
|
|
def calculate_scan_positions(N_scan_x, N_scan_y, scanStepSize_x, scanStepSize_y, rot_angle_d = 0, directory = "", randomOffset = 0, ppX = 0, ppY = 0):
|
|
print("calculate scan positions")
|
|
print("N_scan_x =", N_scan_x, "scanStepSize_x =", scanStepSize_x)
|
|
print("N_scan_y =", N_scan_y, "scanStepSize_y =", scanStepSize_y)
|
|
print("rot_angle =", rot_angle_d)
|
|
rot_angle = rot_angle_d*pi/180.0
|
|
|
|
ppx = linspace(-floor(N_scan_x/2.0),ceil(N_scan_x/2.0)-1,N_scan_x)*scanStepSize_x
|
|
ppy = linspace(-floor(N_scan_y/2.0),ceil(N_scan_y/2.0)-1,N_scan_y)*scanStepSize_y
|
|
[ppX0, ppY0] = meshgrid(ppx,ppy)
|
|
if not isscalar(ppX): ppX0 = ppX
|
|
if not isscalar(ppY): ppY0 = ppY
|
|
|
|
if randomOffset > 0:
|
|
ppX0 = ppX0 + (np.random.rand(ppX0.shape[0], ppX0.shape[1])*2-1)*scanStepSize_x*randomOffset
|
|
ppY0 = ppY0 + (np.random.rand(ppY0.shape[0], ppY0.shape[1])*2-1)*scanStepSize_y*randomOffset
|
|
|
|
ppY_rot = ppX0*-sin(rot_angle) + ppY0*cos(rot_angle)
|
|
ppX_rot = ppX0*cos(rot_angle) + ppY0*sin(rot_angle)
|
|
|
|
directory = directory + "/scanStepSize" + str(np.around(scanStepSize_x,4)) + "_rotAngle"+str(rot_angle_d)
|
|
if randomOffset>0: directory = directory + "_randomOffset" + str(randomOffset)
|
|
if not isscalar(ppX) or not isscalar(ppY): directory = directory + "_externalCoord"
|
|
|
|
return ppX_rot, ppY_rot, directory
|
|
|
|
##############################################################################################
|
|
def gaussian(N, sigma):
|
|
x = linspace(-floor(N/2.0),ceil(N/2.0)-1, N)
|
|
|
|
[X,Y] = meshgrid(x,x)
|
|
g = exp(-(X**2+Y**2)/(2*sigma**2)) + np.zeros((N,N), dtype=np.complex128)
|
|
return g
|
|
|
|
##############################################################################################
|
|
def guess_bad_scan(I, threshold):
|
|
print('Determining bad scans')
|
|
|
|
I_pad = np.lib.pad(I, (1, 1), 'edge')
|
|
# calculate standard deviation in a 3 x 3 window
|
|
averageI2 = scipy.ndimage.filters.uniform_filter(I_pad ** 2)
|
|
averageI = scipy.ndimage.filters.uniform_filter(I_pad)
|
|
std = np.sqrt(abs(averageI2 - averageI**2))[1:-1, 1:-1]
|
|
|
|
medianI = scipy.ndimage.filters.median_filter(I_pad, 2)[1:-1, 1:-1]
|
|
|
|
return abs(I - medianI) > std * threshold
|
|
|