def get_affine_deformations(mraw_path, roi_reference, roi_size, file_shape, progressBar=None, tol=1e-5, maxiter=100, int_order=3, increment=1, crop=False, debug=False): ''' Get defformations of te Region of Interest, using the Newton-Gauss optimization method with a Zero Normalized Cross Correlation based DIC algorithm. :param mraw_path: Path to .mraw file containing image data. :param roi_reference: Upper left coordinate point of ROI, (y, x). :param roi_size: ROI size, (h, w) [px]. :param file_shape: Tuple, (ntotal, height, width) of images in .mraw file. :param tol: Convergence condition (maximum parameter iteration vector norm). :param int_order: Bivariate spline interpolation order. :param increment: Only read every n-th image from sequence. :param: crop: Border size to crop loaded images (if 0, do not crop). :param: debug: If True, display debug output. :return: results: Numpy array, containing extracted data, shaped as [p1, p2, p3, p4, p5, p6] arrays for all images. :return: iters: Array, number of iterations required to reach converegence for each image pair. ''' with open(mraw_path, 'rb') as mraw: memmap = np.memmap(mraw, dtype=np.uint16, mode='r', shape=file_shape) # Map to all images in file memmap = memmap[::increment] # Apply sequence increment N_inc = len(memmap) errors = {} # Initialize warnings dictionary # Precomputable stuff: F = memmap[0] # Initial image of the sequence is only used once. ROI = _get_roi_image( F, roi_reference, roi_size) # First ROI image, used for the initial guess. ROI_st = (np.mean(ROI), np.std(ROI) ) # Mean and standard deviation of ROI gray values. if crop: crop_slice = _crop_with_border_slice(roi_reference, roi_size, crop) F = F[crop_slice] # Crop the initial image. in_guess = dic.get_initial_guess( F, ROI)[0] # Cross-correlation initial guess is only used once. jac = dic.jacobian_affine( roi_size[0], roi_size[1] ) # The Jacobian is constant throughout the computation. ## grad = dic.get_gradient( ROI, prefilter_gauss=True) # Compute gradient images of ROI. sd_im = dic.sd_images(grad, jac) # Steepest descent images for the current ROI. H = dic.hessian( sd_im, n_param=6 ) # Hessian matrix for the current ROI. ## inv_H = np.linalg.inv(H) # Inverse of Hessian. results = np.array([ np.zeros(6, dtype=np.float64) ]) # Initialize the results array. ## iters = np.array([], dtype=int) # Initialize array of iteration counters. p_shift = np.zeros( 6, dtype=np.float64 ) # Initialize cropped image shift ## p_ref = np.zeros( 6, dtype=np.float64 ) # Initialize a reference for all following calculations. p_ref[2], p_ref[5] = in_guess[1], in_guess[0] # ... # Loop through all the images in .mraw file: for i in range(1, len(memmap)): # First image was loaded already. if crop: this_p = results[-1] roi_translation = np.array([this_p[5], this_p[2]]).astype( int) # Last calculated integer displacement new_roi_reference = roi_reference + roi_translation # Shift cropped section new position crop_slice = _crop_with_border_slice( new_roi_reference, roi_size, crop) # Calculate crop indices for new image section if _is_in_image(crop_slice, file_shape): # If still inside image frame G = memmap[i][crop_slice] # Load the next target image. else: roi_translation = np.zeros( 2, dtype=int ) # If crop indices outside image frame: don't crop G = memmap[i] else: roi_translation = np.zeros(2, dtype=int) G = memmap[i] h, w = G.shape # Get the shape of the current image for interpolation. spl = RectBivariateSpline( x=np.arange( h), # Calculate cubic bivariate spline interpolation of G. y=np.arange(w), z=G, kx=int_order, ky=int_order, s=0) err = 1. # Initialize the convergence condition. niter = 0 # Initialize optimization loop iteration counter. # Optimization loop: while err > tol and niter < maxiter: if not 'p' in locals(): # If this is the first iteration: p = np.zeros( 6, dtype=np.float64 ) # Initialize optimization parameters vector ## p[2], p[5] = in_guess[1], in_guess[ 0] # Set initial parameters to in_guess. ## warped_ROI = _get_roi_image( G, in_guess, roi_size ) # Since in_guess are integer, extract new ROI directly. warp = dic.affine_transform_matrix( p ) # Get the affine transformation matrix form initial p. ## else: # Else, use last computed parameters, interpolate new ROI. xi, yi = dic.coordinate_warp( warp, roi_size ) # Get warped coordinates to new ROI, using last optimal warp. warped_ROI = dic.interpolate_warp( xi, yi, # Compute new ROI image by interpolating the reference image target=G, output_shape=roi_size, spl=spl, order=int_order) error_im = dic.get_error_image( ROI, ROI_st, warped_ROI ) # Compute error image, according to the ZNSSD criterion. b = dic.get_sd_error_vector( sd_im, error_im, 6 ) # Compute the right-side vector in the optimization system. ## dp = np.dot( inv_H, b) # Compute the optimal transform parameters increment. err = np.linalg.norm( dp) # Incremental parameter norm = convergence criterion. dp_warp = dic.affine_transform_matrix( dp ) # Construct the increment transformation matrix. ## try: # Singular warp matrix error handling. inverse_increment_warp = np.linalg.inv( dp_warp ) # Construct the inverse of increment warp materix. warp = np.dot(warp, inverse_increment_warp ) # The updated iteration of warp matrix. p = dic.param_from_affine_matrix( warp ) # The updated iteration of transformation parameters. ## except Exception as e: errors[i] = { 'image': G, 'ROI': warped_ROI, 'message': e, 'warp_matrix': dp_warp } niter += 1 # Update the optimization loop iteration counter. p_shift = np.zeros(6, dtype=np.float64) p_shift[2], p_shift[5] = roi_translation[1], roi_translation[0] p_relative = p_shift + p - p_ref # Calculate the relative translation and rotation. results = np.vstack((results, p_relative)) # Update the results array. iters = np.append(iters, niter) # Append current iteration number to list. if progressBar: progressBar.setValue(i / N_inc * 100) # Update the progress bar. else: stdout_print_progress(i - 2, N_inc) # Print progress info to stdout. if debug: # DEBUG if len(errors) != 0: fig, ax = plt.subplots(1, 3) ax[0].imshow(G, cmap='gray', interpolation='nearest') ax[1].imshow(ROI, cmap='gray', interpolation='nearest') ax[2].imshow(warped_ROI, cmap='gray', interpolation='nearest') #plt.show() if np.max( iters) >= maxiter: # If maximum number of iterations was reached: iters = np.append(iters, np.argmax( iters)) # Append index of first iteration number maximum. iters = np.append(iters, 0) # Append 0 to the iters list (warning signal!) print('Max niter: ', np.max(iters), ' (mean, std: ', np.mean(iters), np.std(iters), ')') memmap._mmap.close() # Close the loaded memmap return results, errors, iters, increment
def get_simple_translation(mraw_path, roi_reference, roi_size, file_shape, progressBar=None, increment=1, debug=False): ''' Get translation data from image, using a Zero Normalized Cross Correlation based Lucas-Kanade algorithm.. :param mraw_path: Path to .mraw file containing image data. :param roi_reference: Upper left coordinate point of ROI, (y, x). :param roi_size: ROI size, (h, w) [px]. :param file_shape: Tuple, (ntotal, height, width) of images in .mraw file. :param increment: Only read every n-th image from sequence. :return: results: Numpy array, containing extracted data, shaped as [y, x, phi] arrays at given images. :return: iters: Array, number of iterations required to reach converegence for each image pair. :param: debug: If True, display debug output. ''' with open(mraw_path, 'rb') as mraw: memmap = np.memmap(mraw, dtype=np.uint16, mode='r', shape=file_shape) # Map to all images in file memmap = memmap[::increment] # Apply sequence increment N_inc = len(memmap) errors = {} # Initialize warnings dictionary # Precomputable stuff: roi_reference = np.asarray(roi_reference) F = _get_roi_image( memmap[0], roi_reference, roi_size) # First ROI image, used for the initial guess. Fx, Fy = dic.get_gradient(F) Fx2 = np.sum(Fx**2) Fy2 = np.sum(Fy**2) FxFy = np.sum(Fx * Fy) FxF = np.sum(Fx * F) FyF = np.sum(Fy * F) mean_F = np.mean(F) Fi = F - mean_F denominator = np.sum(Fi**2) results = np.array([[0, 0]], dtype=np.float64) # Initialize the results array. p_ref = roi_reference # Initialize a reference for all following calculations. # Loop through all the images in .mraw file: for i in range(1, len(memmap)): # First image was loaded already. d_int = np.round(results[-1]) # Last calculated integer translation. G = _get_roi_image(memmap[i], p_ref + d_int, roi_size) # Current image at integer location. mean_G = np.mean(G) Gi = G - mean_G # Optimization step: numerator = np.sum(Fi * Gi) a_opt = numerator / denominator b_opt = mean_G - mean_F * a_opt Gb = G - b_opt A = np.array([[Fx2, FxFy], [FxFy, Fx2]]) * a_opt b = np.array( [-a_opt * FxF + np.sum(Fx * Gb), -a_opt * FyF + np.sum(Fy * Gb)]) d = np.linalg.solve(A, b) # dx, dy results = np.vstack((results, d_int + d[::-1])) # y, x if progressBar: progressBar.setValue(i / N_inc * 100) # Update the progress bar. else: stdout_print_progress(i - 2, N_inc) # Print progress info to stdout. memmap._mmap.close() # Close the loaded memmap return results, increment