<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 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