|
import numpy as np |
|
import cv2 |
|
from typing import Tuple, List |
|
|
|
|
|
BONE_NAMES = [ |
|
"A0", "A8", |
|
"J0", "J8", |
|
] |
|
|
|
def check_keypoints(keypoints: np.ndarray): |
|
""" |
|
检查关键点坐标是否正确 |
|
@param keypoints: 关键点坐标, shape 为 (N, 2) |
|
""" |
|
if keypoints.shape != (len(BONE_NAMES), 2): |
|
raise Exception(f"keypoints shape error: {keypoints.shape}") |
|
def perspective_transform( |
|
image: cv2.UMat, |
|
src_points: np.ndarray, |
|
keypoints: np.ndarray, |
|
dst_size=(450, 500)) -> Tuple[cv2.UMat, np.ndarray, np.ndarray]: |
|
""" |
|
透视变换 |
|
@param image: 图片 |
|
@param src_points: 源点坐标 |
|
@param keypoints: 关键点坐标 |
|
@param dst_size: 目标尺寸 (width, height) 10 行 9 列 |
|
|
|
@return: |
|
result: 透视变换后的图片 |
|
transformed_keypoints: 透视变换后的关键点坐标 |
|
corner_points: 棋盘的 corner 点坐标, shape 为 (4, 2) A0, A8, J0, J8 |
|
""" |
|
|
|
check_keypoints(keypoints) |
|
|
|
|
|
|
|
src = np.float32(src_points) |
|
padding = 50 |
|
corner_points = np.float32([ |
|
|
|
[padding, padding], |
|
|
|
[dst_size[0]-padding, padding], |
|
|
|
[padding, dst_size[1]-padding], |
|
|
|
[dst_size[0]-padding, dst_size[1]-padding]]) |
|
|
|
|
|
matrix = cv2.getPerspectiveTransform(src, corner_points) |
|
|
|
|
|
result = cv2.warpPerspective(image, matrix, dst_size) |
|
|
|
|
|
keypoints_reshaped = keypoints.reshape(-1, 1, 2).astype(np.float32) |
|
transformed_keypoints = cv2.perspectiveTransform(keypoints_reshaped, matrix) |
|
|
|
transformed_keypoints = transformed_keypoints.reshape(-1, 2) |
|
|
|
return result, transformed_keypoints, corner_points |
|
|
|
|
|
|
|
def get_board_corner_points(keypoints: np.ndarray) -> np.ndarray: |
|
""" |
|
计算棋局四个边角的 points |
|
@param keypoints: 关键点坐标, shape 为 (N, 2) |
|
@return: 边角的坐标, shape 为 (4, 2) |
|
""" |
|
check_keypoints(keypoints) |
|
|
|
|
|
a0_index = BONE_NAMES.index("A0") |
|
a8_index = BONE_NAMES.index("A8") |
|
j0_index = BONE_NAMES.index("J0") |
|
j8_index = BONE_NAMES.index("J8") |
|
|
|
a0_xy = keypoints[a0_index] |
|
a8_xy = keypoints[a8_index] |
|
j0_xy = keypoints[j0_index] |
|
j8_xy = keypoints[j8_index] |
|
|
|
|
|
dst_points = np.array([ |
|
a0_xy, |
|
a8_xy, |
|
j0_xy, |
|
j8_xy |
|
], dtype=np.float32) |
|
|
|
return dst_points |
|
|
|
def extract_chessboard(img: cv2.UMat, keypoints: np.ndarray) -> Tuple[cv2.UMat, np.ndarray, np.ndarray]: |
|
""" |
|
提取棋盘信息 |
|
@param img: 图片 |
|
@param keypoints: 关键点坐标, shape 为 (N, 2) |
|
@return: |
|
transformed_image: 透视变换后的图片 |
|
transformed_keypoints: 透视变换后的关键点坐标 |
|
transformed_corner_points: 棋盘的 corner 点坐标, shape 为 (4, 2) A0, A8, J0, J8 |
|
""" |
|
|
|
check_keypoints(keypoints) |
|
|
|
source_corner_points = get_board_corner_points(keypoints) |
|
|
|
transformed_image, transformed_keypoints, transformed_corner_points = perspective_transform(img, source_corner_points, keypoints) |
|
|
|
return transformed_image, transformed_keypoints, transformed_corner_points |
|
|