OCR 常用图像预处理方法
在 OCR 项目中,很多人一开始会把重点放在模型选择上,比如 PaddleOCR、Tesseract、EasyOCR、RapidOCR 等。但实际开发中经常会发现:同一个 OCR 模型,在不同图片上的识别效果差异非常大。
原因往往不是模型不行,而是图片质量没有处理好。
OCR 的本质是让模型从图片中识别文字,所以图片越"干净"、文字越"清晰"、背景干扰越少,识别准确率就越高。本文就来系统讲解 OCR 中常用的图片处理方法。
一、为什么 OCR 前要处理图片?
OCR 模型虽然有一定的鲁棒性,但它并不是万能的。下面这些情况都会明显影响识别效果:
- 图片太暗或太亮
- 文字和背景颜色接近
- 图片模糊
- 文字太小
- 截图中有大量无关区域
- 背景纹理复杂
- 图片倾斜
- 文字被边框、图标、阴影干扰
- 压缩严重,出现噪点
所以 OCR 前通常会先做一轮图像预处理,让图片更适合识别。
一个常见流程是:
text
原图
↓
裁剪目标区域
↓
缩放放大
↓
灰度化
↓
增强对比度
↓
二值化
↓
降噪
↓
OCR识别
↓
结果纠错
并不是所有场景都要完整执行这些步骤,而是根据图片情况选择合适的方法。
二、区域裁剪:先把无关内容去掉
OCR 最重要的一步往往不是增强图片,而是裁剪识别区域。
如果整张截图里只有一小块文字需要识别,却直接把全图送进 OCR,模型会受到很多干扰。
例如游戏截图、App 页面、表格截图中,文字通常只出现在固定位置。这个时候可以先根据坐标裁剪:
python
import cv2
image = cv2.imread("screen.png")
# 裁剪区域:y1:y2, x1:x2
crop = image[100:300, 50:500]
cv2.imwrite("crop.png", crop)
在 OCR 项目中,推荐优先做区域裁剪。
因为裁剪可以:
- 减少干扰内容
- 提高识别速度
- 提高识别准确率
- 方便后续单独调参
例如识别"落款名""金额""地址信息""日期"时,最好不要整图识别,而是分别裁剪每个字段对应的区域。
三、图片缩放:小字识别前先放大
很多 OCR 识别失败,是因为文字太小。
尤其是手机截图、游戏界面、网页缩略图,文字区域可能只有十几像素高。这个时候可以先放大图片。
python
import cv2
image = cv2.imread("crop.png")
# 放大 2 倍
resized = cv2.resize(image, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
cv2.imwrite("resized.png", resized)
常用插值方式:
python
cv2.INTER_LINEAR # 普通缩放
cv2.INTER_CUBIC # 放大效果较好
cv2.INTER_AREA # 缩小时常用
一般建议:
text
文字较小:放大 2~4 倍
文字正常:不放大或放大 1.5~2 倍
图片已经很大:不要盲目放大
放大不是越大越好。放大过度会让边缘变虚,反而影响 OCR。
四、灰度化:减少颜色干扰
OCR 识别文字时,很多时候并不需要颜色信息。把彩色图转成灰度图,可以减少干扰,也方便后续二值化、降噪、阈值处理。
python
import cv2
image = cv2.imread("crop.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imwrite("gray.png", gray)
灰度化适合这些场景:
- 黑字白底
- 白字黑底
- 文档扫描件
- 表格截图
- 简单背景文字
如果文字颜色本身很关键,比如游戏里的金色、红色、紫色品质文字,有时候保留彩色再做颜色提取会更好。
五、对比度增强:让文字和背景拉开差距
如果文字和背景颜色太接近,OCR 很容易识别错。这个时候可以增强对比度。
1. 普通对比度增强
python
import cv2
image = cv2.imread("gray.png", 0)
# alpha 控制对比度,beta 控制亮度
enhanced = cv2.convertScaleAbs(image, alpha=1.5, beta=0)
cv2.imwrite("enhanced.png", enhanced)
参数说明:
text
alpha > 1:增强对比度
beta > 0:提高亮度
beta < 0:降低亮度
例如:
python
enhanced = cv2.convertScaleAbs(image, alpha=1.8, beta=10)
适合偏暗、文字不清晰的图片。
2. CLAHE 局部对比度增强
如果图片局部亮度不均,比如一边亮一边暗,可以使用 CLAHE。
python
import cv2
gray = cv2.imread("gray.png", 0)
clahe = cv2.createCLAHE(
clipLimit=2.0,
tileGridSize=(8, 8)
)
result = clahe.apply(gray)
cv2.imwrite("clahe.png", result)
CLAHE 比普通对比度增强更适合:
- 扫描件
- 拍照文档
- 光照不均的图片
- 背景有阴影的图片
六、二值化:把文字和背景分开
二值化就是把图片变成黑白两种颜色,让文字和背景更分明。
1. 固定阈值二值化
python
import cv2
gray = cv2.imread("gray.png", 0)
_, binary = cv2.threshold(
gray,
127,
255,
cv2.THRESH_BINARY
)
cv2.imwrite("binary.png", binary)
意思是:
text
像素值 > 127 的变成白色
像素值 <= 127 的变成黑色
适合光照均匀、背景简单的图片。
2. 反向二值化
如果是白字黑底,可以用反向二值化:
python
_, binary_inv = cv2.threshold(
gray,
127,
255,
cv2.THRESH_BINARY_INV
)
常见场景:
text
黑字白底:THRESH_BINARY
白字黑底:THRESH_BINARY_INV
3. Otsu 自动阈值
固定阈值不一定适合所有图片,Otsu 可以自动寻找一个较合适的阈值。
python
_, otsu = cv2.threshold(
gray,
0,
255,
cv2.THRESH_BINARY + cv2.THRESH_OTSU
)
cv2.imwrite("otsu.png", otsu)
适合:
- 背景较简单
- 文字和背景有明显灰度差
- 不想手动调阈值
4. 自适应阈值
如果图片光照不均,固定阈值和 Otsu 可能效果不好。可以使用自适应阈值。
python
adaptive = cv2.adaptiveThreshold(
gray,
255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,
31,
10
)
cv2.imwrite("adaptive.png", adaptive)
参数说明:
text
31:局部区域大小,必须是奇数
10:常数偏移量
适合:
- 拍照图片
- 阴影明显
- 背景亮度不均
- 纸张泛黄
- 局部过曝或过暗
七、降噪:去掉背景杂点
图片中如果有很多噪点,会影响 OCR 判断文字边缘。
1. 中值滤波
中值滤波常用于去除椒盐噪声。
python
denoise = cv2.medianBlur(gray, 3)
cv2.imwrite("denoise.png", denoise)
适合:
- 图片有小黑点
- 扫描件有杂点
- 背景不干净
2. 高斯模糊
高斯模糊可以平滑图像,但要谨慎使用,因为它可能让文字边缘变虚。
python
blur = cv2.GaussianBlur(gray, (3, 3), 0)
cv2.imwrite("blur.png", blur)
适合轻微噪声,不适合文字本来就很细、很小的图片。
3. 非局部均值降噪
python
denoise = cv2.fastNlMeansDenoising(
gray,
None,
h=10,
templateWindowSize=7,
searchWindowSize=21
)
cv2.imwrite("nlmeans.png", denoise)
这种方式效果较好,但速度相对慢一些。
八、锐化:让文字边缘更清楚
如果图片有点模糊,可以适当锐化。
python
import cv2
import numpy as np
image = cv2.imread("gray.png", 0)
kernel = np.array([
[0, -1, 0],
[-1, 5, -1],
[0, -1, 0]
])
sharp = cv2.filter2D(image, -1, kernel)
cv2.imwrite("sharp.png", sharp)
锐化适合:
- 文字边缘发虚
- 截图压缩后不清晰
- 轻微模糊
但锐化不能过度,否则会产生明显噪点,让 OCR 更难识别。
九、形态学处理:修复断裂文字或去除小干扰
形态学操作主要包括腐蚀、膨胀、开运算、闭运算。
1. 膨胀:让文字变粗
python
kernel = np.ones((2, 2), np.uint8)
dilate = cv2.dilate(binary, kernel, iterations=1)
cv2.imwrite("dilate.png", dilate)
适合文字太细、断裂的情况。
2. 腐蚀:让文字变细,去掉小噪点
python
erode = cv2.erode(binary, kernel, iterations=1)
cv2.imwrite("erode.png", erode)
适合文字过粗、粘连的情况。
3. 开运算:先腐蚀再膨胀,去小噪点
python
opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
cv2.imwrite("opening.png", opening)
适合去除独立小噪点。
4. 闭运算:先膨胀再腐蚀,连接断裂文字
python
closing = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
cv2.imwrite("closing.png", closing)
适合文字笔画断裂、边缘不连续的情况。
十、倾斜校正:让文字保持水平
如果图片是拍照得到的,文字可能会倾斜。倾斜会影响 OCR 的检测和识别。
常见做法是:
- 找到文字区域轮廓
- 计算倾斜角度
- 旋转图片校正
简单示例:
python
import cv2
import numpy as np
image = cv2.imread("text.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(
gray,
0,
255,
cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU
)
coords = np.column_stack(np.where(binary > 0))
angle = cv2.minAreaRect(coords)[-1]
if angle < -45:
angle = -(90 + angle)
else:
angle = -angle
h, w = image.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(
image,
M,
(w, h),
flags=cv2.INTER_CUBIC,
borderMode=cv2.BORDER_REPLICATE
)
cv2.imwrite("rotated.png", rotated)
倾斜校正常用于:
- 发票
- 合同
- 票据
- 拍照文档
- 扫描件
十一、颜色过滤:提取指定颜色文字
在游戏、App、海报类图片中,文字可能不是黑白的,而是彩色文字。
例如:
- 金色文字
- 红色文字
- 蓝色文字
- 白色描边文字
- 紫色品质文字
这种时候直接灰度化可能丢失关键信息,可以用 HSV 颜色空间提取目标颜色。
python
import cv2
import numpy as np
image = cv2.imread("screen.png")
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 示例:提取黄色/金色区域
lower = np.array([15, 80, 80])
upper = np.array([40, 255, 255])
mask = cv2.inRange(hsv, lower, upper)
result = cv2.bitwise_and(image, image, mask=mask)
cv2.imwrite("color_text.png", result)
颜色过滤适合:
- 游戏资源识别
- 等级、品质、数量识别
- 固定颜色标签识别
- UI 截图 OCR
但要注意,不同设备、压缩、亮度会导致颜色范围变化,所以 HSV 阈值需要调试。
十二、去边框和去图标干扰
有些 OCR 区域里会包含边框、图标、按钮、装饰线,这些都会影响识别。
常见处理方式:
1. 更精准裁剪
这是最推荐的方式。能裁掉干扰,就不要交给后处理。
python
crop = image[y1:y2, x1:x2]
2. 根据颜色去除背景
如果边框颜色固定,可以通过颜色过滤去掉。
3. 根据形态学去除线条
比如表格线、横线、竖线可以用形态学检测后去除。
python
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40, 1))
remove_horizontal = cv2.morphologyEx(binary, cv2.MORPH_OPEN, horizontal_kernel)
4. 使用掩码
如果某些干扰位置固定,可以直接把那块区域涂白或涂黑。
python
image[y1:y2, x1:x2] = 255
这个方法在固定 UI 截图中特别实用。
十三、一个通用 OCR 预处理函数示例
下面是一个比较通用的处理函数,适合截图类 OCR:
python
import cv2
import numpy as np
def preprocess_for_ocr(image_path: str, output_path: str = "processed.png"):
image = cv2.imread(image_path)
if image is None:
raise ValueError(f"图片读取失败: {image_path}")
# 1. 放大
image = cv2.resize(
image,
None,
fx=2,
fy=2,
interpolation=cv2.INTER_CUBIC
)
# 2. 灰度化
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 3. 对比度增强
enhanced = cv2.convertScaleAbs(gray, alpha=1.5, beta=5)
# 4. 轻微降噪
denoise = cv2.medianBlur(enhanced, 3)
# 5. Otsu 二值化
_, binary = cv2.threshold(
denoise,
0,
255,
cv2.THRESH_BINARY + cv2.THRESH_OTSU
)
cv2.imwrite(output_path, binary)
return binary
调用方式:
python
processed = preprocess_for_ocr("input.png", "processed.png")
十四、总结
OCR 图片处理的核心目标只有一个:让文字更突出,让干扰更少。
常用方法可以总结为:
text
裁剪:减少无关区域
缩放:解决小字问题
灰度化:减少颜色干扰
对比度增强:拉开文字和背景差距
二值化:突出文字轮廓
降噪:去除背景杂点
锐化:增强文字边缘
形态学:修复断裂或去除干扰
倾斜校正:处理拍照文档
颜色过滤:处理彩色文字
后处理:修正 OCR 结果
OCR 的准确率提升,通常不是靠单一方法,而是靠一整套稳定的图像处理流程。只要把图片处理好,即使使用普通 OCR 模型,也能得到不错的识别效果。