为什么Python OpenCV修改透视变换坐标后输出图像呈灰色?
问题修复方案
根因定位
- 角点排序函数逻辑错误:计算角点的
sum和diff时是对整个角点数组做全局计算,而非对每个角点的x、y坐标单独计算,导致角点排序完全错误,透视变换时源点和目标点无法正确匹配,最终图像内容无法正常渲染 - 翻转逻辑实现错误:沿y轴翻转的需求不需要修改透视变换目标点的坐标顺序,直接调用OpenCV内置翻转函数即可,乱改目标点顺序会导致透视变换矩阵计算异常
修复步骤
- 修正角点排序函数的计算逻辑,改为对每个角点的x+y求和、y-x求差
- 还原透视变换目标点坐标的原始定义,使用
cv.flip实现沿y轴翻转的需求
修复后完整代码
#Imports import cv2 as cv import numpy as np import math #Load image img = cv.imread('sudoku_test_image.jpeg') #Transforms perspective def perspectiveTransform(img, corners): def orderCornerPoints(corners): #Corners sperated into their own points #Index 0 = top-left # 1 = top-right # 2 = bottom-right # 3 = bottom-left #Corners to points corners = [(corner[0][0], corner[0][1]) for corner in corners] # 修正:对每个点单独计算x+y的和 add = [x + y for x, y in corners] top_l = corners[np.argmin(add)] bottom_r = corners[np.argmax(add)] # 修正:对每个点单独计算y-x的差 diff = [y - x for x, y in corners] top_r = corners[np.argmin(diff)] bottom_l = corners[np.argmax(diff)] return (top_l, top_r, bottom_r, bottom_l) ordered_corners = orderCornerPoints(corners) top_l, top_r, bottom_r, bottom_l = ordered_corners #Find width of new image (Using distance formula) width_A = np.sqrt(((bottom_r[0] - bottom_l[0]) ** 2) + ((bottom_r[1] - bottom_l[1]) ** 2)) width_B = np.sqrt(((top_r[0] - top_l[0]) ** 2) + ((top_r[1] - top_l[1]) ** 2)) width = max(int(width_A), int(width_B)) #Find height of new image (Using distance formula) height_A = np.sqrt(((top_r[0] - bottom_r[0]) ** 2) + ((top_r[1] - bottom_r[1]) ** 2)) height_B = np.sqrt(((top_l[0] - bottom_l[0]) ** 2) + ((top_l[1] - bottom_l[1]) ** 2)) height = max(int(height_A), int(height_B)) #Make top down view # 还原原始目标点定义,顺序和返回的ordered_corners对应 dimensions = np.array([[0, 0], [width, 0], [width, height], [0, height]], dtype = "float32") #Make ordered_corners var numpy format ordered_corners = np.array(ordered_corners, dtype = 'float32') #Transform the perspective m = cv.getPerspectiveTransform(ordered_corners, dimensions) transformed = cv.warpPerspective(img, m, (width, height)) # 新增:沿y轴翻转,满足翻转需求 transformed = cv.flip(transformed, 1) return transformed #Processes image (Grayscale, median blur, adaptive threshold) def processImage(img): gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) blur = cv.medianBlur(gray, 3) thresh = cv.adaptiveThreshold(blur,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV,11,3) return thresh #Find and sort contours img_processed = processImage(img) cnts = cv.findContours(img_processed, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] cnts = sorted(cnts, key=cv.contourArea, reverse=True) #Perform perspective transform peri = cv.arcLength(cnts[0], True) approx = cv.approxPolyDP(cnts[0], 0.01 * peri, True) transformed = perspectiveTransform(img, approx) #Draw lines height = transformed.shape[0] width = transformed.shape[1] #for vertical lines line_x = 0 x_increment_val = round((1/9) * width) #for horizontal lines line_y = 0 y_increment_val = round((1/9) * height) #vertical lines for i in range(10): cv.line(transformed, (line_x, 0), (line_x, height), (0, 0, 255), 1) line_x += x_increment_val #horizontal lines for i in range(10): cv.line(transformed, (0, line_y), (width, line_y), (0, 0, 255), 1) line_y += y_increment_val #Show image cv.imshow('Sudoku', transformed) cv.waitKey(0) cv.destroyAllWindows()
内容的提问来源于stack exchange,提问作者Abhijit Prajapati
相关产品推荐
相关产品推荐

