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

如何使用Python和OpenCV实现发票图像的文本块分割?Kmeans及轮廓检测尝试后遇异常

我来帮你搞定发票文本区域提取的问题!先聊聊你现有方法的问题,再给你靠谱的解决方案:

问题分析

1. Kmeans方法的问题

你用Kmeans做颜色聚类的思路本身就不太适合文本区域提取——发票的文本和背景颜色差异往往不大,聚类结果容易把无关区域混在一起。另外你的代码还有个小bug:聚类后res.reshape((img.shape))里的img已经被你reshape成二维数组了,应该用原始图像的形状来恢复。而且cv2.waitKey(2)时间太短,窗口会一闪而过,改成waitKey(0)才能正常查看结果。

2. 轮廓检测的问题

你当前的轮廓检测会提取所有小轮廓(包括单个字母),是因为没做预处理合并相邻文本块,而且用了cv2.RETR_LIST这种会返回所有层级轮廓的模式,导致单个字母都被框出来了。

解决方案:改进的OpenCV文本区域提取流程

下面是针对发票场景优化的完整流程,能准确提取整个文本段的区域:

步骤拆解

  1. 预处理:降噪+自适应二值化(适配发票光照不均的情况)+ 形态学膨胀(合并同一行的字母成一个连通块)
  2. 轮廓提取:只取最外层轮廓,过滤掉噪声小轮廓
  3. 区域提取:把每个文本段单独保存成小图像

完整代码

import cv2
import numpy as np

# 读取原始图像
img = cv2.imread("image1.jpg")
original_img = img.copy()

# 1. 预处理流程
# 转灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 高斯模糊降噪
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# 自适应二值化:比固定阈值更适合光照不均的发票
thresh = cv2.adaptiveThreshold(
    blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2
)
# 形态学膨胀:用横向核合并同一行的文本块
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 3))
dilated = cv2.dilate(thresh, kernel, iterations=1)

# 2. 提取文本区域轮廓
# 只取最外层轮廓,过滤内部小轮廓
contours, _ = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 3. 过滤噪声并提取文本区域
min_area = 200  # 根据你的发票尺寸调整这个值
for cnt in contours:
    area = cv2.contourArea(cnt)
    if area > min_area:
        x, y, w, h = cv2.boundingRect(cnt)
        # 在原图上绘制文本区域矩形
        cv2.rectangle(original_img, (x, y), (x+w, y+h), (0, 0, 255), 2)
        # 提取单个文本区域并保存
        text_region = img[y:y+h, x:x+w]
        cv2.imwrite(f"text_segment_{x}_{y}.jpg", text_region)

# 查看结果
cv2.imshow("Extracted Text Regions", original_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

代码关键点说明

  • 自适应二值化:自动根据局部区域调整阈值,完美解决发票局部明暗不均的问题
  • 形态学膨胀:横向拉长的卷积核会把同一行的字母“粘”成一个块,这样提取的就是整个文本段,而不是单个字母
  • 轮廓过滤:通过面积排除噪声小轮廓,只保留真正的文本区域
进阶方案:EAST文本检测器

如果你的发票文本布局复杂(比如倾斜、多行混合),可以用OpenCV的EAST文本检测器,它能更精准地检测各种形态的文本块。你需要提前下载预训练模型frozen_east_text_detection.pb,核心代码框架如下:

import cv2
import numpy as np

# 加载EAST模型
net = cv2.dnn.readNet("frozen_east_text_detection.pb")
img = cv2.imread("image1.jpg")
h, w = img.shape[:2]

# 调整图像尺寸为32的倍数(模型要求)
new_w, new_h = (w//32)*32, (h//32)*32
img_resized = cv2.resize(img, (new_w, new_h))

# 构建模型输入
blob = cv2.dnn.blobFromImage(
    img_resized, 1.0, (new_w, new_h), (123.68, 116.78, 103.94), swapRB=True, crop=False
)
net.setInput(blob)

# 获取检测结果:得分和几何信息
scores, geometry = net.forward(["feature_fusion/Conv_7/Sigmoid", "feature_fusion/concat_3"])

# 解析结果并提取文本区域(可参考EAST官方解析代码实现)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 12:27:51