Source code for autocnet.matcher.naive_template

from math import floor
import cv2
import numpy as np
from scipy.ndimage.interpolation import zoom


[docs]def pattern_match_autoreg(template, image, subpixel_size=3, max_scaler=0.2, metric=cv2.TM_CCORR_NORMED): """ Call an arbitrary pattern matcher using a subpixel approach where a center of gravity using the correlation coefficients are used for subpixel alignment. Parameters ---------- template : ndarray The input search template used to 'query' the destination image image : ndarray The image or sub-image to be searched subpixel_size : int An odd integer that defines the window size used to compute the moments max_scaler : float The percentage offset to apply to the delta between the maximum correlation and the maximum edge correlation. metric : object The function to be used to perform the template based matching Options: {cv2.TM_CCORR_NORMED, cv2.TM_CCOEFF_NORMED, cv2.TM_SQDIFF_NORMED} In testing the first two options perform significantly better with Apollo data. Returns ------- x : float The x offset y : float The y offset max_corr : float The strength of the correlation in the range [-1, 1]. """ result = cv2.matchTemplate(image, template, method=metric) if metric == cv2.TM_SQDIFF or metric == cv2.TM_SQDIFF_NORMED: y, x = np.unravel_index(np.argmin(result, axis=None), result.shape) else: y, x = np.unravel_index(np.argmax(result, axis=None), result.shape) max_corr = result[(y,x)] upper = int(2 + floor(subpixel_size / 2)) lower = upper - 1 # x, y are the location of the upper left hand corner of the template in the image area = result[y-lower:y+upper, x-lower:x+upper] if area.shape != (subpixel_size+2, subpixel_size+2): print("Max correlation is too close to the boundary.") return None, None, 0, None # Find the max on the edges, scale just like autoreg (but why?) edge_max = np.max(np.vstack([area[0], area[-1], area[:,0], area[:,-1]])) internal = area[1:-1, 1:-1] mask = (internal > edge_max + max_scaler * (edge_max-max_corr)).flatten() empty = np.column_stack([np.repeat(np.arange(0,subpixel_size),subpixel_size), np.tile(np.arange(0,subpixel_size),subpixel_size), np.zeros(subpixel_size*subpixel_size)]) empty[:,-1] = internal.ravel() to_weight = empty[mask, :] # Average is the shift from y, x form average = np.average(to_weight[:,:2], axis=0, weights=to_weight[:,2]) # The center of the 3x3 window is 1.5,1.5, so the shift needs to be recentered to 0,0 y += (subpixel_size/2 - average[0]) x += (subpixel_size/2 - average[1]) # Compute the idealized shift (image center) y -= (image.shape[0] / 2) - (template.shape[0] / 2) x -= (image.shape[1] / 2) - (template.shape[1] / 2) return float(x), float(y), float(max_corr), result
[docs]def pattern_match(template, image, upsampling=16, metric=cv2.TM_CCOEFF_NORMED, error_check=False): """ Call an arbitrary pattern matcher using a subpixel approach where the template and image are upsampled using a third order polynomial. Parameters ---------- template : ndarray The input search template used to 'query' the destination image image : ndarray The image or sub-image to be searched upsampling : int The multiplier to upsample the template and image. func : object The function to be used to perform the template based matching Options: {cv2.TM_CCORR_NORMED, cv2.TM_CCOEFF_NORMED, cv2.TM_SQDIFF_NORMED} In testing the first two options perform significantly better with Apollo data. error_check : bool If True, also apply a different matcher and test that the values are not too divergent. Default, False. Returns ------- x : float The x offset y : float The y offset strength : float The strength of the correlation in the range [-1, 1]. """ print('template avg: ', template.mean()) print('image avg: ', image.mean()) if upsampling < 1: raise ValueError # Fit a 3rd order polynomial to upsample the images if upsampling != 1: u_template = zoom(template, upsampling, order=3) u_image = zoom(image, upsampling, order=3) else: u_template = template u_image = image result = cv2.matchTemplate(u_image, u_template, method=metric) _, max_corr, min_loc, max_loc = cv2.minMaxLoc(result) if metric == cv2.TM_SQDIFF or metric == cv2.TM_SQDIFF_NORMED: x, y = (min_loc[0], min_loc[1]) else: x, y = (max_loc[0], max_loc[1]) # Compute the idealized shift (image center) ideal_y = u_image.shape[0] / 2 ideal_x = u_image.shape[1] / 2 # Compute the shift from template upper left to template center y += (u_template.shape[0] / 2) x += (u_template.shape[1] / 2) x = (x - ideal_x) / upsampling y = (y - ideal_y) / upsampling return x, y, max_corr, result