docs: def register(self, src, trg, trg_mask=None, src_mask=None):
          """ Implementation of pair-wise registration and warping using point-based matching
  
          This function estimates a number of transforms (Euler, PartialAffine and Homography) using point-based matching.
          Features descriptor are first extracted from the pair of images using either SIFT or SURF descriptors. A
          brute-force point-matching algorithm estimates matching points and a transformation is computed. All
          transformations use RANSAC to robustly fit a tranform to the matching points. However, the feature extraction
          and point matching estimation can be very poor and unstable. In those cases, an identity transform is used
          to warp the images instead.
  
          :param src: 2D single channel source moving image
          :param trg: 2D single channel target reference image
          :param trg_mask: Mask of target image. Not used in this method.
          :param src_mask: Mask of source image. Not used in this method.
          :return: Estimated 2D transformation matrix of shape 2x3
          """
          # Initialise matrix and failed registrations flag
          warp_matrix = None
          # Initiate point detector
          ptdt = cv2.xfeatures2d.SIFT_create() if self.params['Descriptor'] == 'SIFT' else cv2.xfeatures2d.SURF_create()
          # create BFMatcher object
          bf_matcher = cv2.BFMatcher(cv2.NORM_L1, crossCheck=True)
          # find the keypoints and descriptors with SIFT
          kp1, des1 = ptdt.detectAndCompute(self.rescale_image(src), None)
          kp2, des2 = ptdt.detectAndCompute(self.rescale_image(trg), None)
          # Match descriptors if any are found
          if des1 is not None and des2 is not None:
              matches = bf_matcher.match(des1, des2)
              # Sort them in the order of their distance.
              matches = sorted(matches, key=lambda x: x.distance)
              src_pts = np.asarray([kp1[m.queryIdx].pt for m in matches], dtype=np.float32).reshape(-1, 2)
              trg_pts = np.asarray([kp2[m.trainIdx].pt for m in matches], dtype=np.float32).reshape(-1, 2)
              # Parse model and estimate matrix
              if self.params['Model'] == 'PartialAffine':
                  warp_matrix = cv2.estimateRigidTransform(src_pts, trg_pts, fullAffine=False)
              elif self.params['Model'] == 'Euler':
                  model = EstimateEulerTransformModel(src_pts, trg_pts)
                  warp_matrix = ransac(src_pts.shape[0], model, 3, self.params['MaxIters'], 1, 5)
              elif self.params['Model'] == 'Homography':
                  warp_matrix, _ = cv2.findHomography(src_pts, trg_pts, cv2.RANSAC,
                                                      ransacReprojThreshold=self.params['RANSACThreshold'],
                                                      maxIters=self.params['MaxIters'])
                  if warp_matrix is not None:
                      warp_matrix = warp_matrix[:2, :]
          return warp_matrix