本文深入解析了Umi-OCR这一基于深度学习的离线OCR开源工具,重点突出其无需联网、支持API调用、兼容多平台的核心优势。工具内置Paddle/Rapid双引擎,提供截图OCR、批量文档处理、二维码生成解析等实用功能,并通过详细的Python代码示例演示了PDF整本转TXT的自动化流程。文章涵盖从软件下载安装、命令行操作到HTTP接口调用的完整教程,并针对常见硬件兼容性问题(如奔腾/赛扬CPU支持)、系统报错(OpenGL配置、DLL缺失等)提供专业解决方案,为开发者提供开箱即用的高效OCR技术方案。
特别注意:Paddle版性能好,但不兼容奔腾、赛扬、凌动CPU。Rapid兼容绝大部分硬件。下面我以Paddle版为例,进行一个简单的使用效果测试。
下载安装包
蓝奏云:https://hiroi-sora.lanzoul.com/s/umi-ocr
GitHub:https://github.com/hiroi-sora/Umi-OCR/releases/latest

解压软件
双击exe之后就会让你选择一个解压目录,可以新建一个文件夹来存储解压后的。

解压之后如图:

主要功能
截图OCR:

批量OCR:

批量文档:

二维码:

命令行API调用
如图,必须允许HTTP服务才能使用命令行(默认开启)。主机选择 仅本地 就行了。

