如何用Python将数独棋盘图像调整为完美正方形?
如何用Python将数独棋盘图像调整为完美正方形?
嗨,我来帮你搞定这个问题!要把非正方形的数独棋盘图像转换成完美正方形,最靠谱的方法是先校正可能存在的透视倾斜,再把数独区域精准转换成标准正方形——毕竟咱们要切81个小格子,必须保证棋盘是正的、四边等长才行。下面用Python结合OpenCV来实现,步骤清晰又好懂:
核心思路
数独棋盘本身是正方形,只是拍摄时可能会有角度倾斜、边缘裁剪不当的问题。我们要先从图像里定位出数独的完整轮廓,再通过透视变换把它拉成正的正方形,这样后续分割成81个小单元格就没问题了。
具体实现步骤
图像预处理:突出数独轮廓
先把彩色图像转成灰度图,再做二值化处理,让数独的线条和背景区分开,方便后续找轮廓。定位数独棋盘的轮廓
找出图像里所有的轮廓,筛选出面积最大的那个(大概率就是数独棋盘),然后用多边形近似得到棋盘的四个顶点。排序顶点并计算正方形尺寸
把四个顶点按「左上→右上→右下→左下」的顺序排好,然后计算棋盘的最大边长(因为数独是正方形,所以取宽和高中的最大值作为目标正方形的边长)。透视变换得到完美正方形
用透视变换矩阵把不规则的数独区域映射成标准正方形。
完整代码示例
import cv2 import numpy as np def get_sudoku_square(image_path): # 1. 读取图像并预处理 img = cv2.imread(image_path) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化(自适应阈值,适配不同光照) thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) # 2. 寻找数独轮廓 contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 筛选面积最大的轮廓 sudoku_contour = max(contours, key=cv2.contourArea) # 3. 获取并排序四个顶点 epsilon = 0.02 * cv2.arcLength(sudoku_contour, True) approx = cv2.approxPolyDP(sudoku_contour, epsilon, True) # 确保是四个顶点的矩形 if len(approx) != 4: raise ValueError("无法检测到数独棋盘的四个顶点,请检查图像清晰度") # 把顶点转换成(x,y)坐标并排序 points = approx.reshape(4, 2).astype(np.float32) # 按x+y从小到大排序(左上点最小) points = points[np.argsort(points.sum(axis=1))] # 右上和左下按x坐标排序 if points[1][0] < points[2][0]: points[1], points[2] = points[2], points[1] top_left, top_right, bottom_right, bottom_left = points # 4. 计算目标正方形的边长 width = int(max(np.linalg.norm(top_right - top_left), np.linalg.norm(bottom_right - bottom_left))) height = int(max(np.linalg.norm(bottom_left - top_left), np.linalg.norm(bottom_right - top_right))) square_size = max(width, height) # 目标正方形的四个顶点 dst_points = np.array([ [0, 0], [square_size - 1, 0], [square_size - 1, square_size - 1], [0, square_size - 1] ], dtype=np.float32) # 透视变换 M = cv2.getPerspectiveTransform(points, dst_points) sudoku_square = cv2.warpPerspective(img, M, (square_size, square_size)) return sudoku_square # 使用示例 square_sudoku = get_sudoku_square("your_sudoku_image.png") # 保存处理后的正方形图像 cv2.imwrite("square_sudoku.png", square_sudoku)
额外小贴士
- 如果你的图像没有透视倾斜,只是比例不对,也可以直接用
cv2.resize调整成正方形,但透视校正的方法更通用,能应对大多数拍摄角度的问题。 - 预处理时的二值化参数可以根据你的图像微调,比如调整自适应阈值的窗口大小,让数独轮廓更清晰。
备注:内容来源于stack exchange,提问作者Ernest Vandenbulcke




