You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么Python OpenCV修改透视变换坐标后输出图像呈灰色?

问题修复方案

根因定位

  • 角点排序函数逻辑错误:计算角点的sum和diff时是对整个角点数组做全局计算,而非对每个角点的x、y坐标单独计算,导致角点排序完全错误,透视变换时源点和目标点无法正确匹配,最终图像内容无法正常渲染
  • 翻转逻辑实现错误:沿y轴翻转的需求不需要修改透视变换目标点的坐标顺序,直接调用OpenCV内置翻转函数即可,乱改目标点顺序会导致透视变换矩阵计算异常

修复步骤

  1. 修正角点排序函数的计算逻辑,改为对每个角点的x+y求和、y-x求差
  2. 还原透视变换目标点坐标的原始定义,使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 02:36:04