我有几张使用 ArUco 标记设置的桌子的图像。作为最终结果,我想要一个自上而下的坐标系,它定义桌子上标记的配置。
我设法使用代码检测到所有标记:
corners, ids = self.detect_aruco_markers(image)
随后,我使用现实生活中的标记大小来定义标记的坐标及其相对位置,并将它们正确地聚集到表格中。
但是,存在一个问题,即照片并不是完美地自上而下拍摄的。我在下面附上了示例图片。问题在于,在生成的坐标系中,标记会稍微旋转并从应有的位置移动。例如,应 x 或 y 对齐的标记不在生成的坐标系中。
为了解决这个问题,我想使用透视变换,使用单应性矩阵。但是,我无法确定到底将哪些点用作
cv2.getPerspectiveTransform
方法的“现实世界”参考点和源点。
我无法从上到下访问标记的真实世界坐标,因为每个输入图像都会发生变化。我所知道的是,标记的大小是固定的(给定的),并且它们都位于同一平面上,面朝上。
到目前为止,我尝试过使用凸包,但没有成功:
# Flatten the list of corners and convert to a NumPy array
src_points = np.concatenate(corners, axis=0).reshape(-1, 2)
# Compute the bounding box of the detected markers
x_min, y_min = np.min(src_points, axis=0)
x_max, y_max = np.max(src_points, axis=0)
# Define destination points for the perspective transform
dst_points = np.array([
[0, 0],
[x_max - x_min, 0],
[x_max - x_min, y_max - y_min],
[0, y_max - y_min]
], dtype=np.float32)
# Ensure src_points has exactly four points by selecting the outermost corners
if src_points.shape[0] > 4:
# Compute the convex hull to find the outermost corners
hull = cv2.convexHull(src_points)
if hull.shape[0] > 4:
# Approximate the hull to a quadrilateral
epsilon = 0.02 * cv2.arcLength(hull, True)
approx = cv2.approxPolyDP(hull, epsilon, True)
if approx.shape[0] == 4:
src_points = approx.reshape(4, 2)
else:
rect = cv2.minAreaRect(hull)
src_points = cv2.boxPoints(rect)
else:
src_points = hull.reshape(-1, 2)
elif src_points.shape[0] < 4:
raise ValueError("Not enough points to compute perspective transform.")
# Compute the perspective transform matrix
matrix = cv2.getPerspectiveTransform(src_points.astype(np.float32), dst_points)
# Warp the image using the transformation matrix
width = int(x_max - x_min)
height = int(y_max - y_min)
warped_image = cv2.warpPerspective(image, matrix, (width, height))
我的这种方法是否走在正确的轨道上?我应该如何进行?感谢您的帮助!
需要细化一些关键点,才能使用 ArUco 标记实现自上而下视图的准确透视变换。
确保您获得每个标记的四个角坐标(这些对于透视变换至关重要):
corners, ids, _ = cv2.aruco.detectMarkers(image, aruco_dict, parameters=parameters)
角将包含每个检测到的标记的四个角。
您需要在一致的自上而下视图中定义标记的“真实世界”坐标。例如,如果您知道桌子上标记的物理位置(例如,以毫米为单位),则可以为桌子定义直角坐标系
src_points 应该是图像中 ArUco 标记检测到的角点。选择形成感兴趣区域边界的四个标记(例如,表格的四个角)。从角数组中提取它们的角坐标。
根据上述内容和我添加的注释,请更新下面的示例代码。
import cv2
import numpy as np
table_width = 1000 # Replace with actual table width
table_height = 500 # Replace with actual table height
# Detect ArUco markers
corners, ids, _ = cv2.aruco.detectMarkers(image, aruco_dict, parameters=parameters)
if ids is not None and len(ids) >= 4:
marker_indices = [0, 1, 2, 3] # Replace with indices of boundary markers
# Get the source points from the corners of the selected markers
src_points = np.array([
corners[marker_indices[0]][0][0],
corners[marker_indices[1]][0][1],
corners[marker_indices[2]][0][2],
corners[marker_indices[3]][0][3]
], dtype=np.float32)
# Define destination points in real-world coordinates
dst_points = np.array([
[0, 0],
[table_width, 0],
[table_width, table_height],
[0, table_height]
], dtype=np.float32)
# Compute the perspective transform
matrix = cv2.getPerspectiveTransform(src_points, dst_points)
# Warp the image
warped_image = cv2.warpPerspective(image, matrix, (int(table_width), int(table_height)))
# Display the result
cv2.imshow("Warped Image", warped_image)
cv2.waitKey(0)
else:
print("Not enough markers detected to compute perspective transform.")