基于Python的表格内手写数字定位与检测技术求助
表格单元格手写数字检测完整流程
你已经通过腐蚀膨胀提取表格结构,接下来可以按以下步骤完成单元格定位与数字检测:
一、完善表格结构提取
你当前的腐蚀膨胀仅处理了单方向线条,需要合并水平与垂直线条得到完整表格结构:
import cv2 import numpy as np img = cv2.imread("test.jpg") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 自适应阈值比固定阈值更适配手写表格的明暗差异 _, img_bin = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # 提取水平表格线 horiz_kernel = np.ones((1, 50), np.uint8) horiz_lines = cv2.morphologyEx(img_bin, cv2.MORPH_OPEN, horiz_kernel, iterations=2) # 提取垂直表格线 vert_kernel = np.ones((50, 1), np.uint8) vert_lines = cv2.morphologyEx(img_bin, cv2.MORPH_OPEN, vert_kernel, iterations=2) # 合并水平与垂直线条,膨胀让线条更连贯 table_struct = cv2.addWeighted(horiz_lines, 0.5, vert_lines, 0.5, 0.0) table_struct = cv2.dilate(table_struct, np.ones((3,3), np.uint8), iterations=2)
二、定位所有单元格
通过轮廓提取锁定表格主体,再分割出单个单元格:
# 提取表格的外轮廓(取面积最大的轮廓即为整个表格) contours, _ = cv2.findContours(table_struct, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) table_contour = max(contours, key=cv2.contourArea) x_table, y_table, w_table, h_table = cv2.boundingRect(table_contour) table_roi = img_bin[y_table:y_table+h_table, x_table:x_table+w_table] # 反向提取单元格区域(表格内的空白区域即为单元格) inverted_table = cv2.bitwise_not(table_roi) cell_contours, _ = cv2.findContours(inverted_table, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 筛选有效单元格:排除噪点类小轮廓,保留符合尺寸的区域 cells = [] for cnt in cell_contours: area = cv2.contourArea(cnt) if 1000 < area < 50000: # 尺寸范围根据你的表格实际调整 x_cell, y_cell, w_cell, h_cell = cv2.boundingRect(cnt) # 转换回原图坐标 cells.append((x_cell + x_table, y_cell + y_table, w_cell, h_cell)) # 按行排序单元格(先按纵向y坐标,再按横向x坐标) cells.sort(key=lambda c: (c[1], c[0]))
三、单元格内数字预处理
对每个单元格的数字做标准化处理,方便后续识别:
processed_digits = [] for (x, y, w, h) in cells: # 提取单元格灰度区域 cell_roi = gray[y:y+h, x:x+w] # 自适应阈值二值化 _, digit_bin = cv2.threshold(cell_roi, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # 去除小噪点 digit_bin = cv2.morphologyEx(digit_bin, cv2.MORPH_OPEN, np.ones((2,2), np.uint8), iterations=1) # 调整为MNIST标准的28x28尺寸(适配多数数字识别模型) digit_resized = cv2.resize(digit_bin, (28, 28)) processed_digits.append(digit_resized)
四、数字识别
新手可以选择两种简单实现方式:
方法1:OpenCV KNN算法(快速上手)
# 需提前准备MNIST训练数据(将训练集转为(样本数,784)的数组,标签为对应数字) knn = cv2.ml.KNearest_create() knn.train(train_data, cv2.ml.ROW_SAMPLE, train_labels) # 逐个识别数字 for digit in processed_digits: test_data = digit.reshape(1, 784).astype(np.float32) _, result, _, _ = knn.findNearest(test_data, k=5) print("识别结果:", int(result[0][0]))
方法2:深度学习模型(更准确)
用TensorFlow/Keras加载预训练的MNIST模型,直接输入处理好的28x28图像即可得到识别结果,适合需要更高准确率的场景。
关键调整点
- 阈值适配:如果表格线条模糊,可替换为
cv2.adaptiveThreshold做局部阈值处理 - 轮廓筛选:根据表格实际大小调整单元格面积的筛选范围
- 噪点去除:若单元格内有多余噪点,可增大形态学操作的核尺寸
内容的提问来源于stack exchange,提问作者user21339606
相关产品推荐
相关产品推荐

