使用 OpenCV 通过 ArUco 标记实现图像的自上而下视图

问题描述 投票:0回答:1

我有几张使用 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))

我的这种方法是否走在正确的轨道上?我应该如何进行?感谢您的帮助!

The example image

python opencv computer-vision aruco
1个回答
0
投票

需要细化一些关键点,才能使用 ArUco 标记实现自上而下视图的准确透视变换。

  1. 确保您获得每个标记的四个角坐标(这些对于透视变换至关重要):

    corners, ids, _ = cv2.aruco.detectMarkers(image, aruco_dict, parameters=parameters)
    

角将包含每个检测到的标记的四个角。

  1. 您需要在一致的自上而下视图中定义标记的“真实世界”坐标。例如,如果您知道桌子上标记的物理位置(例如,以毫米为单位),则可以为桌子定义直角坐标系

  2. 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.")
© www.soinside.com 2019 - 2024. All rights reserved.