OpenCV透视矫正报IndexError,如何输出原图而非二值mask?
报错修复与彩色校正实现方案
1. IndexError 报错原因
报错触发位置为find_corners函数中coor = np.float32([box[0], box[1], box[3], box[2]])行:cv2.approxPolyDP多边形拟合的角点数量受epsilon参数影响,当拟合结果只有3个角点时,box数组长度为3,访问下标3就会触发轴0越界错误。
2. 报错修复方法
在多边形拟合逻辑后增加角点数量校验,动态调整epsilon值保证拟合得到4个角点,修改后的find_corners核心片段如下:
def find_corners(im): cnts = cv2.findContours(im, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] c = max(cnts, key=cv2.contourArea) # 调整epsilon直到拟合出4个角点 epsilon = 0.1*cv2.arcLength(c, True) box = cv2.approxPolyDP(c, epsilon, True) while len(box) != 4 and epsilon < 0.3: epsilon += 0.02 box = cv2.approxPolyDP(c, epsilon, True) if len(box) !=4: raise ValueError("图像中未检测到符合要求的四边形区域") tmp_im = cv2.cvtColor(im, cv2.COLOR_GRAY2BGR) cv2.drawContours(tmp_im, [box], 0, (0, 255, 0), 2) cv2.imshow("tmp_im", tmp_im) box = np.squeeze(box).astype(np.float32) M = cv2.moments(c) cx = M['m10']/M['m00'] cy = M['m01']/M['m00'] center_xy = np.array([cx, cy]) cbox = box - center_xy ang = np.arctan2(cbox[:,1], cbox[:,0]) * 180 / np.pi box = box[ang.argsort()] coor = np.float32([box[0], box[1], box[3], box[2]]) return coor
3. 原始彩色区域校正实现
不需要额外做mask叠加,只要新增读取原始彩色图像的逻辑,用已经计算得到的透视变换矩阵P对彩色图像做变换即可,完整执行逻辑如下:
# 读取灰度图用于检测角点 input_gray = cv2.imread("/home/hamza/Desktop/cards/card2.jpeg", cv2.IMREAD_GRAYSCALE) input_gray = cv2.threshold(input_gray, 0, 255, cv2.THRESH_OTSU)[1] # 读取彩色原图用于最终校正输出 input_color = cv2.imread("/home/hamza/Desktop/cards/card2.jpeg") # 计算角点和透视变换矩阵 orig_im_coor = find_corners(input_gray) height, width = 450, 350 new_image_coor = np.float32([[0, 0], [width, 0], [0, height], [width, height]]) P = cv2.getPerspectiveTransform(orig_im_coor, new_image_coor) # 对彩色原图做透视变换得到彩色校正结果 perspective_color = cv2.warpPerspective(input_color, P, (width, height)) cv2.imshow("彩色校正结果", perspective_color) cv2.waitKey(0) cv2.destroyAllWindows()
可选优化方案
如果需要保留mask区域以外的部分为黑色,可在校正后用二值mask做按位与操作:
# 先得到校正后的二值mask perspective_mask = cv2.warpPerspective(input_gray, P, (width, height)) # mask扩展为3通道和彩色图匹配 mask_3ch = cv2.cvtColor(perspective_mask, cv2.COLOR_GRAY2BGR) # 按位与得到仅mask区域为彩色的结果 perspective_color_masked = cv2.bitwise_and(perspective_color, mask_3ch)
内容的提问来源于stack exchange,提问作者Hamza
相关产品推荐
相关产品推荐

