简介这份资源面向需要快速实现文字、条形码与二维码识别的开发者尤其适合制造业物料标签管理、快递包裹条码扫描等场景。它提供了一套可直接运行的识别方案能自动读取不同供应商标签上的中英文文字替代人工识别降低耗时与出错风险同时兼顾条码与二维码的快速解析。压缩包共16个文件约15MB包含4个Python脚本、3个pdiparams与3个pdmodel模型文件、3个info配置、1个xml、1个txt及1张png效果图覆盖检测、分类、识别模型与推理代码结构清晰便于二次开发与集成。目前已有173人学习下载。读者可借助其中的模型与脚本快速搭建OCR与条码识别流程理解检测、分类、识别三阶段协作方式并参考识别效果图验证结果适合具备一定Python基础、希望将识别能力落地到实际业务中的开发者。1. 从一张糊了的发票说起这个项目到底在解决什么上周帮朋友处理一批报销单据手机拍出来的发票照片歪歪扭扭条形码还反光。手动录入 200 多张眼睛都快看瞎了。当时我就想要是有个能同时搞定 OCR 文字识别、条形码和二维码识别的工具直接批量跑一遍能省下多少重复劳动。后来翻到这个项目核心就是干这件事的——把图片里的中文、英文、条码、二维码一次性提取成结构化文本。它适合两类人一类是手头有大量票据、证件、商品图需要批量转文字的开发者另一类是正在做仓储、零售、物流类应用需要把扫码和文字录入整合进同一个流程的团队。技术栈上它走的是 Python 生态底层依赖 OpenCV 做图像预处理OCR 部分常见做法是接 PaddleOCR 或 Tesseract条码识别用 ZBar 或 pyzbar二维码用 OpenCV 自带的 QRCodeDetector。整个项目不复杂但把几个识别能力串成了一条流水线这才是它真正省事的地方。2. 技术选型与目录结构为什么是 OpenCV PaddleOCR pyzbar 这套组合2.1 三个识别任务的技术拆解文字识别、条形码识别、二维码识别表面看都是“从图里读东西”但底层逻辑差别不小。OCR 要处理的是像素级的字符分割和分类中文还得考虑几千个字符集的映射条形码是一维信号靠黑白条纹的宽度比来解码二维码是二维矩阵有定位图案和纠错码。如果分别用三套独立方案代码里会充斥大量重复的图像读取、灰度化、二值化逻辑。这个项目的做法是统一用 OpenCV 做前置处理然后按任务类型分发给不同的识别引擎。常见做法是 OCR 用 PaddleOCR因为它对中文场景的准确率明显高于 Tesseract而且自带方向分类器能处理旋转文本。条形码和二维码用 pyzbar它封装了 ZBar 库支持 EAN-13、Code128、QR Code 等主流格式调用简单。也有开发者会用 OpenCV 的QRCodeDetector替代 pyzbar 做二维码识别好处是不用额外装 ZBar但识别率在低对比度图片上会差一些。2.2 目录结构长什么样一个典型的项目目录会这样组织project/ ├── main.py # 入口命令行参数解析 ├── config.py # 路径、模型、阈值等配置 ├── core/ │ ├── preprocess.py # 图像预处理灰度、去噪、二值化 │ ├── ocr_engine.py # OCR 封装中英文识别 │ ├── barcode_engine.py # 条形码识别 │ └── qrcode_engine.py # 二维码识别 ├── utils/ │ ├── image_utils.py # 裁剪、旋转、透视校正 │ └── file_utils.py # 批量读取、结果导出 ├── models/ # OCR 模型文件PaddleOCR 下载后放这里 ├── input/ # 待识别图片目录 └── output/ # 识别结果输出目录这个结构的好处是每个识别引擎独立成模块方便替换。比如你觉得 PaddleOCR 太重想换成 Tesseract只需要改ocr_engine.py其他模块不用动。preprocess.py单独抽出来也很关键因为条形码和二维码对图像质量的要求跟 OCR 不一样——OCR 需要保留文字细节条码识别反而需要强化黑白对比。2.3 依赖安装与版本注意安装依赖时PaddleOCR 和 pyzbar 的版本兼容性是个容易翻车的地方。PaddleOCR 依赖 PaddlePaddle而 PaddlePaddle 对 Python 版本和 CUDA 版本有要求。如果你用 CPU 推理安装命令大致是pip install paddlepaddle2.5.2 pip install paddleocr2.7.0.3 pip install opencv-python4.8.1.78 pip install pyzbar0.1.9 pip install pillow10.1.0注意pyzbar 在 Windows 上需要额外安装 Visual C Redistributable否则会报ImportError: Unable to find zbar shared library。Linux 上一般用apt install libzbar0就能解决。PaddleOCR 首次运行会自动下载模型文件到~/.paddleocr/目录如果网络环境不稳定可以手动下载后放到models/下然后在代码里指定det_model_dir和rec_model_dir。这一步不做的话每次换机器都要重新下载批量部署时很浪费时间。3. 核心模块拆解从一张图到结构化文本的完整链路3.1 图像预处理别急着识别先让图能看很多识别失败的案例根源不在模型而在输入图片质量太差。这个项目的preprocess.py做了几件事转灰度、高斯模糊去噪、自适应二值化、边缘检测。对于条形码还会额外做形态学闭运算把断开的条纹连起来。import cv2 import numpy as np def preprocess_for_ocr(image_path): OCR 预处理保留文字细节增强对比度 img cv2.imread(image_path) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 限制对比度自适应直方图均衡化比全局均衡化更温和 clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)) enhanced clahe.apply(gray) # 轻度高斯模糊去掉噪点但保留笔画 blurred cv2.GaussianBlur(enhanced, (3, 3), 0) return blurred def preprocess_for_barcode(image_path): 条码预处理强化黑白对比闭运算连接断裂条纹 img cv2.imread(image_path) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 自适应阈值应对光照不均 binary cv2.adaptiveThreshold( gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2 ) # 闭运算先膨胀后腐蚀填补条纹间的空隙 kernel np.ones((1, 3), np.uint8) closed cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel) return closedclipLimit控制对比度增强的幅度设太大反而会放大噪点2.0 是个比较稳的值。tileGridSize决定局部均衡化的网格大小8x8 适合大多数文档图片。条码预处理里的kernel形状很关键——用(1, 3)横向核是因为条形码的条纹是垂直的横向闭运算能把断开的条纹连起来同时不会把相邻条纹糊在一起。3.2 OCR 引擎封装中英文混排怎么处理PaddleOCR 默认支持中英文混合识别但需要显式设置langch。如果图片里英文占多数可以设成langen提升速度但中文就会识别不出来。这个项目的做法是统一用ch模型然后在后处理阶段过滤掉置信度低于阈值的文本行。from paddleocr import PaddleOCR class OCREngine: def __init__(self, use_gpuFalse): # use_angle_clsTrue 开启方向分类处理旋转文本 self.ocr PaddleOCR( use_angle_clsTrue, langch, use_gpuuse_gpu, det_db_thresh0.3, # 检测阈值降低可召回更多文本 rec_char_dict_pathNone # 用默认字典 ) def recognize(self, image_path, min_confidence0.6): result self.ocr.ocr(image_path, clsTrue) texts [] for line in result[0]: box, (text, confidence) line if confidence min_confidence: texts.append({ text: text, confidence: round(confidence, 4), box: box # 四点坐标可用于后续裁剪 }) return textsdet_db_thresh是文本检测的阈值默认 0.3调低会召回更多候选框但误检也会增加。min_confidence是识别置信度过滤0.6 是个经验值——低于这个值的文本通常是模糊或残缺的强行保留反而干扰后续处理。返回的box是四个点的坐标如果要做版面分析比如判断哪段文字在表格里这个信息就很有用。3.3 条形码与二维码识别pyzbar 的调用与容错pyzbar 的接口很简单但实际用起来有几个坑。它返回的data是 bytes 类型需要 decode 成字符串如果图片里同时有多个条码它会全部返回需要自己判断取哪个。from pyzbar import pyzbar import cv2 def decode_barcodes(image_path): img cv2.imread(image_path) # pyzbar 可以直接处理灰度图先转灰度减少计算量 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) barcodes pyzbar.decode(gray) results [] for barcode in barcodes: # data 是 bytes用 utf-8 解码失败则用 latin-1 兜底 try: data barcode.data.decode(utf-8) except UnicodeDecodeError: data barcode.data.decode(latin-1) results.append({ type: barcode.type, # QRCODE 或 EAN13 等 data: data, rect: barcode.rect, # 边界框 polygon: barcode.polygon # 多边形顶点 }) return resultsbarcode.type会返回具体格式比如QRCODE、EAN13、CODE128。如果业务上只关心二维码可以在循环里加个判断if barcode.type QRCODE。rect和polygon的区别在于rect是正矩形polygon是实际检测到的四边形对于倾斜的条码polygon更准确。提示pyzbar 对低分辨率图片的识别率会骤降。如果原图小于 300x300 像素建议先用cv2.resize放大 2 倍再识别比直接调参有效得多。4. 避坑与排查识别率上不去时先查这五件事4.1 现象OCR 返回空列表但图片肉眼看着很清楚原因通常是图片通道数不对。PaddleOCR 内部期望的是 BGR 三通道图如果你传进去的是灰度图或 RGBA 图检测阶段就会直接跳过。解决方法是统一在入口处用cv2.imread读图它会自动转成 BGR 三通道。如果图片本身是 PNG 带透明通道加一行img cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)。4.2 现象条形码识别结果乱码或者 decode 报错这是编码问题。有些老系统的条码数据不是 UTF-8而是 GBK 或 Latin-1。pyzbar 返回的是原始 bytes直接.decode(utf-8)遇到非 UTF-8 字节就会抛异常。稳妥的做法是写一个多编码尝试函数按utf-8、gbk、latin-1的顺序试哪个成功用哪个。另外如果条码本身是二进制数据比如某些工业条码就不应该 decode直接保留 bytes 做后续处理。4.3 现象二维码能识别但位置框偏移严重这通常发生在透视畸变较大的图片上。pyzbar 返回的polygon是实际检测到的四边形顶点而rect是外接正矩形。如果你用rect去画框在倾斜角度大时就会偏。解决方法是优先用polygon绘制或者先用 OpenCV 做透视校正把二维码区域拉正再识别。4.4 现象批量处理时内存持续上涨最后 OOMPaddleOCR 的模型加载后会常驻内存如果每处理一张图都重新实例化PaddleOCR内存会爆。正确做法是在类初始化时创建一次实例后续所有图片复用同一个self.ocr对象。另外ocr.ocr()返回的结果里包含大量中间张量如果不需要可视化及时用del释放或者把批量大小控制在 10 张以内。4.5 现象中文识别结果里夹杂大量英文误判这是langch模型的通病——它会把一些形似字母的汉字部件识别成英文。比如“口”被识别成“O”“日”被识别成“B”。缓解方法是在后处理阶段加一层规则过滤如果某个文本行里中文字符占比低于 30%且置信度低于 0.8就丢弃。或者针对特定场景用rec_char_dict_path指定自定义字典把容易混淆的字符排除掉。5. 二次开发与改造从能跑到好用我踩过的三个坑5.1 把识别结果落成结构化 JSON项目默认输出可能是纯文本但实际业务里往往需要带位置信息的 JSON。改造思路是在main.py里加一个--output-format参数支持txt和json两种。JSON 结构可以设计成{ image: invoice_001.jpg, ocr: [ {text: 发票代码, confidence: 0.98, box: [[10,20],[100,20],[100,40],[10,40]]} ], barcodes: [ {type: QRCODE, data: https://example.com, polygon: [[200,300],[250,300],[250,350],[200,350]]} ] }这样下游系统可以直接按坐标做版面还原或者把条码数据和 OCR 文本做关联。我一般会在file_utils.py里加一个export_json函数用json.dump时注意ensure_asciiFalse否则中文会变成 Unicode 转义。5.2 加一层图像质量预检不是所有图片都值得跑识别。如果一张图模糊到连人眼都看不清直接跳过比硬跑更省时间。我加了一个简单的拉普拉斯方差检测def is_blurry(image_path, threshold100): img cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) variance cv2.Laplacian(img, cv2.CV_64F).var() return variance thresholdthreshold设 100 是个经验值低于这个值基本可以判定为模糊。这个预检放在批量处理入口能过滤掉 10% 到 20% 的无效图片整体吞吐量提升明显。5.3 用多进程加速批量识别PaddleOCR 在 CPU 上是单线程推理批量处理时 CPU 利用率上不去。改造方法是用multiprocessing.Pool把图片列表分片每个进程独立加载一个 OCR 实例。注意进程数不要超过 CPU 核心数否则上下文切换反而拖慢速度。我一般设processes4配合chunksize2在 8 核机器上能把处理速度提升 3 倍左右。注意多进程下每个进程都会加载一份模型内存占用会翻倍。如果机器内存紧张还是老老实实单进程跑或者改用 PaddleOCR 的predict_system批量接口。从那以后我每次做批量识别都强制先跑一遍模糊检测和尺寸检查再进识别流程。这个习惯帮我省下了大量无效计算时间。希望帮到你。本文还有配套的精品资源点击获取