OpenCV透视变换后:RoI片段/坐标回原图像失败求助
问题:RoI透视变换后逆变换及坐标映射异常
我需要从图像中提取RoI(感兴趣区域),基于该片段完成计算后,将片段转回原位置,或是把计算得到的坐标映射回原图像,但过程中遇到了问题。
提取RoI与透视变换代码
x, y, w, h = cv2.boundingRect(localized_mask) p1 = [x, y + h] p4 = [x, y] p3 = [x + w, y] p2 = [x + w, y + h] w1 = int(np.linalg.norm(np.array(p2) - np.array(p3))) w2 = int(np.linalg.norm(np.array(p4) - np.array(p1))) h1 = int(np.linalg.norm(np.array(p1) - np.array(p2))) h2 = int(np.linalg.norm(np.array(p3) - np.array(p4))) maxWidth = max(w1, w2) maxHeight = max(h1, h2) neighbor_points = [p1, p2, p3, p4] output_poins = np.float32( [ [0, 0], [0, maxHeight], [maxWidth, maxHeight], [maxWidth, 0], ] ) matrix = cv2.getPerspectiveTransform(np.float32(neighbor_points), output_poins) result = cv2.warpPerspective( mask, matrix, (maxWidth, maxHeight), cv2.INTER_LINEAR )
逆变换尝试及问题
我尝试用以下代码将片段转回原位置,但结果均为与片段或原图尺寸一致的全黑图像:
test2 = cv2.warpPerspective( result, matrix, (maxHeight, maxWidth), cv2.WARP_INVERSE_MAP ) test3 = cv2.warpPerspective( result, matrix, (img.shape[1], img.shape[0]), cv2.WARP_INVERSE_MAP )
手动坐标映射的问题
我更关注片段内的白色标记,于是尝试手动逆变换坐标,但得到的坐标(左上区域的白点)未处于预期位置:
inverse_matrix = cv2.invert(matrix)[1] inverse_left=[] for point in output_dict["left"]["knots"]: trans_point = [point.x, point.y] + [1] trans_point = np.float32(trans_point) x, y, z = np.dot(inverse_matrix, trans_point) new_x = np.uint8(x/z) new_y = np.uint8(y/z) inverse_left.append([new_x, new_y])
问题分析与解决方案
1. 核心问题:透视变换的点顺序不匹配
OpenCV的cv2.getPerspectiveTransform要求输入的源点和目标点必须保持一致的顺时针/逆时针顺序,否则生成的变换矩阵会完全错误,导致逆变换或坐标映射失效。你当前的源点(neighbor_points)和目标点(output_poins)顺序混乱,是所有问题的根源。
2. 修正后的透视变换实现
统一采用左上→右上→右下→左下的顺时针顺序定义点:
x, y, w, h = cv2.boundingRect(localized_mask) # 原图RoI的四个角,按顺时针顺序:左上、右上、右下、左下 src_points = np.float32([ [x, y], # 左上 [x + w, y], # 右上 [x + w, y + h], # 右下 [x, y + h] # 左下 ]) # 变换后图像的对应点,同样顺时针顺序 maxWidth = w maxHeight = h dst_points = np.float32([ [0, 0], [maxWidth, 0], [maxWidth, maxHeight], [0, maxHeight] ]) # 生成从原图RoI到变换后图像的透视矩阵 matrix = cv2.getPerspectiveTransform(src_points, dst_points) result = cv2.warpPerspective(mask, matrix, (maxWidth, maxHeight), cv2.INTER_LINEAR)
3. 正确执行逆变换(将片段转回原位置)
有两种可靠方式实现逆变换:
方式一:直接计算逆矩阵
# 计算透视矩阵的逆矩阵 inv_matrix = cv2.invert(matrix)[1] # 逆变换,输出尺寸为原图的宽高(注意:OpenCV中尺寸是(宽, 高)) restored_img = cv2.warpPerspective(result, inv_matrix, (img.shape[1], img.shape[0]))
方式二:重新生成逆变换矩阵
# 生成从变换后图像到原图RoI的透视矩阵 inv_matrix = cv2.getPerspectiveTransform(dst_points, src_points) restored_img = cv2.warpPerspective(result, inv_matrix, (img.shape[1], img.shape[0]))
4. 正确映射坐标到原图
修正点顺序后,手动逆变换坐标的逻辑即可正常工作,注意用int而非uint8避免坐标溢出(当坐标超过255时uint8会截断):
inv_matrix = cv2.invert(matrix)[1] inverse_left = [] for point in output_dict["left"]["knots"]: # 构造齐次坐标 [x, y, 1] trans_point = np.float32([point.x, point.y, 1]) # 矩阵乘法完成逆变换 x, y, z = np.dot(inv_matrix, trans_point) # 归一化得到原图绝对坐标 new_x = int(x / z) new_y = int(y / z) inverse_left.append([new_x, new_y])
内容的提问来源于stack exchange,提问作者maierf
相关产品推荐
相关产品推荐

