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

如何用OpenCV和Python检测图像中4×4字母网格的位置

4×4字母网格OCR优化方案

方案一:优化轮廓筛选逻辑(解决内外轮廓与干扰问题)

针对O、P这类带内轮廓的字母,以及干扰物问题,可以通过以下调整简化筛选:

  • 仅提取外轮廓:使用cv2.RETR_EXTERNAL模式提取轮廓,直接忽略字母的内轮廓,避免内轮廓被误判为独立字符。
  • 多维度过滤:除面积外,结合外接矩形的宽高比、尺寸一致性以及位置分布筛选:
    1. 计算每个轮廓的外接矩形x,y,w,h,过滤掉宽高比偏离常规字母(比如0.5-2.0)的轮廓;
    2. 统计所有候选轮廓的平均宽高,过滤掉尺寸超出平均值±30%的干扰物;
    3. 计算所有轮廓的中心坐标(x+w/2, y+h/2),按x坐标排序分成4列,按y坐标排序分成4行,只保留每行列中位置符合网格规律的轮廓(比如列内中心x值接近,行内中心y值接近)。

示例代码:

import cv2
import numpy as np

# 预处理
img = cv2.imread('grid_image.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# 提取外轮廓
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 筛选候选轮廓
candidates = []
for cnt in contours:
    x, y, w, h = cv2.boundingRect(cnt)
    area = cv2.contourArea(cnt)
    # 过滤过小/过大的面积,以及宽高比异常的
    if 100 < area < 5000 and 0.5 < w/h < 2.0:
        candidates.append((x, y, w, h, (x+w/2, y+h/2)))

# 按位置分组为4×4网格
# 先按y坐标排序分4行
candidates.sort(key=lambda x: x[4][1])
rows = np.array_split(candidates, 4)
grid_cells = []
for row in rows:
    # 每行按x坐标排序分4列
    row.sort(key=lambda x: x[4][0])
    grid_cells.extend(row[:4])  # 取前4个符合的

# 裁剪并识别每个字符
import pytesseract
pytesseract.pytesseract.tesseract_cmd = r'your_tesseract_path'
result = []
for (x, y, w, h, _) in grid_cells:
    char_img = thresh[y:y+h, x:x+w]
    # 用--psm 10指定单字符识别
    char = pytesseract.image_to_string(char_img, config='--psm 10 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ')
    result.append(char.strip())

# 整理为4×4结果
final_grid = np.array(result).reshape(4,4)
print(final_grid)

方案二:模糊生成Blob + 网格模式检测

通过模糊让字母变为实心Blob,消除内轮廓干扰,再利用4×4网格的规则性筛选:

  1. 模糊处理:用高斯模糊cv2.GaussianBlur让字母边缘融合成实心块,核大小根据字母尺寸调整(比如(7,7));
  2. 二次二值化:模糊后再次用OTSU二值化,此时字母为实心区域,无内轮廓;
  3. Blob筛选与网格验证:提取外轮廓后,验证轮廓数量接近16,再通过中心坐标的行列分布确认4×4网格结构,过滤干扰Blob;
  4. 单字符识别:裁剪每个Blob区域,用Tesseract单字符模式识别。

示例代码:

import cv2
import numpy as np
import pytesseract

img = cv2.imread('grid_image.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 模糊生成Blob
blurred = cv2.GaussianBlur(gray, (7,7), 0)
_, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# 提取外轮廓
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 筛选Blob:面积符合字母范围
blob_candidates = []
for cnt in contours:
    area = cv2.contourArea(cnt)
    if 200 < area < 6000:  # 调整阈值适配你的图像
        x, y, w, h = cv2.boundingRect(cnt)
        blob_candidates.append((x, y, w, h, (x+w/2, y+h/2)))

# 验证4×4网格:按中心坐标排序分组
if len(blob_candidates) >=16:
    # 按y坐标分4行
    blob_candidates.sort(key=lambda x: x[4][1])
    rows = np.array_split(blob_candidates, 4)
    final_blobs = []
    for row in rows:
        # 每行按x坐标取前4个(确保4列)
        row.sort(key=lambda x: x[4][0])
        final_blobs.extend(row[:4])
    
    # 识别每个字符
    result = []
    for (x, y, w, h, _) in final_blobs:
        char_img = thresh[y:y+h, x:x+w]
        char = pytesseract.image_to_string(char_img, config='--psm 10 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ')
        result.append(char.strip())
    
    final_grid = np.array(result).reshape(4,4)
    print(final_grid)
else:
    print("未检测到足够的Blob,请调整模糊核或面积阈值")

方案三:基于网格线的单元格分割

如果图像中存在网格边框,可以直接分割单元格:

  1. 提取网格线:用形态学操作,先创建水平和垂直结构元素,分别做开运算提取水平线和垂直线,合并后得到网格线掩码;
  2. 检测线条交点:通过霍夫直线检测或轮廓提取,找到网格线的交点,计算出4×4单元格的坐标;
  3. 裁剪单元格并识别:对每个单元格单独预处理后识别。

示例代码(提取网格线部分):

import cv2
import numpy as np

img = cv2.imread('grid_image.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# 提取水平线
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (20,1))
horizontal_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)

# 提取垂直线
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,20))
vertical_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)

# 合并网格线
grid_lines = cv2.addWeighted(horizontal_lines, 1, vertical_lines, 1, 0)

# 提取网格线轮廓,找到交点
contours, _ = cv2.findContours(grid_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 后续可通过轮廓的外接矩形或直线检测计算单元格坐标,此处省略具体交点计算逻辑

内容的提问来源于stack exchange,提问作者pilu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 03:15:48