(可API调用)无需联网即可使用基于深度学习识别的OCR工具Umi-OCR,内置高效率的离线OCR引擎

(可API调用)无需联网即可使用基于深度学习识别的OCR工具Umi-OCR,内置高效率的离线OCR引擎

admin
4月9日发布
温馨提示:
本文最后更新于2025年04月10日,已超过202天没有更新,若内容或图片失效,请留言反馈。

本文深入解析了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

批量OCR:

批量OCR

批量文档:

批量文档

二维码:

二维码

命令行API调用

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

允许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.txt

HTTP接口手册

HTTP接口手册 - Github

具体有点太多了,可以自行查看官方文档。

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 ……

  1. 下载运行库:
    https://github.com/hiroi-sora/Umi-OCR_v2/files/13167436/opengl32sw_64.zip
  2. 解压,将其中的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早期版本,缺少系统补丁(尤其是 KB4534310KB3042058

修复方法:

注意!由于 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

© 版权声明
THE END
喜欢就支持一下吧
点赞 0 分享 赞赏
评论 抢沙发
上传图片
OωO
取消