def sample_image_dribinski(n=361, origin=None): """ Sample test image used in the BASEX paper Rev. Sci. Instrum. 73, 2634 (2002) 9x Gaussian functions of half-width 4 pixel + 1 background width 3600 - anisotropy - ß = -1 for cosθ term - ß = +2 for sinθ term - ß = 0 isotropic, no angular variation (there are some missing negative exponents in the publication) Parameters ---------- - n: integer (square) image width (height) - origin: tuple, (row, col) center of image Returns ------- - IM: 2D n x n numpy array image """ def Gauss(r, r0, sigma2): return np.exp(-(r - r0)**2 / sigma2) def I(r, theta): # intensity function Eq. (16) t0 = 7 * Gauss(r, 10, 4) * np.sin(theta)**2 t1 = 3 * Gauss(r, 15, 4) t2 = 5 * Gauss(r, 20, 4) * np.cos(theta)**2 t3 = Gauss(r, 70, 4) t4 = 2 * Gauss(r, 85, 4) * np.cos(theta)**2 t5 = Gauss(r, 100, 4) * np.sin(theta)**2 t6 = 2 * Gauss(r, 145, 4) * np.sin(theta)**2 t7 = Gauss(r, 150, 4) t8 = 3 * Gauss(r, 155, 4) * np.cos(theta)**2 t9 = 20 * Gauss(r, 45, 3600) # background under t3 to t5 return 2000 * (t0 + t1 + t2) + 200 * (t3 + t4 + t5) + 50 * (t6 + t7 + t8) + t9 # meshgrid @DanHickstein issue #67 x = np.arange(n) n2 = n // 2 + n % 2 X, Y = np.meshgrid(x - n2, x - n2) R, THETA = cart2polar(X, Y) IM = I(R, THETA) return IM
def sample_image_dribinski(n=361, origin=None): """ Sample test image used in the BASEX paper Rev. Sci. Instrum. 73, 2634 (2002) 9x Gaussian functions of half-width 4 pixel + 1 background width 3600 - anisotropy - ß = -1 for cosθ term - ß = +2 for sinθ term - ß = 0 isotropic, no angular variation (there are some missing negative exponents in the publication) Parameters ---------- - n: integer (square) image width (height) - origin: tuple, (row, col) center of image Returns ------- - IM: 2D n x n numpy array image """ def Gauss (r, r0, sigma2): return np.exp(-(r-r0)**2/sigma2) def I(r, theta): # intensity function Eq. (16) t0 = 7*Gauss(r, 10, 4)*np.sin(theta)**2 t1 = 3*Gauss(r, 15, 4) t2 = 5*Gauss(r, 20, 4)*np.cos(theta)**2 t3 = Gauss(r, 70, 4) t4 = 2*Gauss(r, 85, 4)*np.cos(theta)**2 t5 = Gauss(r, 100, 4)*np.sin(theta)**2 t6 = 2*Gauss(r, 145, 4)*np.sin(theta)**2 t7 = Gauss(r, 150, 4) t8 = 3*Gauss(r, 155, 4)*np.cos(theta)**2 t9 = 20*Gauss(r, 45, 3600) # background under t3 to t5 return 2000*(t0+t1+t2) + 200*(t3+t4+t5) + 50*(t6+t7+t8) + t9 # meshgrid @DanHickstein issue #67 x = np.arange(n) n2 = n//2 + n%2 X, Y = np.meshgrid(x-n2, x-n2) R, THETA = cart2polar(X, Y) IM = I(R, THETA) return IM
def sample_image(n=361, name="dribinski", sigma=2, temperature=200): """ Sample images, made up of Gaussian functions Parameters ---------- n : integer image size n rows x n cols name : str one of "dribinski" or "Ominus" sigma : float Gaussian 1/e width (pixels) temperature : float for 'Ominus' only anion levels have Boltzmann population weight (2J+1) exp(-177.1 h c 100/k/temperature) Returns ------- IM : 2D np.array image """ def gauss(r, r0, sigma): return np.exp(-(r-r0)**2/sigma**2) def dribinski(r, theta, sigma): # intensity function Eq. (16) """ Sample test image used in the BASEX paper Rev. Sci. Instrum. 73, 2634 (2002) 9x Gaussian functions of half-width 4 pixel + 1 background width 3600 anisotropy - ß = -1 for cosθ term - ß = +2 for sinθ term - ß = 0 isotropic, no angular variation (there are some missing negative exponents in the publication) """ sinetheta2 = np.sin(theta)**2 cosinetheta2 = np.cos(theta)**2 t0 = 7*gauss(r, 10, sigma)*sinetheta2 t1 = 3*gauss(r, 15, sigma) t2 = 5*gauss(r, 20, sigma)*cosinetheta2 t3 = gauss(r, 70, sigma) t4 = 2*gauss(r, 85, sigma)*cosinetheta2 t5 = gauss(r, 100, sigma)*sinetheta2 t6 = 2*gauss(r, 145, sigma)*sinetheta2 t7 = gauss(r, 150, sigma) t8 = 3*gauss(r, 155, sigma)*cosinetheta2 t9 = 20*gauss(r, 45, 3600) # background under t3 to t5 return 2000*(t0+t1+t2) + 200*(t3+t4+t5) + 50*(t6+t7+t8) + t9 def Ominus(r, theta, sigma, boltzmann, rfact=1): """ Simulate the photoelectron spectrum of O- photodetachment 3PJ <- 2P3/2,1/2 6 transitions, triplet neutral, and doublet anion """ # positions based on 812.5 nm ANU O- PES t1 = gauss(r, 341*rfact, sigma) # 3P2 <- 2P3/2 t2 = gauss(r, 285*rfact, sigma) # 3P1 <- 2P3/2 t3 = gauss(r, 257*rfact, sigma) # 3P0 <- 2P3/2 t4 = gauss(r, 394*rfact, sigma) # 3P2 <- 2P1/2 t5 = gauss(r, 348*rfact, sigma) # 3P1 <- 2P1/2 t6 = gauss(r, 324*rfact, sigma) # 3P0 <- 2P1/2 # intensities = fine-structure known ratios # 2P1/2 transtions scaled by temperature dependent Boltzmann factor t = t1 + 0.8*t2 + 0.36*t3 + (0.2*t4 + 0.36*t5 + 0.16*t6)*boltzmann # anisotropy sinetheta2 = np.sin(theta)**2*0.2 + 0.8 return t*sinetheta2 n2 = n//2 x = np.linspace(-n2, n2, n) if name=='dribinski': x = x * 180/n2 elif name=='Ominus': x = x * 501/n2 X, Y = np.meshgrid(x, x) R, THETA = cart2polar(X, Y) if name == "dribinski": IM = dribinski(R, THETA, sigma=sigma) elif name == "Ominus": boltzmann = 0.5*np.exp(-177.1*const.h*const.c*100/const.k/temperature) IM = Ominus(R, THETA, sigma=sigma, boltzmann=boltzmann) else: raise ValueError('sample image name not recognized') return IM
def reproject_image_into_polar(data, origin=None, Jacobian=False, dr=1, dt=None, log=False): """ Reprojects a 2D numpy array (``data``) into a polar coordinate system. "origin" is a tuple of (x0, y0) relative to the bottom-left image corner, and defaults to the center of the image. Parameters ---------- data : 2D np.array origin : tuple The coordinate of the image center, relative to bottom-left Jacobian : boolean Include ``r`` intensity scaling in the coordinate transform. This should be included to account for the changing pixel size that occurs during the transform. dr : float Radial coordinate spacing for the grid interpolation tests show that there is not much point in going below 0.5 dt : float Angular coordinate spacing (in radians) if ``dt=None``, dt will be set such that the number of theta values is equal to the maximum value between the height or the width of the image. Returns ------- output : 2D np.array The polar image (r, theta) r_grid : 2D np.array meshgrid of radial coordinates theta_grid : 2D np.array meshgrid of theta coordinates Notes ----- Adapted from: http://stackoverflow.com/questions/3798333/image-information-along-a-polar-coordinate-system """ # bottom-left coordinate system requires numpy image to be np.flipud data = np.flipud(data) ny, nx = data.shape[:2] if origin is None: origin = (nx // 2, ny // 2) # Determine that the min and max r and theta coords will be... x, y = index_coords(data, origin=origin) # (x,y) coordinates of each pixel r, theta = cart2polar(x, y) # convert (x,y) -> (r,θ), note θ=0 is vertical nr = np.int(np.ceil((r.max() - r.min()) / dr)) if dt is None: nt = max(nx, ny) else: # dt in radians nt = np.int(np.ceil((theta.max() - theta.min()) / dt)) # Make a regular (in polar space) grid based on the min and max r & theta if log: r_i = np.logspace(np.log10(r.min() + 1), np.log10(r.max()), nr, endpoint=False) else: r_i = np.linspace(r.min(), r.max(), nr, endpoint=False) theta_i = np.linspace(theta.min(), theta.max(), nt, endpoint=False) theta_grid, r_grid = np.meshgrid(theta_i, r_i) # Project the r and theta grid back into pixel coordinates X, Y = polar2cart(r_grid, theta_grid) X += origin[0] # We need to shift the origin Y += origin[1] # back to the bottom-left corner... xi, yi = X.flatten(), Y.flatten() coords = np.vstack((yi, xi)) # (map_coordinates requires a 2xn array) zi = map_coordinates(data, coords) output = zi.reshape((nr, nt)) if Jacobian: output = output * r_i[:, np.newaxis] return output, r_grid, theta_grid