def crop_cardboard(self, model): # Performs the crop mat = np.array(self.raw_scan.resize((1024, 688))) mat = mat.reshape(1, 688, 1024, 3) mat = mat.astype(np.uint8) prediction = model.gen_prediction(mat)[0] full_size_image = np.asarray(self.raw_scan.resize((2048, 1376))) self.p, self.prediction, self.angle, self.center_x, self.center_y = unwarp.get_uwrap( prediction) self.prediction = map_coordinates(self.prediction, warp_coords(self.transform, self.prediction.shape), order=1, prefilter=False) # rotate it here full_size_image = unwarp.rorate_image(full_size_image, self.angle) self.warped_image = map_coordinates(full_size_image, warp_coords( self.transform, full_size_image.shape), order=1, prefilter=False) rect = cv2.minAreaRect(np.argwhere(self.prediction > 0)) self.cropped_cardboard = self.crop_minAreaRect(self.warped_image, rect)
def test_fast_homography(): img = rgb2gray(data.lena()).astype(np.uint8) img = img[:, :100] theta = np.deg2rad(30) scale = 0.5 tx, ty = 50, 50 H = np.eye(3) S = scale * np.sin(theta) C = scale * np.cos(theta) H[:2, :2] = [[C, -S], [S, C]] H[:2, 2] = [tx, ty] tform = ProjectiveTransform(H) coords = warp_coords(tform.inverse, (img.shape[0], img.shape[1])) for order in range(4): for mode in ('constant', 'reflect', 'wrap', 'nearest'): p0 = map_coordinates(img, coords, mode=mode, order=order) p1 = warp(img, tform, mode=mode, order=order) # import matplotlib.pyplot as plt # f, (ax0, ax1, ax2, ax3) = plt.subplots(1, 4) # ax0.imshow(img) # ax1.imshow(p0, cmap=plt.cm.gray) # ax2.imshow(p1, cmap=plt.cm.gray) # ax3.imshow(np.abs(p0 - p1), cmap=plt.cm.gray) # plt.show() d = np.mean(np.abs(p0 - p1)) assert d < 0.001
def get_rot_coordinates(R, shape): """ image rotation coordinates calculation with affine matrix R Parameters ---------- R : affine matrix 3x3 shape : image_shape Returns ------- coords_index : coordinate_index with order = 'C' idx_valid : valid index """ inverse_map = ProjectiveTransform(matrix=R) coords = warp_coords(inverse_map, shape) xs = coords[0].flatten().astype('int') ys = coords[1].flatten().astype('int') a = np.all(np.vstack((xs >= 0, xs < shape[1], ys >= 0, ys < shape[0])), axis=0) idx_valid = np.where(a)[0] coords_index = np.nan * np.ones((np.prod(shape), )) coords_index[idx_valid] = 1 coords_index[idx_valid] = np.ravel_multi_index( (xs[idx_valid], ys[idx_valid]), shape) coords_index = np.reshape(coords_index, shape) return coords_index, idx_valid
def _get_warped_image(is_left, single_photo, depth_map, distortion_rate): image = np.array(single_photo) shifted = _get_shifted_coords2(depth_map, is_left, distortion_rate) def shift_function(xy): return shifted coords = warp_coords(shift_function, image.shape) warped_image = map_coordinates(image, coords, prefilter=False) return warped_image
def align_by_offset(Image, shift_x, shift_y, splitstyle="hsplit", shift_channel=1): """ This function shifts one channel of the array based supplied offset values. Retains the single image structure. :param Image: 2D image array :param shift_x: float, offset in x :param shift_y: float, offset in y :param splitstyle: string, passed to ``im_split``; accepts "hsplit", "vsplit". Default is "hsplit" :param shift_channel: int, which channel to shift by offsets, default is channel 1. :return: 2D image array of aligned image :Example: >>> from smtools.alignment import find_global_offset, align_by_offset >>> import smtools.testdata as test >>> import matplotlib.pyplot as plt >>> im = test.image_stack() >>> dx, dy = find_global_offset(im) >>> new_image = align_by_offset(im[0], dx, dy) >>> plt.imshow(new_image), plt.show() """ ch1, ch2 = im_split(Image, splitstyle) if shift_channel == 1: new_coords = warp_coords(lambda xy: xy - np.array([shift_x, shift_y]), ch2.shape) warped_channel = map_coordinates(ch2, new_coords) aligned_image = np.concatenate((ch1, warped_channel), axis=1) else: new_coords = warp_coords(lambda xy: xy + np.array([shift_x, shift_y]), ch1.shape) warped_channel = map_coordinates(ch1, new_coords) aligned_image = np.concatenate((warped_channel, ch2), axis=1) return aligned_image
def face_warp_coord(src_face, src_face_lm, dst_face_lm, tri, bg, warp_only=False, use_bg=True): """ Function takes two faces and landmarks and warp one face around another according to the face landmarks. script modified from https://github.com/marsbroshok/face-replace/blob/master/faceWarp.py :param src_face: grayscale (?) image (np.array of int) of face which will warped around second face :param src_face_lm: landmarks for the src_face :param dst_face: predicted image landmarks (np.array of int) which will be replaced by src_face. :param bg: image background :return: image with warped face """ src_face_coord = src_face_lm dst_face_coord = dst_face_lm affines = [] # find affine mapping from source positions to destination for k in tri: affine = AffineTransform() affine.estimate(src_face_coord[k, :], dst_face_coord[k, :]) affines.append(affine) inverse_affines = [] # find the inverse affine mapping for k in tri: affine = AffineTransform() affine.estimate(dst_face_coord[k, :], src_face_coord[k, :]) inverse_affines.append(affine) coords = warp_coords(coord_map, src_face.shape) warped_face = map_coordinates(src_face, coords) if not warp_only: if use_bg: warped_face = _merge_images(warped_face, bg) else: warped_face = _merge_images(warped_face, src_face) return warped_face
def __init__(self, input_shape, angles, radial_positions, radii, n_steps=5, min_blur=.5): """ :param input_shape: (height, width) of input images :param angles: list of angles of receptive field centres :param radial_positions: list of radial positions of receptive field centres (pixels from image centre) :param radii: list of radii of receptive fields; same length as radial_positions, as radius is mainly a function of eccentricity :param n_steps: receptive fields of various sizes are approximated in discrete steps by sampling from copies of the image with different degrees of blur; this is the number of different blurred images created; a larger number will result in less quantization error in the RF size, and longer run time :param min_blur: sigma of Gaussian blur of the sharpest image; some blur is needed to avoid moire due to aliasing """ self.radial_positions = radial_positions self.radii = radii blurs = np.linspace(np.min(radii), np.max(radii), n_steps) blurs = np.maximum(min_blur, blurs) self.blurs = list(set(blurs)) self.blurs.sort() self.sigmas = [blurs[0]] for i in range(1,len(blurs)): self.sigmas.append(np.sqrt(blurs[i]**2 - blurs[i-1]**2)) # find index of blur stage closest to blur wanted at each radius self.blur_indices = np.interp(radii, self.blurs, range(len(self.blurs))) self.blur_indices = np.round(self.blur_indices).astype('int') self.coords = [] for i in range(len(blurs)): rp = [radial_positions[j] for j in range(len(radial_positions)) if self.blur_indices[j] == i] map = AngleEccentricityMap(input_shape, angles, rp) if len(rp) > 0: wc = warp_coords(map, (len(angles), len(rp), 3)) else: wc = None self.coords.append(wc)
def test_warp_coords_example(): image = data.astronaut().astype(np.float32) assert 3 == image.shape[2] tform = SimilarityTransform(translation=(0, -10)) coords = warp_coords(tform, (30, 30, 3)) map_coordinates(image[:, :, 0], coords[:2])
def shift_stack(stack, popt, n_cols, n_rows, ndx, ndy, limit=None, save=False, savedir=None, name=None): """Shift a stack Shifts the input stack, using the second and third elements in popt, and makes a new stack of the shifted images. Parameters ---------- stack : hyperspy.api.signals.Signal2D A stack of e.g. Precession Electron Diffraction patterns to be shifted. Assumed to have shape (Nx, Ny, nx, ny) popt : numpy.ndarray A numpy array of shape (Nx*Ny, 7), where the second and third elements are used as shifts in row and column directions, respectively n_cols : int, float or str Number of columns in the stack (equal to Ny) n_rows : int, float or str Number of rows in the stack (equal to Nx) ndx : int, float or str Number of vertical (?) pixels in the diffraction pattern ndy : int, float or str Number of horizontal (?) pixels in the diffraction pattern limit : int, float, str or None, optional Number of frames to shift before breaking, useful for debugging (the default is `None` indicating that all frames will be shifted) save : {False, True}, optional Whether or not the shifted stack should be saved savedir : int, float or str, optional Used to specify a directory to store the shifted stack if `save=True` (default is `''` indicating that the signal will be stored in the cwd) name : int, float or str, optional Used to specify the name of the signal if `save=True` (default is `'shifted_stack'` Returns ------- shifted_signal : hyperspy.api.signals.Signal2D The shifted stack as a hyperspy signal times : list of floats The time spent since the start of the for loop, sampled at every 1% of total frames. Raises ------ Notes ----- Examples -------- Load a premade `popt` file and a signal to shift, then shift the signal >>> s = hs.load('C:\\Users\\emilc\\Desktop\\SPED_align_laptop\\2017_01_11_6060-20-1-C-4_001.blo') >>> n_cols = s.axes_manager['x'].get('size')['size'] >>> n_rows = s.axes_manager['y'].get('size')['size'] >>> ndx = s.axes_manager['dx'].get('size')['size'] >>> ndy = s.axes_manager['dy'].get('size')['size'] >>> Popts = np.load(savedir+'Popts_1.npy') >>> shifted_signal = sa.shift_stack(s, Popts, n_cols=n_cols, n_rows=n_rows, ndx=ndx, ndy=ndy, save=True, savedir='C:\\Users\\emilc\\Desktop\\SPED_align_laptop\\2017_01_11_6060-20-1-C-4_001_shifted') """ assert isinstance(stack, hs.signals.Signal2D), '`stack` is type {}, must be a `hyperspy.api.signals.Signal2D` object'.format( type(stack)) assert isinstance(popt, np.ndarray), '`popt` is type {}, must be a `numpy.ndarray`'.format( type(popt)) assert len(np.shape( stack)) == 4, '`stack` has shape {}, must have a 4D shape'.format( np.shape(stack)) assert len(np.shape( popt)) == 2, '`popt` has shape {}, must have a 2D shape (flattened array)'.format( np.shape(popt)) assert np.shape(popt)[0] == np.shape(stack)[0] * np.shape(stack)[1] and \ np.shape(popt)[ 1] == 7, 'First dimension of `popt` ({}) must equal the product of the first ({}) and second ({}) dimension of `stack`.'.format( np.shape(popt)[0], np.shape(stack)[0], np.shape(stack)[1]) try: n_cols, n_rows, ndx, ndy = int(n_cols), int(n_rows), int(ndx), int( ndy) if limit is None: limit = n_rows * n_cols else: limit = int(limit) save = bool(save) if save: if savedir is None: savedir = '' else: savedir = str(savedir) if name is None: name = 'shifted_stack' else: name = str(name) except ValueError as e: print(e) return None except TypeError as e: print(e) return None # Define function for shifting image (called by skimage.transform.warp_coords) def shift(xy): """Shift image coordinates somehow Parameters ---------- xy : numpy.ndarray Coordinate array Returns ------- numpy.ndarray I think this function returns a numpy.ndarray... But I am not sure yet: On Todo! """ return xy - np.array( [72 - popt[frameno, 2], 72 - popt[frameno, 1]])[None, :] # Total number of frames in the stack n_tot = n_cols * n_rows # Allocate memory and define the new (shifted) stack shifted_stack = np.zeros((n_rows, n_cols, ndx, ndy), dtype=np.uint8) # Define row and column counters rowno = 0 colno = 0 # Make a list over rumtime times. times = [time.time()] # loop over all the frames in the stack, and for each frame, use a corresponding image shift found by e.g. # `align_stack_fast()` to shift the frame for frameno, frame in enumerate(stack): if colno == n_cols: colno = 0 rowno += 1 # Print some output for every 1/100 th frame if not frameno % (int(limit / 100)): curr_t_diff = time.time() - times[0] times.append(curr_t_diff) print( '{}% done (now on Frame {} of {}: row {}, col {})\n\tTime passed since start: {} seconds.'.format( int(frameno / limit * 100), frameno, limit, rowno, colno, curr_t_diff)) coords = warp_coords(shift, frame.data.shape) shifted_stack[rowno, colno, :, :] = map_coordinates(frame.data, coords).astype( np.uint8) colno += 1 # Check if the limit is reached or if the loop is finished. if frameno == limit or frameno == n_tot - 1: shifted_signal = hs.signals.Signal2D(shifted_stack) shifted_signal.metadata = stack.metadata.deepcopy() new_metadata = {'Postprocessing': { 'date': dt.datetime.now().strftime('%c%'), 'version': 'latest', 'type': 'Shifted stack', 'limit': limit, 'save': save, 'savedirectory': savedir, 'name': name, 'time elapsed': times[-1]}} shifted_signal.metadata.add_dictionary(new_metadata) shifted_signal.axes_manager = stack.axes_manager.copy() # If the user wants to save the shifted signal, save it as `.hdf5` file if save: shifted_signal.save(savedir + name + '.hdf5') return shifted_signal, times # Just in case the if statement above bugs, return the signal anyways shifted_signal = hs.signals.Signal2D(shifted_stack) shifted_signal.metadata = shifted_signal.metadata = stack.metadata.deepcopy() new_metadata = { 'Postprocessing': {'date': dt.datetime.now().strftime('%c%'), 'version': 'latest', 'type': 'Shifted stack', 'limit': limit, 'save': save, 'savedirectory': savedir, 'name': name, 'time elapsed': times[-1]}} shifted_signal.metadata.add_dictionary(new_metadata) shifted_signal.axes_manager = stack.axes_manager.copy() return shifted_signal, times
def align_stack_fast(stack, limit=None, bounds=10, save=False, savedir=None, name=None): """Find 000 position of each frame in stack and align the stack to these positions Parameters ---------- stack : hyperspy.api.signals.Signal2D The stack containing the diffraction patterns to be aligned. limit : int, float or str, optional The total number of frames to consider before ending, useful for debugging (default is None which implies treating the whole stack). bounds : int, float or str, optional Defines the region where a 2D gaussian is fitted to the dataset (the default is 10). The region is defined as `frame[center[0]-bounds:center[0]+bounds+1, center[1]-bounds:center[1]+bounds+1`. The region should be chosen large enough to (preferably) only contain the 000 reflection. save : {False, True}, optional Whether or not to save the aligned stack and the gaussian fits as hdf5 files. savedir : str, optional The directory to store the results, if `save=True` (defaults to `''` which implies storing results in the cwd). name : str, optional The name to give the aligned stack (defaults to `aligned_stack`). Returns ------- Popt : numpy.ndarray The fit results containing all the data to produce the fitted gaussian. The array has shape (N*M, 7) where N and M are the scan dimensions of the stack (total number of frames), and 7 is the number of parameters to describe the gaussian. g : hyperspy.api.signals.Signal2D A stack of the intensities of the fitted gaussians. aligned_stack : hyperspy.api.signals.Signal2D A stack containing the aligned diffraction patterns of the input stack. See Also -------- gaussian_2d_fast : Compute 2D gaussian fit_gaussian_2d_to_imagesubset_fast : Fit a 2D gaussian to a subset of image Examples -------- Load a blockfile containing Scanning Precession Electron Diffraction data and align them. >>> s = hs.load('data.blo') >>> Popts, g, s_aligned = sa.align_stack_fast(s, limit=None, save=True) """ assert isinstance(stack, hs.signals.Signal2D), '`stack` is type {}, must be a `hyperspy.api.signals.Signal2D` object'.format( type(stack)) assert len(np.shape( stack)) == 4, '`stack` has shape {}, must have a 4D shape'.format( np.shape(stack)) try: n_cols = stack.axes_manager['x'].get('size')['size'] n_rows = stack.axes_manager['y'].get('size')['size'] n_tot = n_cols * n_rows if limit is None: limit = n_tot else: limit = int(limit) ndx = stack.axes_manager['dx'].get('size')['size'] ndy = stack.axes_manager['dy'].get('size')['size'] bounds = int(bounds) assert bounds < ndx / 2 and bounds < ndy / 2, 'The bounds ({}) cannot be larger than half the diffraction pattern width (whole widths: {}, {}).'.format( bounds, ndx, ndy) save = bool(save) if save: if savedir is None: savedir = '' else: savedir = str(savedir) if name is None: name = 'aligned_stack' else: name = str(name) except ValueError as e: print(e) return None except TypeError as e: print(e) return None def shift(xy): return xy - np.array([72 - fit_popt[2], 72 - fit_popt[1]])[None, :] dx, dy = np.mgrid[0:ndx, 0:ndy] Popt = np.zeros((n_tot, 7)) G = np.zeros((n_rows, n_cols, ndx, ndy), dtype=np.uint8) shifted_stack = np.zeros((n_rows, n_cols, ndx, ndy), dtype=np.uint8) rowno = 0 colno = 0 times = [time.time()] for frameno, frame in enumerate(stack): if colno == n_cols: colno = 0 rowno += 1 if not frameno % (int(limit / 100)): times.append(time.time() - times[0]) print( '{}% done (now on Frame {} of {}: row {}, col {})'.format( int(frameno / limit * 100), frameno, limit, rowno, colno)) try: fit_popt = fit_gaussian_2d_to_imagesubset_fast(frame.data, bounds) except RuntimeError as e: g = hs.signals.Signal2D(G) g.metadata = stack.metadata.deepcopy() g.axes_manager = stack.axes_manager.copy() new_metadata = {'Postprocessing': { 'date': dt.datetime.now().strftime('%c'), 'version': 'latest', 'type': 'Gaussian fit', 'limit': limit, 'save': save, 'savedirectory': savedir, 'name': name, 'time elapsed': times[-1]}} g.metadata.add_dictionary(new_metadata) # g.axes_manager = stack.axes_manager.copy() aligned_stack = hs.signals.Signal2D(shifted_stack) aligned_stack.metadata = stack.metadata.deepcopy() aligned_stack.axes_manager = stack.axes_manager.copy() new_metadata = {'Postprocessing': { 'date': dt.datetime.now().strftime('%c'), 'version': 'latest', 'type': 'aligned stack', 'limit': limit, 'save': save, 'savedirectory': savedir, 'name': name, 'time elapsed': times[-1]}} aligned_stack.metadata.add_dictionary(new_metadata) if save: np.save(savedir + 'Popts_1', Popt) g.save(savedir + 'G.hdf5') aligned_stack.save(savedir + name + '.hdf5') print(e) return Popt, g, aligned_stack Popt[frameno, :] = fit_popt G[rowno, colno, :, :] = gaussian_2d_fast((dx, dy), *fit_popt).reshape( np.shape(dx)).astype(np.uint8) coords = warp_coords(shift, frame.data.shape) shifted_stack[rowno, colno, :, :] = map_coordinates(frame.data, coords).astype( np.uint8) colno += 1 if frameno == limit or frameno == n_tot - 1: g = hs.signals.Signal2D(G) g.metadata = stack.metadata.deepcopy() #print('Stack metadata:\n', stack.metadata) #print('G metadata (deepcopied):\n', g.metadata) g.axes_manager = stack.axes_manager.copy() new_metadata = {'Postprocessing': { 'date': dt.datetime.now().strftime('%c'), 'version': 'latest', 'type': 'Gaussian fit', 'limit': limit, 'save': save, 'savedirectory': savedir, 'name': name, 'time elapsed': times[-1]}} g.metadata.add_dictionary(new_metadata) #print('G metadata (added dict):\n',g.metadata) aligned_stack = hs.signals.Signal2D(shifted_stack) aligned_stack.metadata = stack.metadata.deepcopy() aligned_stack.axes_manager = stack.axes_manager.copy() new_metadata = {'Postprocessing': { 'date': dt.datetime.now().strftime('%c'), 'version': 'latest', 'type': 'aligned stack', 'limit': limit, 'save': save, 'savedirectory': savedir, 'name': name, 'time elapsed': times[-1]}} aligned_stack.metadata.add_dictionary(new_metadata) if save: np.save(savedir + 'Popts_1', Popt) g.save(savedir + 'G.hdf5') aligned_stack.save(savedir + name + '.hdf5') return Popt, g, aligned_stack
def test_warp_coords_example(): image = data.lena().astype(np.float32) assert 3 == image.shape[2] tform = SimilarityTransform(translation=(0, -10)) coords = warp_coords(tform, (30, 30, 3)) map_coordinates(image[:, :, 0], coords[:2])