利用特征匹配定求解单应性矩阵

In [1]:

import cv2
import numpy as np
from matplotlib import pyplot as plt
from arknights_mower.utils.image import cropimg, loadimg, loadres
from arknights_mower.utils.matcher import (
    GOOD_DISTANCE_LIMIT,
    flann,
    keypoints_scale_invariant,
)

In [2]:

res = loadres("sanity", True)
plt.imshow(res, cmap="gray", vmin=0, vmax=255)
plt.show()
2024-07-16 21:01:18,429 - DEBUG - /home/zhao/Documents/arknights-mower/arknights_mower/utils/image.py:44 - loadimg - /home/zhao/Documents/arknights-mower/arknights_mower/resources/sanity.png

No description has been provided for this image

In [3]:

sc = loadimg("/home/zhao/Downloads/Screenshot_20240716-180721.png", True)
plt.imshow(sc, cmap="gray", vmin=0, vmax=255)
plt.show()
2024-07-16 21:01:18,783 - DEBUG - /home/zhao/Documents/arknights-mower/arknights_mower/utils/image.py:44 - loadimg - /home/zhao/Downloads/Screenshot_20240716-180721.png

No description has been provided for this image

In [4]:

img = cropimg(sc, ((1400, 000), (2000, 800)))
plt.imshow(img, cmap="gray", vmin=0, vmax=255)
plt.show()

No description has been provided for this image

In [5]:

kp1, des1 = keypoints_scale_invariant(res)
kp2, des2 = keypoints_scale_invariant(img)
bf = cv2.BFMatcher(cv2.NORM_HAMMING)
matches = flann.knnMatch(des1, des2, k=2)
good = []
for pair in matches:
    if (len_pair := len(pair)) == 2:
        m, n = pair
        if m.distance < GOOD_DISTANCE_LIMIT * n.distance:
            good.append(m)
    elif len_pair == 1:
        good.append(pair[0])
print(len(good))
src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
matchesMask = mask.ravel().tolist()
240

In [6]:

h, w = res.shape
pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2)
dst = cv2.perspectiveTransform(pts, M)
disp = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
disp = cv2.polylines(disp, [np.int32(dst)], True, (255, 0, 0), 2, cv2.LINE_AA)
good = sorted(good, key=lambda x: x.distance)
disp = cv2.drawMatches(
    res,
    kp1,
    disp,
    kp2,
    good[:50],
    None,
    (0, 255, 0),
    flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS,
)
plt.imshow(disp)
plt.show()

No description has been provided for this image

In [7]:

M

Out[7]:

array([[ 5.45219656e-01, -1.40243401e-02,  5.38688840e+01],
       [-6.00027151e-02,  6.48058168e-01,  2.06700298e+02],
       [-1.17835742e-04, -1.26823789e-05,  1.00000000e+00]])

In [8]:

offset = (80, 250)
A = np.array([[1, 0, -offset[0]], [0, 1, -offset[1]], [0, 0, 1]])

In [9]:

disp = cv2.warpPerspective(img, M.dot(A), (800, 1100), None, cv2.WARP_INVERSE_MAP)
plt.subplot(1, 2, 1)
plt.imshow(img, cmap="gray", vmin=0, vmax=255)
plt.subplot(1, 2, 2)
plt.imshow(disp, cmap="gray", vmin=0, vmax=255)
plt.show()

No description has been provided for this image