Python OCR识别数独图像为数字网格 现有代码运行结果不符预期
数独OCR识别代码修复方案
你现有代码无法输出预期的结构化数独网格,核心问题如下:
- 轮廓分组逻辑错误:靠累计9个轮廓就归为一行的逻辑完全不可靠,
findContours会返回数独外框、残留噪点等多余轮廓,分组必然错位。 - 缺少透视矫正环节:测试样例中的数独存在倾斜变形,直接在原图上分割单元格会出现行列不对齐、大小不一的问题。
- 无OCR识别环节:原有代码仅实现了单元格弹窗预览,没有数字识别逻辑,无法输出结构化数字结果。
- 形态学参数硬编码:固定的核大小、迭代次数对样例图适配差,修复网格线时要么残留数字笔画,要么糊住单元格区域。
测试用数独样例图如下:
修复后实现逻辑
调整流程后稳定性大幅提升,不需要手动调大量轮廓筛选参数:
- 预处理后定位数独外边框的四边形轮廓
- 通过透视变换将倾斜的数独矫正为450450的标准正方形,每个单元格固定为5050像素
- 直接按固定尺寸切分81个单元格,省略不稳定的轮廓排序步骤
- 对每个单元格做笔画占比判断,空单元格填0,有数字的单元格调用Tesseract做单字符OCR识别
- 最终输出9*9的结构化数独网格
可运行代码
先安装依赖:pip install opencv-python imutils numpy pytesseract
注意:除了Python包,还需要安装Tesseract OCR引擎本体,Windows用户如果没把Tesseract加入系统环境变量,需要在代码中指定
tesseract_cmd的本地路径。
import cv2 import numpy as np import pytesseract from imutils.perspective import four_point_transform # Windows用户未配置环境变量时取消注释,修改为自己的Tesseract安装路径 # pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe' # 读取并预处理图像 image = cv2.imread('Sample.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray, (7, 7), 0) thresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) # 定位数独外边框(最大的四边形轮廓) cnts, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = sorted(cnts, key=cv2.contourArea, reverse=True) sudoku_contour = None for c in cnts: perimeter = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.02 * perimeter, True) if len(approx) == 4: sudoku_contour = approx break # 透视矫正为450*450的标准正方形 warped = four_point_transform(image, sudoku_contour.reshape(4, 2)) warped_gray = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY) warped_thresh = cv2.adaptiveThreshold(warped_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 21, 5) # 切分单元格并识别数字 sudoku_grid = [] cell_size = 50 # 450 / 9 = 50,每个单元格固定50*50像素 for row_idx in range(9): current_row = [] for col_idx in range(9): # 裁掉单元格边缘5像素,避免把网格线纳入识别区域 cell = warped_thresh[ row_idx*cell_size + 5 : (row_idx+1)*cell_size - 5, col_idx*cell_size + 5 : (col_idx+1)*cell_size - 5 ] # 统计白色像素(数字笔画)占比,占比过低判定为空格 non_zero_ratio = cv2.countNonZero(cell) / (cell.shape[0] * cell.shape[1]) if non_zero_ratio < 0.05: current_row.append(0) continue # 配置Tesseract为单字符识别模式,仅识别1-9数字 ocr_config = '--psm 10 -c tessedit_char_whitelist=123456789' recognize_res = pytesseract.image_to_string(cell, config=ocr_config).strip() current_row.append(int(recognize_res) if recognize_res.isdigit() else 0) sudoku_grid.append(current_row) # 输出结构化结果 print("识别得到的数独网格(0代表空格):") for row in sudoku_grid: print(row) # 预览矫正后的数独图像 cv2.imshow("Warped Sudoku", warped) cv2.waitKey(0) cv2.destroyAllWindows()
运行说明
- 将数独样例图命名为
Sample.jpg放在脚本同目录下运行 - 运行后控制台会直接打印9*9的数独列表,0对应该位置没有数字
- 如果识别准确率不够,可以调整二值化参数,或者对单元格做额外的腐蚀/膨胀预处理优化数字显示
内容的提问来源于stack exchange,提问作者YasserKhalil
相关产品推荐
相关产品推荐

