Skip to content
Snippets Groups Projects
Select Git revision
  • 5398a27d470898f83e27a5f5619ca5e910f51619
  • main default protected
  • polar_bug_update
  • 553
  • subpixelapi
  • dev
  • rq
  • 602-replace-print-warnings-with-proper-logging
  • dependabot/pip/protobuf-3.15.0
  • github/fork/readthedocs-assistant/update-rtd-config-assistant
  • github/fork/acpaquette/scipy_0.19_update
  • github/fork/gsn9/loggingForMatcher
  • ladoramkershner-logos
  • jlaura-patch-1
  • 1.2.2
  • v1.2.1
  • v1.2.0
  • v1.1.0
  • v1.0.2
  • 1.0.1
  • v1.0.0-rc2
  • v1.0.0-rc1
  • v0.7.1
  • v0.7.0
  • v0.6.0
  • v0.4.0
  • 0.1.0
27 results

naive_template.py

Blame
  • naive_template.py 7.01 KiB
    import logging
    from math import floor
    
    import cv2
    import numpy as np
    
    from scipy.ndimage import center_of_mass
    from skimage.transform import rescale
    from skimage.util import img_as_float32
    try:
        from image_registration import chi2_shift
    except:
        chi2_shift = None
    
    
    log = logging.getLogger(__name__)
    
    def _template_match(image, template, metric):
        template = img_as_float32(template)
        image = img_as_float32(image)
        
        # If image is WxH and templ is wxh  , then result is (W-w)+1, (H-h)+1 .
        w, h = template.shape[::-1]
        corrmap = cv2.matchTemplate(image, template, method=metric)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(corrmap)
        if metric in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
            top_left = min_loc
            max_corr = min_val
        else:
            top_left = max_loc
            max_corr = max_val
        # This is the location in the image where the match has occurred.
        # I need the shift in the template needed to get into alignment (so the inverse!)
        # Need to take the initial location in the image and diff the updated location.
        matched_x = top_left[0] + w//2
        matched_y = top_left[1] + h//2
        assert max_corr == np.max(corrmap)
        return matched_x, matched_y, max_corr, corrmap
    
    def pattern_match_chi2(image, template, usfac=16):
        assert image.shape == template.shape
    
        # Swapped so that we get the adjustment to the image to match the template
        # like the other matchers.
        if chi2_shift is None:
            raise ValueError("chi2_shift function is not defined. You need to install the 'image_registration' package with 'pip install image_registration'.")
    
        dx, dy, err_x, err_y = chi2_shift(image, template, return_error=True, upsample_factor=usfac, boundary='constant')
        shape_y, shape_x = np.array(template.shape)//2
        err =  (err_x + err_y) / 2.
        return shape_x-dx, shape_y-dy, err, None
    
    
    def pattern_match_autoreg(image, template, subpixel_size=5, metric=cv2.TM_CCOEFF_NORMED, upsampling=16):
        """
        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].
        """
    
        x, y, max_corr, corrmap = _template_match(image, template, metric)
       
        maxy, maxx = np.unravel_index(corrmap.argmax(), corrmap.shape)
        area = corrmap[maxy - subpixel_size:maxy + subpixel_size + 1,
                       maxx - subpixel_size:maxx + subpixel_size + 1]
    
        # # If the area is not square and large enough, this method should fail
        # if area.shape != (subpixel_size+2, subpixel_size+2):
        #     raise Exception("Max correlation is too close to the boundary.")
        #     # return None, None, 0, None
    
        cmass = center_of_mass(area)
    
        subpixel_y_shift = subpixel_size - 1 - cmass[0]
        subpixel_x_shift = subpixel_size - 1 - cmass[1]
        
        # Apply the subpixel shift to the whole pixel shifts computed above
        y += subpixel_y_shift
        x += subpixel_x_shift
        return x, y, max_corr, corrmap
    
    def pattern_match(image, template, upsampling=8, metric=cv2.TM_CCOEFF_NORMED):
        """
        Call an arbitrary pattern matcher using a subpixel approach where the template and image
        are upsampled using a third order polynomial.
    
        This function assumes that the image center (0,0) and template center (0,0) are the a priori
        coordinates. This function returns the offset to the center of the template such that the 
        template is brought into alignment with the image.
    
        For example, if the image to be searched appears as follow:
    
        0, 0, 0, 0, 0, 0, 0, 1, 0
        0, 0, 0, 0, 0, 0, 0, 1, 0
        1, 1, 1, 0, 0, 0, 0, 1, 0
        0, 1, 0, 0, 0, 0, 0, 0, 0
        0, 1, 0, 0, 0, 0, 0, 0, 0
        0, 0, 0, 0, 0, 0, 0, 0, 0
        0, 0, 0, 0, 0, 0, 0, 0, 0
        0, 0, 0, 0, 0, 0, 0, 0, 0
        0, 0, 0, 0, 0, 0, 1, 1, 1
        0, 1, 1, 1, 0, 0, 1, 0, 1
        0, 1, 0, 1, 0, 0, 1, 0, 1
        0, 1, 1, 1, 0, 0, 1, 0, 1
        0, 0, 0, 0, 0, 0, 1, 1, 1
    
        and the template image is: 
    
        1, 1, 1
        0, 1, 0
        0, 1, 0 
    
        the expected shift from the center of the search image to have template image align is -3 in
        the y-direction and -3 in the x-direction. Conversely, if the search image is:
    
        1, 1, 1
        1, 0, 1
        1, 0, 1
        1, 0, 1
        1, 1, 1         
    
        the expected shift is 4 in the y-direction and 3 in the x-direction.
    
        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.
    
        Returns
        -------
        x : float
            The x offset of the template center the image center, the inverse of this shift will 
            need to be applied to the template as a correction.
        y : float
            The y offset of the template center to the image center, the inverse of this shift
            will need to be applied to the template as a correction.
        max_corr : float
                   The strength of the correlation in the range [-1, 1].
        result : ndarray
                 (m,n) correlation matrix showing the correlation for all tested coordinates. The
                 maximum correlation is reported where the upper left hand corner of the template
                 maximally correlates with the image.
        """
        if upsampling < 1:
            raise ValueError
    
        # Fit a 3rd order polynomial to upsample the images
        if upsampling != 1:
            u_template = rescale(template, upsampling, order=3, mode='edge')
            u_image = rescale(image, upsampling, order=3, mode='edge')
        else:
            u_template = template
            u_image = image
     
        # new_x, new_y is the updated center location in the image
        new_x, new_y, max_corr, corrmap = _template_match(u_image, u_template, metric)
        new_x /= upsampling
        new_y /= upsampling
    
        return new_x, new_y, max_corr, corrmap