def align(img1,img2,inc1,inc2,mask1=False,mask2=False): #align image1 with image2 ##shift, error, diffphase = register_translation((img1), (img2),100) if mask1 is False: shift,error,diffphase = phase_cross_correlation((img1),(img2),upsample_factor=100) else: shift = phase_cross_correlation((img1),(img2),upsample_factor=100,reference_mask=mask1,moving_mask=mask2) if mask1 is False: print ('register images new shift (y,x): [{} : {}] mas'.format(shift[0]*inc1,shift[1]*inc2)) print ('register images new shift (y,x): {} px +- {}'.format(shift,error)) else: print ('register images new shift (y,x): [{} : {}] mas'.format(shift[0]*inc1,shift[1]*inc2)) print ('register images new shift (y,x): {} px'.format(shift)) #shift img2 to found position img2 = apply_shift(img2,shift) #return aligned image and the computed shift if mask1 is False: return {'align':img2, 'shift':shift, 'error':error, 'diffphase': diffphase} else: return {'align':img2, 'shift':shift}
def find_beam_offset_cross_correlation(z, radius_start, radius_finish): """Find the offset of the direct beam from the image center by a cross-correlation algorithm. The shift is calculated relative to an circle perimeter. The circle can be refined across a range of radii during the centring procedure to improve performance in regions where the direct beam size changes, e.g. during sample thickness variation. Parameters ---------- radius_start : int The lower bound for the radius of the central disc to be used in the alignment. radius_finish : int The upper bounds for the radius of the central disc to be used in the alignment. Returns ------- shift: np.array np.array [y, x] containing offset (from center) of the direct beam positon. """ radiusList = np.arange(radius_start, radius_finish) errRecord = np.zeros_like(radiusList, dtype="single") origin = np.array( [[round(np.size(z, axis=-2) / 2), round(np.size(z, axis=-1) / 2)]]) for ind in np.arange(0, np.size(radiusList)): radius = radiusList[ind] ref = reference_circle(origin, np.size(z, axis=-2), np.size(z, axis=-1), radius) h0 = np.hanning(np.size(ref, 0)) h1 = np.hanning(np.size(ref, 1)) hann2d = np.sqrt(np.outer(h0, h1)) ref = hann2d * ref im = hann2d * z shift, error, diffphase = phase_cross_correlation(ref, im, upsample_factor=10) errRecord[ind] = error index_min = np.argmin(errRecord) ref = reference_circle(origin, np.size(z, axis=-2), np.size(z, axis=-1), radiusList[index_min]) h0 = np.hanning(np.size(ref, 0)) h1 = np.hanning(np.size(ref, 1)) hann2d = np.sqrt(np.outer(h0, h1)) ref = hann2d * ref im = hann2d * z shift, error, diffphase = phase_cross_correlation(ref, im, upsample_factor=100) shift = shift[::-1] return shift - 0.5
def align_image(image_in: np.ndarray, im_index: int, interpolation: str, accuracy: float, resize: Optional[float], num_references: int, subframe: Optional[float], ref_images_reshape: np.ndarray, ref_images_shape: Tuple[int, int, int]) -> np.ndarray: offset = np.array([0., 0.]) # Reshape the reference images back to their original 3D shape # The original shape can not be used directly because of util.module.update_arguments ref_images = ref_images_reshape.reshape(ref_images_shape) for i in range(num_references): if subframe is None: tmp_offset, _, _ = phase_cross_correlation(ref_images[i, :, :], image_in, upsample_factor=accuracy) else: sub_in = crop_image(image_in, None, subframe) sub_ref = crop_image(ref_images[i, :, :], None, subframe) tmp_offset, _, _ = phase_cross_correlation(sub_ref, sub_in, upsample_factor=accuracy) offset += tmp_offset offset /= float(num_references) if resize is not None: offset *= resize sum_before = np.sum(image_in) tmp_image = rescale(image_in, (resize, resize), order=5, mode='reflect', multichannel=False, anti_aliasing=True) sum_after = np.sum(tmp_image) # Conserve flux because the rescale function normalizes all values to [0:1]. tmp_image = tmp_image*(sum_before/sum_after) else: tmp_image = image_in return shift_image(tmp_image, offset, interpolation)
def _determine_registration_offset(base_image, uncorrected_image): """ Finds the translational offset required to align this image with all others in the stack. Returns dx, dy adjustments in pixels *but does not change the image!* :param base_image: a 2D numpy array that the other image should be aligned to :param uncorrected_image: a 2D numpy array :returns: float, float """ # Original bounds: left_bounds = (0.1, 0.3) right_bounds = (0.7, 0.9) # left_bounds = (0.35, 0.45) # right_bounds = ( 0.6, 0.7) # Get the dimensions of the images that we're aligning base_height, base_width = base_image.shape uncorrected_height, uncorrected_width = uncorrected_image.shape # We take the area that roughly corresponds to the catch channels. This has two benefits: one, it # speeds up the registration significantly (as it scales linearly with image size), and two, if # a large amount of debris/yeast/bacteria/whatever shows up in the central trench, the registration # algorithm goes bonkers if it's considering that portion of the image. # Thus we separately find the registration for the left side and right side, and average them. left_base_section = base_image[:, int(base_width * left_bounds[0]):int(base_width * left_bounds[1])] left_uncorrected = uncorrected_image[:, int(uncorrected_width * left_bounds[0] ):int(uncorrected_width * left_bounds[1])] right_base_section = base_image[:, int(base_width * right_bounds[0]):int(base_width * right_bounds[1])] right_uncorrected = uncorrected_image[:, int(uncorrected_width * right_bounds[0] ):int(uncorrected_width * right_bounds[1])] # left_dy, left_dx = phase_cross_correlation(left_base_section, left_uncorrected, upsample_factor=20)[0] right_dy, right_dx = phase_cross_correlation(right_base_section, right_uncorrected, upsample_factor=20)[0] return (left_dy + right_dy) / 2.0, (left_dx + right_dx) / 2.0
def find_and_apply_shifts(ref_image, other_images, dapi_index, block_size=500, block_pad=250): im1 = ref_image[:, :, dapi_index] ImagesAligned = [ref_image.astype(np.float32)] for im2 in other_images: im2_shift = np.zeros(im2.shape, dtype=np.float32) for i in range(0, im1.shape[0], block_size): for j in range(0, im1.shape[1], block_size): im1_block = im1[max(0, i - block_pad):i + block_size + block_pad, max(0, j - block_pad):j + block_size + block_pad] im2_block = im2[i:i + block_size, j:j + block_size] if (im1_block.sum() > 0) and (im2_block.sum() > 0): pad0 = im1_block.shape[0] - im2_block.shape[0] pad1 = im1_block.shape[1] - im2_block.shape[1] pad0 = (int(pad0 / 2), int(pad0 / 2 + pad0 % 2)) pad1 = (int(pad1 / 2), int(pad1 / 2 + pad1 % 2)) im2_block = np.pad(im2_block, (pad0, pad1, (0, 0)), 'constant').astype(im1_block.dtype) shift, error, diffphase = phase_cross_correlation( im1_block, im2_block[:, :, dapi_index]) offset_image = apply_shift_to_stack(im2_block, shift) im2_shift[max(0, i - block_pad):i + block_size + block_pad, max(0, j - block_pad):j + block_size + block_pad] += offset_image ImagesAligned.append(im2_shift) return ImagesAligned
def get_cam_roll_pxsize(imgs, positions): '''Finds camera angle and pixel size Parameters ---------- imgs : list(ndarray) List of images where nozzle has been moved in x-direction positions : list(float) List of motor positions in millimeters Returns ------- cam_roll : float Camera angle in radians pxsize : float Pixel size in millimeters ''' ytot = 0 xtot = 0 changetot = 0 for i in range(len(positions) - 1): im1, im2 = imgs[i], imgs[i + 1] (dy, dx), _, _ = phase_cross_correlation(im1, im2, upsample_factor=100) if dy < 0: dy *= -1 dx *= -1 ytot += dy xtot += dx changetot += abs(positions[i + 1] - positions[i]) cam_roll = -np.arctan(ytot / xtot) pxsize = changetot / np.sqrt(ytot**2 + xtot**2) return cam_roll, pxsize
def get_nozzle_shift(im1, im2, *, cam_roll, pxsize): """ Find the distance the nozzle has shifted between two images. Parameters ---------- im1 : ndarray On-axis camera image 1. im2 : ndarray On-axis camera image 2. cam_roll : float Rotation of camera about z axis in radians. pxsize : float Size of pixel in mm. Returns ------- dy : float Distance in y. dx : float Distance in x. """ # Generalize for both cameras? (sy, sx), _, _ = phase_cross_correlation(im1, im2, upsample_factor=100) dx = (sx * np.cos(cam_roll) - sy * np.sin(cam_roll)) * pxsize dy = (sy * np.cos(cam_roll) + sx * np.sin(cam_roll)) * pxsize return dy, dx
def image_registration(self): """ Register using cross correlation""" tforms = self.fishdata.load_data('tforms',dataset=self.dataset,posname=self.posname,hybe=self.hybe) if not isinstance(tforms,type(None)): self.tforms = tforms self.completed = True self.utilities.save_data('Passed', Dataset=self.dataset, Position=self.posname, Hybe=self.hybe, Channel=self.channel, Type='flag') else: if self.verbose: self.update_user('Registering Image') self.translation_z = 0 self.residual = 0 self.nbeads = 0 if self.hybe==self.parameters['ref_hybe']: self.translation_x = 0 self.translation_y = 0 else: self.ref_image = self.load_image(self.parameters['ref_hybe'],'FarRed') self.image = self.load_image(self.hybe,'FarRed') shift, error, diffphase = phase_cross_correlation(self.ref_image, self.image, upsample_factor=10) self.translation_x = shift[1] self.translation_y = shift[0] self.save_tforms()
def piecewise_fov_shift(ref_img, tar_img, n_patch=8): """ Calculates FOV-shift map between a reference and a target image. Images are split in n_patch X n_patch patches, and shift is calculated for each patch separately with phase correlation. The resulting shift map is scaled up and missing values interpolated to ref_img size to get an estimated shift value for each pixel. Args: ref_img (np.array): reference image tar_img (np.array): target image to which FOV shift is calculated. Has to be same dimensions as ref_img n_patch (int): root number of patches the FOV should be subdivided into for piecewise phase correlation Returns: np.array: Array containing estimated shifts per pixel (upscaled x_shift_map) np.array: Array containing estimated shifts per pixel (upscaled y_shift_map) """ img_dim = ref_img.shape patch_size = int(img_dim[0] / n_patch) shift_map_x = np.zeros((n_patch, n_patch)) shift_map_y = np.zeros((n_patch, n_patch)) for row in range(n_patch): for col in range(n_patch): curr_ref_patch = ref_img[row * patch_size:row * patch_size + patch_size, col * patch_size:col * patch_size + patch_size] curr_tar_patch = tar_img[row * patch_size:row * patch_size + patch_size, col * patch_size:col * patch_size + patch_size] patch_shift = phase_cross_correlation(curr_ref_patch, curr_tar_patch, upsample_factor=100, return_error=False) shift_map_x[row, col] = patch_shift[0] shift_map_y[row, col] = patch_shift[1] shift_map_x_big = zoom(shift_map_x, patch_size, order=3) shift_map_y_big = zoom(shift_map_y, patch_size, order=3) return shift_map_x_big, shift_map_y_big
def find_center_pc(images: Images, initial_guess: Optional[float] = None, tol: float = 0.5) -> float: """ Find rotation axis location by finding the offset between the first projection and a mirrored projection 180 degrees apart using phase correlation in Fourier space. Implements an updated version of Tomopy's `find_center_pc`, source: https://github.com/tomopy/tomopy/blob/1ae454caf4da496499be6e6c6d6299e74550cf50/source/tomopy/recon/rotation.py#L374-L418 The changes make use of the newer scikit-image version and it's registration module, for a faster registration by using the `phase_cross_correlation` function. The rest of the changes are to be compatible with the data structure used within this package (Images class) """ # if the user provides an initial guess of the COR, take that into account to move the image to it initial_guess = 0 if initial_guess is None else initial_guess - images.h_middle p1 = ndimage.shift(images.projection(0), [0, -initial_guess], mode='constant', cval=0) p2 = np.fliplr( ndimage.shift(images.proj180deg.data, [0, -initial_guess], mode='constant', cval=0)) shift = phase_cross_correlation(p1, p2, upsample_factor=1.0 / tol) getLogger(__name__).info(f"Found COR shift {shift}") # Compute center of rotation as the center of first image and the # registered translation with the second image center = (p1.shape[1] + shift[0][1]) / 2 return center + initial_guess
def correct_stage_drift(image1, image2, additional_images=[]): # find shift with image registration shift_values = phase_cross_correlation(image1, image2, upsample_factor=100) shift_y = shift_values[0][0] shift_x = shift_values[0][1] # using interpolation to shift subpixel precision, image2 is the reference image1_shift = shift(image1, shift=(-shift_y, -shift_x), order=5) # normalizing and converting to image format b = normalizing(croping_after_shift(image1_shift, shift_x, shift_y)) a = normalizing(croping_after_shift(image2, shift_x, shift_y)) b_save = Image.fromarray(b * 255) a_save = Image.fromarray(a * 255) # doing the same with additional images additional_images_save = [] for add_image in additional_images: add_image_shift = shift(add_image, shift=(-shift_y, -shift_x), order=5) add_image_norm = normalizing(croping_after_shift(add_image_shift, shift_x, shift_y)) add_image_save = Image.fromarray(add_image_norm * 255) additional_images_save.append(add_image_save) return b_save, a_save, additional_images_save, (shift_x, shift_y)
def _conventional_xc(exp_disc, sim_disc, upsample_factor): """Takes two images of disc and finds the shift between them using conventional (phase) cross correlation. Parameters ---------- exp_disc : np.array() A numpy array of the "experimental" disc sim_disc : np.array() A numpy array of the disc used as a template upsample_factor: int (must be even) Factor to upsample by, reciprocal of the subpixel resolution (eg 10 ==> 1/10th of a pixel) Returns ------- shifts Pixel shifts required to register the two images """ shifts, error, _ = phase_cross_correlation(exp_disc, sim_disc, upsample_factor=upsample_factor) shifts = np.flip( shifts) # to comply with hyperspy conventions - see issue#490 return shifts
def get_cam_roll(imgs): '''Finds the camera angle Parameters ---------- imgs : list(ndarray) List of images where nozzle has been moved in x-direction Returns ------- cam_roll : float Camera angle in radians ''' ytot = 0 xtot = 0 for i in range(len(imgs) - 1): im1, im2 = imgs[i], imgs[i + 1] # Is the order dy, dx correct? (dy, dx), _, _ = phase_cross_correlation(im1, im2, upsample_factor=100) if dy < 0: dy *= -1 dx *= -1 ytot += dy xtot += dx return -np.arctan(ytot / xtot)
def get_cam_pitch(imgs): """ Find the camera angle. Parameters ---------- imgs : list of ndarray List of images where nozzle has been moved in x-direction. Returns ------- cam_pitch : float Offaxis camera pitch angle in radians. """ ytot = 0 ztot = 0 for i in range(len(imgs) - 1): im1, im2 = imgs[i], imgs[i + 1] (dy, dz), _, _ = phase_cross_correlation(im1, im2, upsample_factor=100) if dy < 0: dy *= -1 dz *= -1 ytot += dy ztot += dz # why is this one not negative? return np.arctan(ytot / ztot)
def test_detrecated_masked_register_translation(): reference_image, moving_image, _ = stereo_motorcycle() ref_mask = np.random.choice( [True, False], reference_image.shape, p=[3 / 4, 1 / 4]) with expected_warnings(["Function ``masked_register_translation``"]): assert_equal(_deprecated(reference_image, moving_image, ref_mask), phase_cross_correlation(reference_image, moving_image, reference_mask=ref_mask))
def _compute_transform(self, image1, image2, mask1=None, mask2=None): # Masks are ignored by default dy, dx = phase_cross_correlation(image1, image2, upsample_factor=self._up_factor, space=self._fft_space, return_error=False) return transform.AffineTransform(translation=(-dx, -dy))
def register_frame(frame, mask, reference): detected_shift = phase_cross_correlation(reference, frame, reference_mask=mask) shifted_frame = ndi.shift(frame, detected_shift, mode='reflect') shifted_mask = ndi.shift(mask, detected_shift, mode='constant', cval=0) return shifted_frame, shifted_mask
def cross_correlate_image_pairs(pairs: tuple) -> list: """Cross correlate image pairs.""" translations = [] for img0, img1 in pairs: translation, error, phasediff = phase_cross_correlation(img0, img1, upsample_factor=10) print(f'shift {translation} error {error:.4f} phasediff {phasediff:.4f}') translations.append(translation) return translations
def image_registration(ref_image, off_image, img_to_reg=None, upsample_fac=50): """ Function to co-register off_image with respect to off_image""" shift, error, diffphase = phase_cross_correlation( ref_image, off_image, upsample_factor=upsample_fac) if img_to_reg is None: img_to_reg = off_image reg_image = np.real( np.fft.ifftn(fourier_shift(np.fft.fftn(img_to_reg), shift))) return reg_image
def calibrate_mag1_from_image_fn(center_fn, other_fn): """Calibrate pixel->stageposition coordinates from a set of images. center_fn: `str` Reference image at the center of the grid (with the clover in the middle) other_fn: `tuple` of `str` Set of images to cross correlate to the first reference image return: instance of Calibration class with conversion methods """ img_cent, h_cent = read_image(center_fn) # binsize = h_cent["ImageBinsize"] cam_dimensions = h_cent['ImageCameraDimensions'] bin_x, bin_y = cam_dimensions / np.array(img_cent.shape) assert bin_x == bin_y, 'Binsizes do not match {bin_x} != {bin_y}' binsize = int(bin_x) img_cent, scale = autoscale(img_cent, maxdim=512) x_cent, y_cent, _, _, _ = h_cent['StagePosition'] xy_cent = np.array([x_cent, y_cent]) print('Center:', center_fn) print('Stageposition: x={:.0f} | y={:.0f}'.format(*xy_cent)) print() shifts = [] stagepos = [] for i, fn in enumerate(other_fn): img, h = read_image(fn) img = imgscale(img, scale) x_xobs, yobs, _, _, _ = h_cent['StagePosition'] print('Image:', fn) print(f'Stageposition: x={xobs:.0f} | y={yobs:.0f}') shift, error, phasediff = phase_cross_correlation(img_cent, img, upsample_factor=10) print('Shift:', shift) print() stagepos.append((xobs, yobs)) shifts.append(shift) # correct for binsize, store as binsize=1 shifts = np.array(shifts) * binsize / scale stagepos = np.array(stagepos) - xy_cent c = CalibStage.from_data(shifts, stagepos, reference_position=xy_cent, camera_dimensions=cam_dimensions) c.plot() c.to_file() return c
def _align_image(image_in: np.ndarray) -> np.ndarray: offset = np.array([0., 0.]) for i in range(self.m_num_references): if self.m_subframe is None: tmp_offset, _, _ = phase_cross_correlation( ref_images[i, :, :], image_in, upsample_factor=self.m_accuracy) else: sub_in = crop_image(image_in, None, self.m_subframe) sub_ref = crop_image(ref_images[i, :, :], None, self.m_subframe) tmp_offset, _, _ = phase_cross_correlation( sub_ref, sub_in, upsample_factor=self.m_accuracy) offset += tmp_offset offset /= float(self.m_num_references) if self.m_resize is not None: offset *= self.m_resize sum_before = np.sum(image_in) tmp_image = rescale(image=np.asarray(image_in, dtype=np.float64), scale=(self.m_resize, self.m_resize), order=5, mode='reflect', anti_aliasing=True, multichannel=False) sum_after = np.sum(tmp_image) # Conserve flux because the rescale function normalizes all values to [0:1]. tmp_image = tmp_image * (sum_before / sum_after) else: tmp_image = image_in return shift_image(tmp_image, offset, self.m_interpolation)
def align_to( self, ref_img: 'np.array', apply: bool = True, verbose: bool = False, ) -> list: """Align current view by comparing it against the given image using cross correlation. The stage is translated so that the object of interest (in the reference image) is at the center of the view. Parameters ---------- ref_img : np.array Reference image that the microscope will be aligned to apply : bool Toggle to translate the stage to center the image verbose : bool Be more verbose Returns ------- stage_shift : np.array[2] The stage shift vector determined from cross correlation """ from skimage.registration import phase_cross_correlation current_x, current_y = self.stage.xy if verbose: print(f'Current stage position: {current_x:.0f} {current_y:.0f}') stagematrix = self.get_stagematrix() img = self.get_rotated_image() pixel_shift, error, phasediff = phase_cross_correlation( ref_img, img, upsample_factor=10) stage_shift = np.dot(pixel_shift, stagematrix) stage_shift[0] = -stage_shift[0] # match TEM Coordinate system print( f'Aligning: shifting stage by dx={stage_shift[0]:6.0f} dy={stage_shift[1]:6.0f}' ) new_x = current_x + stage_shift[0] new_y = current_y + stage_shift[1] if verbose: print(f'New stage position: {new_x:.0f} {new_y:.0f}') if apply: self.stage.set_xy_with_backlash_correction(x=new_x, y=new_y) return stage_shift
def calibrate_stage_lowmag_from_image_fn(center_fn, other_fn): """Calibrate pixel->stageposition coordinates from a set of images. center_fn: `str` Reference image at the center of the grid (with the clover in the middle) other_fn: `tuple` of `str` Set of images to cross correlate to the first reference image return: instance of Calibration class with conversion methods """ img_cent, h_cent = read_image(center_fn) img_cent, scale = autoscale(img_cent, maxdim=512) x_cent, y_cent, _, _, _ = h_cent['StagePosition'] xy_cent = np.array([x_cent, y_cent]) print('Center:', center_fn) print('Stageposition: x={:.0f} | y={:.0f}'.format(*xy_cent)) print() binsize = h_cent['ImageBinsize'] shifts = [] stagepos = [] for fn in other_fn: img, h = read_image(fn) img = imgscale(img, scale) xobs, yobs, _, _, _ = h['StagePosition'] print('Image:', fn) print(f'Stageposition: x={xobs:.0f} | y={yobs:.0f}') print() shift, error, phasediff = phase_cross_correlation(img_cent, img, upsample_factor=10) stagepos.append((xobs, yobs)) shifts.append(shift) # correct for binsize, store as binsize=1 shifts = np.array(shifts) * binsize / scale stagepos = np.array(stagepos) - xy_cent c = CalibStage.from_data(shifts, stagepos, reference_position=xy_cent, header=h_cent) c.plot() return c
def calculate_image_offset(img1, img2, upsample_factor=1): ref = utils.whiten(img1, 0) test = utils.whiten(img2, 0) shift = phase_cross_correlation( ref, test, upsample_factor=upsample_factor, normalization=None, return_error=False, ) return shift
def find_shift(reference_image, other_image, scale=0.25): """ """ # TODO: Fill out docstring. Also why is there a scale parameter here? Is it to save computation? rescaled_reference_image = rescale(reference_image, scale) rescaled_other_image = rescale(other_image, scale) shift, error, diffphase = phase_cross_correlation(rescaled_reference_image, rescaled_other_image) scaled_shift = shift / scale return scaled_shift
def _value_function_handle(params: Dict[Enum, Parameter]) -> np.ndarray: shifts, error, _ = phase_cross_correlation( params[AngleSelectParams.REF_IMG].value, params[AngleSelectParams.ROT_B_IMG].value, upsample_factor=params[AngleSelectParams.UPSAMPLING].value, ) tform = AffineTransform( scale=1, rotation=np.deg2rad(-params[AngleSelectParams.ANGLE_B].value), ) shifts = tform.params[:2, :2] @ shifts[::-1] return np.array([*shifts, error])
def cross_correlation(moving, fixed): if moving.shape[-1] == 3: moving_gray = rgb2gray(moving) fixed_gray = rgb2gray(fixed) elif moving.shape[-1] == 1: moving_gray = moving[..., 0] fixed_gray = fixed[..., 0] else: print("Image channel Error!") shift, error, diffphase = phase_cross_correlation(moving_gray, fixed_gray) out = np.roll(moving, -np.array(shift).astype(np.int), axis=(0, 1)) return out, error
def _value_function_handle(params: Dict[Enum, Parameter]) -> np.ndarray: shifts, error, _ = phase_cross_correlation( params[LogPolParams.REF_IMG].value, params[LogPolParams.RECOVERED_ROT_SCALE_IMG].value, upsample_factor=params[LogPolParams.UPSAMPLING].value, ) tform = AffineTransform( scale=params[LogPolParams.RECOVERED_SCALE].value[0], rotation=np.deg2rad( -params[LogPolParams.RECOVERED_ROTATION].value[0]), ) shifts = tform.params[:2, :2] @ shifts[::-1] return np.array([*shifts, error])
def measure_shift(previous_frame, current_frame, mask=None, f=100): # note frames are reversed so the shift measures wind speed # in terms of the reference image shift_yx = phase_cross_correlation( current_frame, previous_frame, return_error=False, reference_mask=mask, upsample_factor=f # will have no effect if mask is not None ) x = shift_yx[1] * PYDM_SPEEDSCALE_X y = shift_yx[0] * PYDM_SPEEDSCALE_Y r, theta = polar_transform(x=x, y=y) return x, y, r, theta
def test_masked_registration_vs_phase_cross_correlation(): """masked_register_translation should give the same results as phase_cross_correlation in the case of trivial masks.""" reference_image = camera() shift = (-7, 12) shifted = np.real( fft.ifft2(fourier_shift(fft.fft2(reference_image), shift))) trivial_mask = np.ones_like(reference_image) nonmasked_result, *_ = phase_cross_correlation(reference_image, shifted) masked_result = masked_register_translation(reference_image, shifted, reference_mask=trivial_mask, overlap_ratio=1 / 10) assert_equal(nonmasked_result, masked_result)