def test_copy_axes_manager(self): s = self.s s_new = Signal2D(np.zeros((50, 50))) pst._copy_signal2d_axes_manager_metadata(s, s_new) sa_ori = s.axes_manager.signal_axes sa_new = s_new.axes_manager.signal_axes assert sa_ori[0].offset == sa_new[0].offset assert sa_ori[1].offset == sa_new[1].offset assert sa_ori[0].scale == sa_new[0].scale assert sa_ori[1].scale == sa_new[1].scale assert sa_ori[0].name == sa_new[0].name assert sa_ori[1].name == sa_new[1].name assert sa_ori[0].units == sa_new[0].units assert sa_ori[1].units == sa_new[1].units
def get_phase_signal(self, rotation=None): """Get DPC phase image visualized using continuous color scale. Converts the x and y beam shifts into an RGB array, showing the direction of the beam shifts. Useful for visualizing magnetic domain structures. Parameters ---------- rotation : float, optional In degrees. Useful for correcting the mismatch between scan direction and diffraction pattern rotation. autolim : bool, default True autolim_sigma : float, default 4 Returns ------- phase_signal : HyperSpy 2D RGB signal Examples -------- >>> s = pxm.dummy_data.get_simple_dpc_signal() >>> s_color = s.get_phase_signal(rotation=20) >>> s_color.plot() See Also -------- get_color_signal : Signal showing both phase and magnitude get_magnitude_signal : Signal showing the magnitude """ # Rotate the phase by -30 degrees in the color "wheel", to get better # visualization in the vertical and horizontal direction. if rotation is None: rotation = -30 else: rotation = rotation - 30 phase = np.arctan2(self.inav[0].data, self.inav[1].data) % (2 * np.pi) rgb_array = pst._get_rgb_phase_array(phase=phase, rotation=rotation) signal_rgb = Signal1D(rgb_array * (2 ** 16 - 1)) signal_rgb.change_dtype("uint16") signal_rgb.change_dtype("rgb16") pst._copy_signal2d_axes_manager_metadata(self, signal_rgb) return signal_rgb
def get_magnitude_signal(self, autolim=True, autolim_sigma=4): """Get DPC magnitude image visualized as greyscale. Converts the x and y beam shifts into a magnitude map, showing the magnitude of the beam shifts. Useful for visualizing magnetic domain structures. Parameters ---------- autolim : bool, default True autolim_sigma : float, default 4 Returns ------- magnitude_signal : HyperSpy 2D signal Examples -------- >>> s = pxm.dummy_data.get_simple_dpc_signal() >>> s_magnitude = s.get_magnitude_signal() >>> s_magnitude.plot() See Also -------- get_color_signal : Signal showing both phase and magnitude get_phase_signal : Signal showing the phase """ inav02 = np.abs(self.inav[0].data)**2 inav12 = np.abs(self.inav[1].data)**2 magnitude = np.sqrt(inav02 + inav12) magnitude_limits = None if autolim: magnitude_limits = pst._get_limits_from_array(magnitude, sigma=autolim_sigma) np.clip(magnitude, magnitude_limits[0], magnitude_limits[1], out=magnitude) signal = Signal2D(magnitude) pst._copy_signal2d_axes_manager_metadata(self, signal) return signal
def phase_retrieval(self, method="kottler", mirroring=False, mirror_flip=False): """Retrieve the phase from two orthogonal phase gradients. Parameters ---------- method : 'kottler', 'arnison' or 'frankot', optional the formula to use, 'kottler'[1], 'arnison'[2] and 'frankot'[3] are available. The default is 'kottler'. mirroring : bool, optional whether to mirror the phase gradients before Fourier transformed. Attempt to reduce boundary effect. The default is False. mirror_flip : bool, optional only active when 'mirroring' is True. Flip the direction of the derivatives which results in negation during signal mirroring. The default is False. If the retrieved phase is not sensible after mirroring, set this to True may resolve it. Raises ------ ValueError if the method is not implemented Returns ------- signal : HyperSpy 2D signal the phase retrieved. References ---------- .. [1] Kottler, C., David, C., Pfeiffer, F. and Bunk, O., 2007. A two-directional approach for grating based differential phase contrast imaging using hard x-rays. Optics Express, 15(3), p.1175. (Equation 4) .. [2] Arnison, M., Larkin, K., Sheppard, C., Smith, N. and Cogswell, C., 2004. Linear phase imaging using differential interference contrast microscopy. Journal of Microscopy, 214(1), pp.7-12. (Equation 6) .. [3] Frankot, R. and Chellappa, R., 1988. A method for enforcing integrability in shape from shading algorithms. IEEE Transactions on Pattern Analysis and Machine Intelligence, 10(4), pp.439-451. (Equation 21) Examples -------- >>> s = pxm.dummy_data.get_square_dpc_signal() >>> s_phase = s.phase_retrieval() >>> s_phase.plot() """ method = method.lower() if method not in ("kottler", "arnison", "frankot"): raise ValueError( "Method '{}' not recognised. 'kottler', 'arnison'" " and 'frankot' are available.".format(method) ) # get x and y phase gradient dx = self.inav[0].data dy = self.inav[1].data # attempt to reduce boundary effect if mirroring: Ax = dx Bx = np.flip(dx, axis=1) Cx = np.flip(dx, axis=0) Dx = np.flip(dx) Ay = dy By = np.flip(dy, axis=1) Cy = np.flip(dy, axis=0) Dy = np.flip(dy) # the -ve depends on the direction of derivatives if not mirror_flip: dx = np.bmat([[Ax, -Bx], [Cx, -Dx]]).A dy = np.bmat([[Ay, By], [-Cy, -Dy]]).A else: dx = np.bmat([[Ax, Bx], [-Cx, -Dx]]).A dy = np.bmat([[Ay, -By], [Cy, -Dy]]).A nc, nr = dx.shape[1], dx.shape[0] # get scan step size calX = np.diff(self.axes_manager.signal_axes[0].axis).mean() calY = np.diff(self.axes_manager.signal_axes[1].axis).mean() # construct Fourier-space grids kx = (2 * np.pi) * np.fft.fftshift(np.fft.fftfreq(nc)) ky = (2 * np.pi) * np.fft.fftshift(np.fft.fftfreq(nr)) kx_grid, ky_grid = np.meshgrid(kx, ky) if method == "kottler": gxy = dx + 1j * dy numerator = np.fft.fftshift(np.fft.fft2(gxy)) denominator = 2 * np.pi * 1j * (kx_grid + 1j * ky_grid) elif method == "arnison": gxy = dx + 1j * dy numerator = np.fft.fftshift(np.fft.fft2(gxy)) denominator = 2j * ( np.sin(2 * np.pi * calX * kx_grid) + 1j * np.sin(2 * np.pi * calY * ky_grid) ) elif method == "frankot": kx_grid /= calX ky_grid /= calY fx = np.fft.fftshift(np.fft.fft2(dx)) fy = np.fft.fftshift(np.fft.fft2(dy)) # weights in x,y directins, currently hardcoded, but easy to extend if required wx, wy = 0.5, 0.5 numerator = -1j * (wx * kx_grid * fx + wy * ky_grid * fy) denominator = wx * kx_grid ** 2 + wy * ky_grid ** 2 # handle the division by zero in the central pixel # set the undefined/infinity pixel to 0 with np.errstate(divide="ignore", invalid="ignore"): res = numerator / denominator res = np.nan_to_num(res, nan=0, posinf=0, neginf=0) retrieved = np.fft.ifft2(np.fft.ifftshift(res)).real # get 1/4 of the result if mirroring if mirroring: M, N = retrieved.shape retrieved = retrieved[: M // 2, : N // 2] signal = Signal2D(retrieved) pst._copy_signal2d_axes_manager_metadata(self, signal) return signal