自研工具分享:多媒体文件分配2.0 PaddleOCR成功打包exe
书接上回https://blog.csdn.net/weixin_44548582/article/details/145139908
1.0版本虽然逻辑完成,但交互还是很粗糙的,一些数据校验、限制没做全,这次优化到位,小白放心使用。
并且考虑到分完文件夹后还要给文件夹起名字的问题,实现自动把名字打到每个文件夹上,因为拍产品,每家企业内都是对产品有名字信息或编号的(像下图中一样),自己打很麻烦,所以整合了图像文字识别技术。
成果分享
3个产品,33张图片,相当于3个产品以①、②、③的顺序,循环拍了10个角度+1个铭牌
技术分享
项目git地址https://gitee.com/tenkkk/media_classifier
在整合 PaddleOCR 进行图像文字识别的过程中,我遇到了一些问题。以下是我总结的主要问题及其解决方案,希望对其他开发者有所帮助。仅展示代码片段,完整内容git见。
1. 控制台输出问题
问题描述
在使用 pyInstaller 打包时,使用 --noconsole 或 -w 参数隐藏控制台窗口,导致 OCR 向控制台输出信息被堵死,出现错误 'NoneType' object has no attribute 'write'。
解决方案
- 重定向标准输出和标准错误:通过将 sys.stdout 和 sys.stderr 重定向到文件或 os.devnull,避免库尝试向控制台输出信息。
#主程序
import sys
import os
# 重定向标准输出和标准错误,指向虚无,
# 不然OCR初始化的过程中一定向控制台输出,打包用了noconsole,会无法输出控制台而报错
sys.stdout = open(os.devnull, 'w')
sys.stderr = open(os.devnull, 'w')
2. 模型文件未正确打包
问题描述
在pyinstaller打包时使用--onefile参数, exe 文件中模型文件未被正确包含,导致程序在运行时需要重新下载模型文件。尝试在build.py中使用一下方法,希望模型能被打包进exe
build.py
# 获取模型路径
model_dir = "./model"
# 检查模型目录是否存在
if not os.path.exists(model_dir):
# raise FileNotFoundError(f"模型目录不存在: {model_dir}")
params = [
……
'--add-data={};model'.format(model_dir), # 包含模型文件
……
]
从前后的exe体积来判断,模型确实有被打包进去,但在主程序的代码中,各种方式始终无法让程序从自己身上找到模型,这样的exe每次打开都会把模型下载到C:\Users\<用户名>\AppData\Local\Temp\_MEI166442\model\det\ch_PP-OCRv4_det_infer.tar的位置,关闭程序后清除,类似缓存。
后暂放弃在打包时把模型打包的想法,从主程序入手,OCR初始化时,发现没有模型,会自己下载,默认位置C:\Users\<用户名>\.paddleocr\whl,不希望这样的可以把主程序中初始化OCR里指定模型位置的代码去掉即可,我为了突出这个问题,在初始化OCR时指定模型为同级目录下的model,没有也会自动下载在这个位置。
3. 依赖项问题
问题描述
在运行 PaddleOCR 时,会遇到缺少依赖项的问题,例如 ppocr_keys_v1.txt 和 mklml.dll。
解决方案
- 确保 ppocr_keys_v1.txt 文件存在:该文件通常用于字符集的加载,确保在打包时将其包含在内。
- 确保 mklml.dll 文件存在:该文件是 PaddleOCR 运行所需的动态链接库,确保在打包时将其包含在内。
- 确保tools目录存在
#build.py
# 获取各个包的路径
site_packages = os.path.dirname(paddleocr.__file__) # 使用 paddleocr 模块的路径
ppocr_keys_path = os.path.join(site_packages, 'ppocr', 'utils', 'ppocr_keys_v1.txt')
tools_path = os.path.join(site_packages, 'tools') # 确保正确引用 tools 目录
mklml_path = os.path.join(os.path.dirname(paddle.__file__), 'libs', 'mklml.dll') # 确保正确引用 mklml.dll
# 创建临时目录以复制所需文件
temp_dir = os.path.join(current_dir, 'temp_build')
if os.path.exists(temp_dir):
shutil.rmtree(temp_dir)
os.makedirs(temp_dir)
# 复制 ppocr_keys_v1.txt 文件
if os.path.exists(ppocr_keys_path):
shutil.copy2(ppocr_keys_path, os.path.join(temp_dir, 'ppocr_keys_v1.txt'))
print(f"已复制 ppocr_keys_v1.txt 到临时目录")
else:
print("错误: 无法找到 ppocr_keys_v1.txt 文件")
# 定义打包参数
params = [
……
'--add-data={};ppocr'.format(os.path.join(site_packages, 'ppocr')), # 包含 ppocr 目录
'--add-data={};tools'.format(tools_path), # 包含 tools 目录
'--add-data={};ppocr/utils'.format(os.path.join(temp_dir, 'ppocr_keys_v1.txt')), # 包含字符集文件
'--add-binary={};.'.format(mklml_path), # 包含 mklml.dll
]