code: def applyFeaures(self, raw_frame, detections=None):
      # Initialize
      height, width, _ = raw_frame.shape
      frame = cv2.cvtColor(raw_frame, cv2.COLOR_BGR2GRAY)
      H = np.eye(2, 3)
  
      # Downscale image (TODO: consider using pyramids)
      if self.downscale > 1.0:
          # frame = cv2.GaussianBlur(frame, (3, 3), 1.5)
          frame = cv2.resize(
              frame, (width // self.downscale, height // self.downscale)
          )
          width = width // self.downscale
          height = height // self.downscale
  
      # find the keypoints
      mask = np.zeros_like(frame)
      # mask[int(0.05 * height): int(0.95 * height), int(0.05 * width): int(0.95 * width)] = 255
      mask[
          int(0.02 * height) : int(0.98 * height),
          int(0.02 * width) : int(0.98 * width),
      ] = 255
      if detections is not None:
          for det in detections:
              tlbr = (det[:4] / self.downscale).astype(np.int_)
              mask[tlbr[1] : tlbr[3], tlbr[0] : tlbr[2]] = 0
  
      keypoints = self.detector.detect(frame, mask)
  
      # compute the descriptors
      keypoints, descriptors = self.extractor.compute(frame, keypoints)
  
      # Handle first frame
      if not self.initializedFirstFrame:
          # Initialize data
          self.prevFrame = frame.copy()
          self.prevKeyPoints = copy.copy(keypoints)
          self.prevDescriptors = copy.copy(descriptors)
  
          # Initialization done
          self.initializedFirstFrame = True
  
          return H
  
      # Match descriptors.
      knnMatches = self.matcher.knnMatch(
          self.prevDescriptors, descriptors, 2
      )
  
      # Filtered matches based on smallest spatial distance
      matches = []
      spatialDistances = []
  
      maxSpatialDistance = 0.25 * np.array([width, height])
  
      # Handle empty matches case
      if len(knnMatches) == 0:
          # Store to next iteration
          self.prevFrame = frame.copy()
          self.prevKeyPoints = copy.copy(keypoints)
          self.prevDescriptors = copy.copy(descriptors)
  
          return H
  
      for m, n in knnMatches:
          if m.distance < 0.9 * n.distance:
              prevKeyPointLocation = self.prevKeyPoints[m.queryIdx].pt
              currKeyPointLocation = keypoints[m.trainIdx].pt
  
              spatialDistance = (
                  prevKeyPointLocation[0] - currKeyPointLocation[0],
                  prevKeyPointLocation[1] - currKeyPointLocation[1],
              )
  
              if (
                  np.abs(spatialDistance[0]) < maxSpatialDistance[0]
              ) and (
                  np.abs(spatialDistance[1]) < maxSpatialDistance[1]
              ):
                  spatialDistances.append(spatialDistance)
                  matches.append(m)
  
      meanSpatialDistances = np.mean(spatialDistances, 0)
      stdSpatialDistances = np.std(spatialDistances, 0)
  
      inliesrs = (
          spatialDistances - meanSpatialDistances
      ) < 2.5 * stdSpatialDistances
  
      goodMatches = []
      prevPoints = []
      currPoints = []
      for i in range(len(matches)):
          if inliesrs[i, 0] and inliesrs[i, 1]:
              goodMatches.append(matches[i])
              prevPoints.append(
                  self.prevKeyPoints[matches[i].queryIdx].pt
              )
              currPoints.append(keypoints[matches[i].trainIdx].pt)
  
      prevPoints = np.array(prevPoints)
      currPoints = np.array(currPoints)
  
      # Draw the keypoint matches on the output image
      if 0:
          matches_img = np.hstack((self.prevFrame, frame))
          matches_img = cv2.cvtColor(matches_img, cv2.COLOR_GRAY2BGR)
          W = np.size(self.prevFrame, 1)
          for m in goodMatches:
              prev_pt = np.array(
                  self.prevKeyPoints[m.queryIdx].pt, dtype=np.int_
              )
              curr_pt = np.array(
                  keypoints[m.trainIdx].pt, dtype=np.int_
              )
              curr_pt[0] += W
              color = np.random.randint(0, 255, (3,))
              color = (int(color[0]), int(color[1]), int(color[2]))
  
              matches_img = cv2.line(
                  matches_img,
                  prev_pt,
                  curr_pt,
                  tuple(color),
                  1,
                  cv2.LINE_AA,
              )
              matches_img = cv2.circle(
                  matches_img, prev_pt, 2, tuple(color), -1
              )
              matches_img = cv2.circle(
                  matches_img, curr_pt, 2, tuple(color), -1
              )
  
          plt.figure()
          plt.imshow(matches_img)
          plt.show()
  
      # Find rigid matrix
      if (np.size(prevPoints, 0) > 4) and (
          np.size(prevPoints, 0) == np.size(prevPoints, 0)
      ):
          H, inliesrs = cv2.estimateAffinePartial2D(
              prevPoints, currPoints, cv2.RANSAC
          )
  
          # Handle downscale
          if self.downscale > 1.0:
              H[0, 2] *= self.downscale
              H[1, 2] *= self.downscale
      else:
          print("Warning: not enough matching points")
  
      # Store to next iteration
      self.prevFrame = frame.copy()
      self.prevKeyPoints = copy.copy(keypoints)
      self.prevDescriptors = copy.copy(descriptors)
  
      return H
  
file_path: PaddleDetection/deploy/pptracking/python/mot/motion/gmc.py
imports: import cv2
  import matplotlib.pyplot
  import numpy
  import copy
  import time
label_desc: Use image node_id 4 for calling the GMC obj's underlying member method code with example usage: obj.applyFeaures(raw_frame, detections) and returns: H, H, H