跳到主要内容
Python OCR 技术入门与验证码识别实战 | 极客日志
Python AI 算法
Python OCR 技术入门与验证码识别实战 介绍 Python OCR 技术基础及实战应用。涵盖 Tesseract 引擎安装配置、图像预处理(灰度化、二值化、去噪)、字符分割与倾斜校正。提供基础文字识别、验证码识别(含缓存优化)及批量图片转 Excel 的完整代码示例。同时对比 PaddleOCR 方案,并总结常见错误解决方案,帮助开发者实现图像文字提取功能。
RustyLab 发布于 2026/3/22 更新于 2026/5/31 24 浏览Python OCR 技术入门与验证码识别实战
引言:当机器学会'阅读'
OCR(Optical Character Recognition,光学字符识别)是一种将图像中的文字转换为可编辑文本的技术。简单来说,就是让计算机'看懂'图片里的字。它的核心流程包括以下几个步骤:
图像预处理 :对原始图像进行处理,提高文字的可识别性,包括灰度化、二值化、去噪、倾斜校正等。
版面分析 :识别图像中的文本区域,将文字与背景分离。
字符分割 :将文本行分割成单个字符。
特征提取 :提取每个字符的特征(如笔画、轮廓等)。
字符分类 :将提取的特征与字符库进行匹配,识别出具体字符。
后处理 :利用语言模型或词典对识别结果进行校正。
在实际应用中,OCR 面临诸多挑战:
图像干扰因素 :验证码常包含噪点、扭曲、重叠字符、背景干扰等设计,增加识别难度
字符多样性 :可能包含大小写字母、数字、特殊符号,甚至多种字体混合
图像质量问题 :模糊、光照不均、分辨率低等都会影响识别率
实时性要求 :某些场景(如高频爬虫)需要在毫秒级完成识别
Tesseract 是一个开源的 OCR 引擎,最初由 HP 开发,后来由 Google 维护和赞助。它支持 100 多种语言的识别,是目前最流行、最成熟的 OCR 引擎之一。Tesseract 5.x 版本在 2025 年已支持 100+ 种语言,中文识别准确率达 89.7%。它的优势在于开源免费、多语言支持、可训练以及社区活跃。
一、环境搭建:工欲善其事,必先利其器
1.1 安装 Tesseract OCR 引擎
Windows 系统 :
访问 GitHub 的 Tesseract 发布页面:https://github.com/UB-Mannheim/tesseract/wiki
下载适合你系统的安装包(如 tesseract-ocr-w64-setup-5.3.3.20231005.exe)
安装过程中,勾选需要的语言包(至少勾选'中文简体'和'英文')
安装完成后,将 Tesseract 的安装路径(如 C:\Program Files\Tesseract-OCR)添加到系统环境变量 PATH 中
macOS 系统 :
brew install tesseract
brew install tesseract-lang
Linux 系统(Ubuntu/Debian) :
sudo apt-get update
sudo apt-get install tesseract-ocr
sudo apt-get install tesseract-ocr-chi-sim
sudo apt-get install tesseract-ocr-eng
安装完成后,可以通过命令行验证安装是否成功:
tesseract --version
tesseract --list-langs
1.2 安装 Python 库 pip install pytesseract pillow opencv-python numpy
pytesseract :Tesseract 引擎的 Python 封装,提供 OCR 识别接口
Pillow(PIL) :Python 图像处理库,用于图片的打开、保存和基础处理
opencv-python :OpenCV 的 Python 版本,提供更强大的图像预处理功能
numpy :数值计算库,OpenCV 的图像数据基于 numpy 数组
1.3 验证环境配置 编写一个简单的测试脚本,验证 OCR 环境是否配置成功:
import pytesseract
from PIL import Image
import os
def test_tesseract ():
try :
version = pytesseract.get_tesseract_version()
print (f"Tesseract 版本:{version} " )
print ("环境配置成功!" )
except Exception as e:
print (f"环境配置失败:{e} " )
print ("请检查 Tesseract 是否正确安装并添加到 PATH" )
test_tesseract()
二、基础实战:从图片中提取文字
2.1 最简单的 OCR 识别 我们先从一个最简单的例子开始:识别一张清晰的图片中的文字。
假设有一张图片 sample.png,内容为纯英文文本:
import pytesseract
from PIL import Image
def ocr_basic (image_path ):
""" 基础 OCR 识别 """
image = Image.open (image_path)
text = pytesseract.image_to_string(image, lang='eng' )
print ("识别结果:" )
print (text)
return text
如果图片中包含中文,只需将 lang 参数改为 'chi_sim'(中文简体):
text = pytesseract.image_to_string(image, lang='chi_sim' )
对于中英文混合的图片,可以使用 '+' 组合多个语言包:
text = pytesseract.image_to_string(image, lang='chi_sim+eng' )
2.2 图像预处理:提高识别准确率的关键 在实际应用中,我们遇到的图片往往不是理想状态的——可能有噪点、背景复杂、文字倾斜或光照不均。这时,直接使用 OCR 的准确率会大幅下降。图像预处理是提高 OCR 准确率最关键的一步 。
灰度转换 :将彩色图像转换为灰度图,简化处理
二值化 :将灰度图转换为黑白两色,突出文字轮廓
去噪 :消除图像中的噪点和干扰线条
倾斜校正 :校正拍摄角度导致的文字倾斜
缩放 :调整图像大小,使文字更清晰
下面我们使用 OpenCV 和 Pillow 实现一个完整的图像预处理流程:
import cv2
import numpy as np
from PIL import Image
import pytesseract
def preprocess_image (image_path ):
""" 图像预处理:灰度化、二值化、去噪 """
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5 , 5 ), 0 )
binary = cv2.adaptiveThreshold(
blurred,
255 ,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,
11 ,
2
)
kernel = np.ones((1 , 1 ), np.uint8)
opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
return opening
def ocr_with_preprocess (image_path ):
""" 预处理后的 OCR 识别 """
processed_img = preprocess_image(image_path)
pil_img = Image.fromarray(processed_img)
text = pytesseract.image_to_string(pil_img, lang='eng' )
return text
def compare_ocr (image_path ):
print ("=== 直接识别 ===" )
img_raw = Image.open (image_path)
text_raw = pytesseract.image_to_string(img_raw, lang='eng' )
print (text_raw[:200 ])
print ("\n=== 预处理后识别 ===" )
text_processed = ocr_with_preprocess(image_path)
print (text_processed[:200 ])
预处理技术的选择需要根据具体图像的特点来决定。例如:
对于光照不均 的图像:使用自适应阈值比固定阈值效果更好
对于有噪点 的图像:高斯模糊或中值滤波可以有效去噪
对于倾斜 的图像:需要进行倾斜校正(后面会介绍)
对于低分辨率 的图像:适当放大可以改善识别效果
2.3 倾斜校正 对于拍摄角度不正导致的文字倾斜,需要进行倾斜校正。常用的方法是利用霍夫变换检测直线,计算平均倾斜角度,然后进行旋转校正:
import cv2
import numpy as np
import math
def correct_skew (image ):
""" 校正图像倾斜 """
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(gray, 0 , 255 , cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
edges = cv2.Canny(binary, 50 , 150 , apertureSize=3 )
lines = cv2.HoughLinesP(edges, 1 , np.pi / 180 , 100 , minLineLength=100 , maxLineGap=10 )
if lines is None :
return image
angles = []
for line in lines:
x1, y1, x2, y2 = line[0 ]
angle = math.degrees(math.atan2(y2 - y1, x2 - x1))
angles.append(angle)
median_angle = np.median(angles)
h, w = image.shape[:2 ]
center = (w // 2 , h // 2 )
M = cv2.getRotationMatrix2D(center, median_angle, 1.0 )
rotated = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
return rotated
2.4 OCR 配置优化 pytesseract允许用户自定义 OCR 配置,以提高识别效果。最常用的配置是 --psm(页面分割模式,Page Segmentation Mode),它告诉 Tesseract 如何分析图像中的文本布局。
--psm 6:将图像视为一个统一的文本块
--psm 7:将图像视为单行文本
--psm 8:将图像视为单个单词
--psm 13:原始行处理(不进行额外的文本方向检测)
def ocr_with_config (image_path, psm=6 ):
""" 使用自定义配置进行 OCR 识别 """
image = Image.open (image_path)
custom_config = r'--oem 3 --psm {}' .format (psm)
text = pytesseract.image_to_string(
image,
lang='eng' ,
config=custom_config
)
return text
def test_psm_modes (image_path ):
for psm in [6 , 7 , 8 , 13 ]:
text = ocr_with_config(image_path, psm)
print (f"PSM 模式 {psm} :" )
print (text[:100 ] + "...\n" )
对于验证码识别,通常使用 --psm 8(单个单词)或 --psm 7(单行文本)效果更好。
三、进阶实战:验证码识别 验证码识别是 OCR 技术的一个重要应用场景。虽然现代验证码越来越复杂(如滑动验证码、点选验证码),但在简单场景下(如数字字母组合的静态验证码),OCR 仍然是一种有效的解决方案。
3.1 验证码识别的挑战
噪点和干扰线 :随机分布的噪点或线条,干扰字符分割和识别
字符扭曲 :对字符进行拉伸、旋转、变形
背景干扰 :复杂的背景图案或颜色渐变
字符粘连 :字符之间没有明显间隔
字体变化 :使用特殊字体,增加识别难度
3.2 验证码预处理流程 import cv2
import numpy as np
import pytesseract
from PIL import Image
def preprocess_captcha (image_path ):
""" 验证码图像预处理 """
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
denoised = cv2.medianBlur(gray, 3 )
_, binary = cv2.threshold(denoised, 0 , 255 , cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
kernel = np.ones((2 , 2 ), np.uint8)
opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
return opening
def recognize_captcha (image_path ):
""" 识别验证码 """
processed = preprocess_captcha(image_path)
pil_img = Image.fromarray(processed)
custom_config = r'--psm 8 -c tessedit_char_whitelist=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
text = pytesseract.image_to_string(
pil_img,
lang='eng' ,
config=custom_config
)
text = '' .join(filter (str .isalnum, text))
return text
captcha_text = recognize_captcha('captcha.png' )
print (f"验证码识别结果:{captcha_text} " )
3.3 字符分割 对于字符粘连的验证码,可以先进行字符分割,然后逐个识别,提高准确率:
def segment_and_recognize (image_path ):
""" 字符分割后识别 """
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(gray, 0 , 255 , cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
char_contours = []
for contour in contours:
x, y, w, h = cv2.boundingRect(contour)
if w > 5 and h > 10 and w < 50 and h < 50 :
char_contours.append((x, y, w, h))
char_contours.sort(key=lambda x: x[0 ])
result = ""
for i, (x, y, w, h) in enumerate (char_contours):
char_img = binary[y:y+h, x:x+w]
char_with_border = cv2.copyMakeBorder(
char_img, 5 , 5 , 5 , 5 , cv2.BORDER_CONSTANT, value=0
)
pil_char = Image.fromarray(char_with_border)
custom_config = r'--psm 10 -c tessedit_char_whitelist=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
char_text = pytesseract.image_to_string(pil_char, config=custom_config).strip()
if char_text:
result += char_text
return result
3.4 验证码识别的性能优化 对于需要频繁识别验证码的场景(如爬虫程序),性能优化非常重要:
缓存机制 :对重复出现的验证码建立缓存,避免重复识别
并行处理 :使用线程池同时处理多个验证码
模型选择 :对于特定类型的验证码,可以训练专用模型,提高速度和准确率
from concurrent.futures import ThreadPoolExecutor
import hashlib
import pickle
import os
class CaptchaRecognizer :
""" 带缓存的验证码识别器 """
def __init__ (self, cache_dir='captcha_cache' ):
self .cache_dir = cache_dir
if not os.path.exists(cache_dir):
os.makedirs(cache_dir)
def _get_cache_key (self, image_path ):
"""生成缓存键(基于图片内容的哈希)"""
with open (image_path, 'rb' ) as f:
img_data = f.read()
return hashlib.md5(img_data).hexdigest()
def _recognize (self, image_path ):
"""实际的识别逻辑"""
processed = preprocess_captcha(image_path)
pil_img = Image.fromarray(processed)
custom_config = r'--psm 8 -c tessedit_char_whitelist=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
text = pytesseract.image_to_string(pil_img, config=custom_config)
return text.strip()
def recognize (self, image_path ):
"""带缓存的识别"""
cache_key = self ._get_cache_key(image_path)
cache_file = os.path.join(self .cache_dir, cache_key)
if os.path.exists(cache_file):
with open (cache_file, 'rb' ) as f:
return pickle.load(f)
result = self ._recognize(image_path)
with open (cache_file, 'wb' ) as f:
pickle.dump(result, f)
return result
def batch_recognize (self, image_paths, max_workers=4 ):
"""批量识别(并行处理)"""
with ThreadPoolExecutor(max_workers=max_workers) as executor:
results = list (executor.map (self .recognize, image_paths))
return results
四、实战项目:批量图片文字识别与 Excel 导出 将 OCR 技术与办公自动化结合,可以实现很多实用功能。下面我们实现一个批量图片文字识别工具,将识别结果保存到 Excel 文件中。
4.1 完整实现代码 import os
import pytesseract
from PIL import Image
import pandas as pd
from concurrent.futures import ThreadPoolExecutor
import cv2
import numpy as np
from datetime import datetime
class BatchOCRProcessor :
""" 批量 OCR 识别处理器 """
def __init__ (self, input_dir, output_excel, lang='chi_sim+eng' , use_preprocess=True ):
""" 初始化
:param input_dir: 输入图片目录
:param output_excel: 输出 Excel 文件路径
:param lang: OCR 语言包
:param use_preprocess: 是否使用预处理
"""
self .input_dir = input_dir
self .output_excel = output_excel
self .lang = lang
self .use_preprocess = use_preprocess
self .image_extensions = ('.png' , '.jpg' , '.jpeg' , '.bmp' , '.tiff' )
def preprocess_image (self, image_path ):
""" 图像预处理 """
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
denoised = cv2.medianBlur(gray, 3 )
binary = cv2.adaptiveThreshold(
denoised,
255 ,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,
11 ,
2
)
return Image.fromarray(binary)
def process_single_image (self, filename ):
""" 处理单张图片 """
file_path = os.path.join(self .input_dir, filename)
try :
if self .use_preprocess:
img = self .preprocess_image(file_path)
else :
img = Image.open (file_path)
text = self .ocr_with_multiple_configs(img)
return {
'文件名' : filename,
'识别内容' : text,
'状态' : '成功' ,
'处理时间' : datetime.now().strftime('%Y-%m-%d %H:%M:%S' )
}
except Exception as e:
return {
'文件名' : filename,
'识别内容' : '' ,
'状态' : f'失败:{str (e)} ' ,
'处理时间' : datetime.now().strftime('%Y-%m-%d %H:%M:%S' )
}
def ocr_with_multiple_configs (self, img ):
""" 使用多种配置尝试识别,返回最佳结果 """
psm_modes = [6 , 7 , 8 , 13 ]
results = []
for psm in psm_modes:
config = f'--psm {psm} '
text = pytesseract.image_to_string(img, lang=self .lang, config=config)
valid_chars = sum (c.isalnum() for c in text)
results.append((valid_chars, text))
best_result = max (results, key=lambda x: x[0 ])
return best_result[1 ].strip()
def run (self, max_workers=4 ):
""" 运行批量处理 """
print (f"开始扫描目录:{self.input_dir} " )
image_files = [
f for f in os.listdir(self .input_dir)
if f.lower().endswith(self .image_extensions)
]
print (f"找到 {len (image_files)} 个图片文件" )
if not image_files:
print ("未找到图片文件" )
return
results = []
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = [executor.submit(self .process_single_image, f) for f in image_files]
for i, future in enumerate (futures):
result = future.result()
results.append(result)
print (f"进度:{i+1 } /{len (image_files)} - 已处理 {result['文件名' ]} " )
df = pd.DataFrame(results)
df.to_excel(self .output_excel, index=False , engine='openpyxl' )
print (f"\n处理完成!结果已保存至:{self.output_excel} " )
print (f"成功:{len (df[df['状态' ]=='成功' ])} 个,失败:{len (df[df['状态' ]!='成功' ])} 个" )
return df
if __name__ == "__main__" :
processor = BatchOCRProcessor(
input_dir='./images' ,
output_excel='./ocr_results.xlsx' ,
lang='chi_sim+eng' ,
use_preprocess=True
)
results_df = processor.run(max_workers=4 )
4.2 使用 PaddleOCR 作为备选方案 如果 Tesseract 的识别效果不够理想,可以考虑使用 PaddleOCR。PaddleOCR 是百度开源的 OCR 工具包,在中文识别方面表现优异。
from paddleocr import PaddleOCR
def ocr_with_paddle (image_path ):
""" 使用 PaddleOCR 识别 """
ocr = PaddleOCR(use_angle_cls=True , lang='ch' )
result = ocr.ocr(image_path, cls=True )
text = ''
for line in result:
for word_info in line:
text += word_info[1 ][0 ] + ' '
return text
五、性能优化与常见问题解决方案
5.1 识别准确率提升策略 根据实践经验,提升 OCR 准确率可以从以下几个方面入手:
图像质量优先 :确保输入图像清晰,分辨率适中(建议 300 DPI 以上)
针对性预处理 :根据图像特点选择合适的预处理技术
语言包选择 :确保使用正确的语言包,必要时可以组合多个语言包
PSM 模式调优 :根据文本布局选择合适的页面分割模式
字符白名单 :限制识别字符集,减少误识别
后处理校正 :利用正则表达式、词典或语言模型校正识别结果
def postprocess_text (text, known_words=None ):
""" 后处理:清洗和校正识别结果 """
text = ' ' .join(text.split())
import re
text = re.sub(r'[^\u4e00-\u9fff\u0041-\u005a\u0061-\u007a\u0030-\u0039\s\.,;:!?()]' , '' , text)
if known_words:
words = text.split()
corrected = []
for word in words:
if word not in known_words:
pass
corrected.append(word)
text = ' ' .join(corrected)
return text
5.2 常见问题及解决方案 问题 1:TesseractNotFoundError
解决方案 :确保 Tesseract 已正确安装并添加到系统 PATH,或在代码中手动指定路径:
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
确认已安装中文语言包(tesseract-ocr-chi-sim)
使用 lang='chi_sim' 参数
确保图像预处理正确,特别是二值化处理
考虑使用 PaddleOCR 替代
使用字符白名单限制识别范围
加强图像预处理,去除噪点
使用后处理过滤无效字符
使用并行处理批量图片
适当降低图像分辨率(但需保持清晰)
缓存重复的识别结果
使用 OpenCV 的超分辨率技术
尝试图像锐化增强细节
放大图像(保持长宽比)
def enhance_image (image_path ):
""" 图像增强:锐化 + 超分辨率 """
img = cv2.imread(image_path)
kernel_sharpen = np.array([[-1 , -1 , -1 ], [-1 , 9 , -1 ], [-1 , -1 , -1 ]])
sharpened = cv2.filter2D(img, -1 , kernel_sharpen)
height, width = sharpened.shape[:2 ]
if width < 800 or height < 600 :
scale = max (800 / width, 600 / height)
new_width = int (width * scale)
new_height = int (height * scale)
enlarged = cv2.resize(sharpened, (new_width, new_height), interpolation=cv2.INTER_CUBIC)
return enlarged
return sharpened
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
随机西班牙地址生成器 随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online