一些基本操作:
弹出主窗口:umi-ocr --show
隐藏主窗口:umi-ocr --hide
关闭软件:umi-ocr --quit
鼠标截屏
umi-ocr --screenshot
范围截屏
umi-ocr --screenshot screen=0 rect=x,y,w,h
范围截屏控制参数:
screen: 要截图的显示器编号(多个显示器时有效),从0开始。缺省为0。rect: 截图范围矩形框,x坐标,y坐标,w宽度,h高度。缺省为全屏。
注意:
- 这两个参数的前面无需加
--。 - 这两个参数至少要填一个,才能触发范围截图。没有任一参数时,执行鼠标截屏。
示例1:截取第1个显示器的全屏
umi-ocr --screenshot screen=0示例2:截取第2个显示器,从左上角 (50,100) 开始,大小为 300x200 的矩形区域
umi-ocr --screenshot screen=1 rect=50,100,300,200粘贴图片
umi-ocr --clipboard
指定路径
指定路径:umi-ocr --path "D:/xxx.png"
- 可传入文件夹的路径。将搜索文件夹中所有图片(包括嵌套子文件夹),并输出所有识别结果。
- 可传入多个路径。请用双引号
""包裹单个路径,不同路径间用空格隔开。
指定多个路径 示例:umi-ocr --path "D:/img1.png" "D:/img2.png" "D:/image/test"
提示:
- 多图识别时,耗时较长;一次命令结束前不要输入下一个命令。
- 对于截屏、粘贴、路径指令,OCR参数(如识别语言,是否复制到剪贴板、是否弹出主窗口)采用
截图OCR标签页的设定。如果不希望命令行任务弹出主窗口,请在截图OCR标签页中关闭该选项。
二维码指令
识别二维码:umi-ocr --qrcode_read "D:/xxx.png"
- 与OCR指令一致,二维码识别的指令也支持传入多个图片&文件夹路径。
生成二维码:umi-ocr --qrcode_create "文本内容" "D:/输出图片.jpeg"
- 默认的图片宽高为最小适配长度。也可以在指令后方加上数字,手动指定图片宽高:
例,同时指定宽高为128像素:umi-ocr --qrcode_create "文本内容" "D:/输出图片.jpeg" 128
例,宽128,高256像素:umi-ocr --qrcode_create "文本内容" "D:/输出图片.jpeg" 128 256
命令行结果输出
- 复制到剪贴板
--clip - 输出到文件(覆盖)
--output "file.txt" - 输出到文件(追加)
--output_append "file.txt"
也可以使用箭头符号:
"-->"等价于--output"-->>"等价于--output_append
例:
umi-ocr --screenshot --clip
umi-ocr --screenshot --output test.txt
umi-ocr --screenshot "-->" test.txtHTTP接口手册
具体有点太多了,可以自行查看官方文档。
Python将整本pdf转为txt的示例
这里我写一个Python的代码,用来把pdf提取成txt。这是基于HTTP做的。
import os
import json
import time
import requests
class UmiOCRProcessor:
"""Umi-OCR HTTP接口处理器"""
def __init__(self, base_url="http://127.0.0.1:1224", download_dir="./download"):
"""
初始化OCR处理器
:param base_url: API基础地址
:param download_dir: 文件下载保存目录
"""
self.base_url = base_url
self.download_dir = download_dir
self.headers = {"Content-Type": "application/json"}
self.task_id = None # 当前任务ID
def upload_file(self, file_path, options=None):
"""
上传文件并启动OCR任务
:param file_path: 待识别文件路径
:param options: 任务参数(字典格式)
:return: 任务ID
"""
print("=======================================")
print("===== 1. 上传文件,获取任务ID =====")
url = f"{self.base_url}/api/doc/upload"
print("== 请求地址:", url)
# 默认参数设置
if options is None:
options = {"doc.extractionMode": "mixed"}
options_json = json.dumps(options)
# 第一次尝试上传
with open(file_path, "rb") as file:
response = requests.post(url, files={"file": file}, data={"json": options_json})
# 处理上传失败的情况(非ASCII文件名问题)
res_data = self._check_response(response)
if res_data["code"] == 101:
print("[警告] 检测到文件上传失败:错误码 == 101")
file_name = os.path.basename(file_path)
file_prefix, file_suffix = os.path.splitext(file_name)
temp_name = f"temp{file_suffix}"
print(f"尝试使用临时文件名 {temp_name} 替代原文件名 {file_name}")
# 使用临时文件名重试上传
with open(file_path, "rb") as file:
response = requests.post(
url,
files={"file": (temp_name, file)},
data={"json": options_json},
)
res_data = self._check_response(response)
self.task_id = res_data["data"]
print("任务ID:", self.task_id)
return self.task_id
def poll_task_status(self, interval=1):
"""
轮询任务状态直到完成
:param interval: 轮询间隔(秒)
"""
if not self.task_id:
raise ValueError("没有有效的任务ID")
print("===================================================")
print("===== 2. 轮询任务状态直到OCR任务完成 =====")
url = f"{self.base_url}/api/doc/result"
print("== 请求地址:", url)
request_data = {
"id": self.task_id,
"is_data": True,
"format": "text",
"is_unread": True,
}
while True:
time.sleep(interval)
response = requests.post(url, data=json.dumps(request_data), headers=self.headers)
res_data = self._check_response(response)
# 打印处理进度
processed = res_data["processed_count"]
total = res_data["pages_count"]
print(f" 处理进度: {processed}/{total}")
# 打印实时数据
if res_data["data"]:
print(f"{res_data['data']}\n========================")
# 检查任务是否完成
if res_data["is_done"]:
if res_data["state"] != "success":
raise RuntimeError(f"任务执行失败: {res_data['message']}")
print("OCR任务处理完成")
break
def generate_download_link(self, file_types=None, ignore_blank=False):
"""
生成结果文件下载链接
:param file_types: 需要生成的文件类型列表
:param ignore_blank: 是否忽略空白页
:return: (下载链接, 文件名)
"""
if not self.task_id:
raise ValueError("没有有效的任务ID")
print("======================================================")
print("===== 3. 生成目标文件,获取下载链接 =====")
url = f"{self.base_url}/api/doc/download"
print("== 请求地址:", url)
# 默认文件类型列表
if file_types is None:
file_types = [
"txt",
"txtPlain",
"jsonl",
"csv",
"pdfLayered",
"pdfOneLayer",
]
request_data = {
"id": self.task_id,
"file_types": file_types,
"ingore_blank": ignore_blank, # 注意:历史版本可能需要保留拼写错误
}
response = requests.post(url, data=json.dumps(request_data), headers=self.headers)
res_data = self._check_response(response)
return res_data["data"], res_data["name"]
def download_file(self, url, filename):
"""
下载结果文件
:param url: 下载链接
:param filename: 保存文件名
"""
print("===================================")
print("===== 4. 下载目标文件 =====")
print("== 请求地址:", url)
# 创建下载目录
if not os.path.exists(self.download_dir):
os.makedirs(self.download_dir)
save_path = os.path.join(self.download_dir, filename)
# 执行下载并显示进度
with requests.get(url, stream=True) as response:
response.raise_for_status()
total_size = int(response.headers.get("content-length", 0))
downloaded = 0
log_interval = 10_485_760 # 每10MB打印进度
with open(save_path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
downloaded += len(chunk)
if downloaded >= log_interval:
log_interval += 10_485_760
progress = (downloaded / total_size) * 100
print(
f" 下载进度: {downloaded//1_048_576}MB | "
f"总进度: {progress:.2f}%"
)
print(f"文件下载完成,保存路径: {save_path}")
def cleanup_task(self):
"""清理服务器上的任务数据"""
if not self.task_id:
raise ValueError("没有有效的任务ID")
print("============================")
print("===== 5. 清理任务 =====")
url = f"{self.base_url}/api/doc/clear/{self.task_id}"
print("== 请求地址:", url)
response = requests.get(url)
res_data = self._check_response(response)
print("任务数据清理完成")
@staticmethod
def _check_response(response):
"""统一检查响应结果"""
response.raise_for_status()
res_data = json.loads(response.text)
if res_data["code"] != 100:
raise RuntimeError(f"API请求失败: {res_data}")
return res_data
# 使用示例
if __name__ == "__main__":
# 初始化处理器
processor = UmiOCRProcessor(download_dir="./下载结果")
try:
# 步骤1:上传文件
task_id = processor.upload_file("XXXXX.pdf")
# 步骤2:轮询任务状态
processor.poll_task_status()
# 步骤3:生成下载链接
download_url, filename = processor.generate_download_link()
# 步骤4:下载文件
processor.download_file(download_url, filename)
# 步骤5:清理任务
processor.cleanup_task()
print("\n======================\n处理流程完成")
except Exception as e:
print(f"\n发生错误: {str(e)}")
最终的识别结果:

错误排查手册
详细内容请见: https://github.com/hiroi-sora/Umi-OCR/issues/447
================================
弹窗报错 Cannot find Py_Main() in ……
解决方法1:
下载安装VC运行库,重启系统,测试Umi-OCR能否正常运行。https://aka.ms/vs/17/release/vc_redist.x64.exe
解决方法2:
使用这个bat文件代替 Umi-OCR.exe 来启动软件。双击它即可。
UmiOCR-data/RUN_GUI.bat
注意1:通过bat启动时,部分功能受限,将无法使用命令行指令和创建快捷方式(开始菜单、开机自启等)。如有需要,请参考后面【手动放置快捷方式】条目。
注意2:不要移动bat的位置。
================================
手动放置快捷方式
如果因为某些原因,软件自身无法创建快捷方式;请手动创建并将快捷方式放置到如下目录:
开始菜单目录:
C:\ProgramData\Microsoft\Windows\Start Menu
开机自启目录:
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
================================
弹窗报错 Failed to create OpenGL context ……
- 下载运行库:
https://github.com/hiroi-sora/Umi-OCR_v2/files/13167436/opengl32sw_64.zip - 解压,将其中的dll文件放置于:
UmiOCR-data/site-packages/PySide2/
================================
弹窗报错 Umi-OCR.exe 已停止工作
此问题常见于:软件已经在win10使用过,然后原封不动复制到win7上,导致配置冲突。
删除下述配置文件即可:
UmiOCR-data/.pre_settings
================================
应用程序无法正常启动(0xc0000142) 或者:[Error] OCR init fail.l. Argd: {'enable_mkldnn': True...
此问题大概率是:CPU不支持AVX指令集。
请换用 PaddleOCR 之外的插件或软件版本。比如:
方法1:更换使用 Umi-OCR_Rapid 。
方法2:额外导入 RapleOCR插件 。
================================
弹出黑框控制台窗口,【错误】Umi-OCR Error 找不到指定的程序 OSError
可能的发生条件:
- win7早期版本,缺少系统补丁(尤其是
KB2533623) - 其他原因,导致 Python 3.8 无法在该系统中运行。
修复方法:
推荐方法:使用系统检查更新(控制面板 → 系统和安全 → Windows Update → 检查更新),安装所有更新。
另一种方法:单独下载安装 KB2533623补丁 ,重启系统即可。不过,微软官方渠道已经关闭了该补丁的下载链接,您可能只能从第三方网站下载补丁,请务必注意安全。
================================
保存PDF时 “已停止工作”
文档识别,能识别出文字,能保存为txt等文件。但如果选择保存为双层可搜索PDF,则最后导出文件时弹窗报错:
Umi-OCR.exe 已停止工作
查看问题详细信息:
问题事件名称:BEX64
故障模块名称:ucrtbase.DLL
故障模块版本:10.0.10240.16390
异常偏移:00000000064399
异常代码:c0000417可能的发生条件:win7早期版本,缺少系统补丁(尤其是 KB4534310、KB3042058)
修复方法:
注意!由于 KB4534310 依赖前置补丁,因此 不能 单独下载安装该补丁。
您必须使用系统检查更新(控制面板 → 系统和安全 → Windows Update → 检查更新),安装所有缺失的更新,直到下面这个项目安装完毕:
2020-01 适用于基于 x64 的系统的 Windows 7 月度安全质量汇总 (KB4534310)
================================
丢失api-ms-win-crt-runtime-l1-1-0.dll
打开软件时,弹出错误弹窗:
Umi-OCR.exe-系统错误
无法启动此程序,因为计算机中丢失 api-ms-win-crt-runtime-l1-1-0.dll 。尝试重新安装该程序以解决此问题。
可能的发生条件:缺少VC运行库。
修复方法:安装VC运行库:
https://aka.ms/vs/17/release/vc_redist.x64.exe