# lw-ppocr-vulkan-java **Repository Path**: wuyuan/lw-ppocr-vulkan-java ## Basic Information - **Project Name**: lw-ppocr-vulkan-java - **Description**: lw-ppocr-vulkan java操作库 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-08 - **Last Updated**: 2026-10-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # lw-ppocr-vulkan 基于 Vulkan GPU 加速的 PPOCRv6 Java 接口库 ## 项目简介 lw-ppocr-vulkan 是一个高性能的 Java OCR(光学字符识别)库,基于 PPOCRv6 模型并利用 Vulkan GPU 进行加速计算。该项目提供了简洁的 Java API,支持多种集成方式,包括原生 Java 调用、Spring Boot 和 Solon 框架集成。 ## 主要特性 - **Vulkan GPU 加速**:利用 Vulkan API 实现高效的 GPU 并行计算 - **多框架支持**:支持原生 Java、Spring Boot 和 Solon - **连接池支持**:内置引擎连接池,支持高并发场景 - **丰富的配置选项**:提供细粒度的 OCR 参数配置 - **多语言支持**:支持中文、英文等多种语言的文本识别 ## 模块结构 | 模块 | 说明 | |------|------| | lw-ppocr-vulkan-common | 核心库,包含 OCR 引擎和所有核心类 | | lw-ppocr-vulkan-spring-boot-starter | Spring Boot 自动配置 starter | | lw-ppocr-vulkan-solon-plugin | Solon 框架插件 | | samples/spring-boot-ocr-app | Spring Boot 示例应用 | | samples/solon-ocr-app | Solon 示例应用 | ## 快速开始 ### Maven 依赖 ```xml com.lw.ppocr lw-ppocr-vulkan-spring-boot-starter 1.0.0 ``` ### 基本使用 ```java // 创建 OCR 引擎 LwPpocr ocr = LwPpocr.create("/path/to/ppocrv6-tiny"); // 识别图片 OcrResult result = ocr.ocr(imageBytes); // 获取识别结果 for (OcrItem item : result.getItems()) { System.out.println("文本: " + item.getText()); System.out.println("置信度: " + item.getScore()); } ``` ### Spring Boot 集成 在 `application.yml` 中配置: ```yaml lw: ppocr: enabled: true model-root: ./models/ppocrv6-tiny device-index: 0 # 单引擎 + 有界队列(与官方 HTTP 服务同一套模型),默认 4 / 32 / 5000 workers: 4 max-queued: 32 engine-wait-timeout-ms: 5000 ``` 注入服务: ```java @RestController public class OcrController { @Autowired private LwPpocrService ocrService; @PostMapping("/ocr") public OcrResult ocr(@RequestParam("file") MultipartFile file) throws IOException { return ocrService.ocr(file.getBytes()); } } ``` ## 配置选项 | 配置项 | 类型 | 默认值 | 说明 | |--------|------|--------|------| | model-root | String | - | 模型文件根目录(必填) | | device-index | int | 0 | GPU 设备编号 | | nativeLibrary | String | 自动检测 | 原生库路径 | | nativeDir | String | 自动检测 | 原生库目录 | | workers | int | 4 | worker 线程数(最多并发执行中的任务数) | | max-queued | int | 32 | 待处理队列上限,满了返回 429 | | engine-wait-timeout-ms | long | 5000 | 等待结果的时限,超时返回 503 | | enableClassifier | Boolean | null | 启用方向分类器 | | useDilation | Boolean | null | 使用膨胀操作 | | readingOrder | Boolean | null | 按阅读顺序排序 | | detLimitSide | Integer | null | 检测边长限制 | | maxCandidates | Integer | null | 最大候选数量 | | bitmapThreshold | Float | 0.3 | 二值化阈值 | | boxThreshold | Float | 0.5 | 文本框置信度阈值 | | unclipRatio | Float | 1.5 | 文本框扩展比例 | | clsThreshold | Float | 0.9 | 方向分类置信度阈值 | ## API 参考 ### LwPpocr(核心引擎) ```java // 创建引擎 LwPpocr ocr = LwPpocr.create(modelRoot); // 或使用自定义选项 LwPpocrOptions options = LwPpocrOptions.builder(modelRoot) .deviceIndex(0) .enableClassifier(true) .build(); LwPpocr ocr = LwPpocr.create(options); // 识别图片 OcrResult ocr(byte[] encodedImageBytes); OcrResult ocr(BgrImage image); OcrResult ocr(byte[] pixels, int width, int height, int stride); // 获取设备列表 List devices(); // 引擎是否已关闭(close() 之后为 true) boolean isClosed(); // 关闭引擎 ocr.close(); ``` > `version()` / `devices()` 只读库级信息、不碰引擎 handle,因此 `close()` 之后仍可安全调用;推理入口 > (`ocr` / `recognizeLine`)在关闭后抛 `IllegalStateException`。 ### LwPpocrQueue(单引擎 + 有界队列) 与官方 `lw-ppocr-vulkan-http-service` 同一套并发模型:唯一引擎、N 个 worker 取任务、待处理队列有上限。 ```java // 用默认参数包装:4 worker / 队列 32 / 等待 5000ms LwPpocrQueue queue = LwPpocrQueue.create(options); // 或直接从引擎包装 LwPpocrQueue queue = LwPpocrQueue.of(LwPpocr.create(options)); // 提交任务并等结果 String text = queue.submit(ocr -> ocr.ocr(imageBytes).text()); // 关闭 queue.closeAndAwait(); ``` **三种过载各有各的状态码**(与官方一致): | 情况 | 异常 | HTTP | |------|------|------| | 队列已满 | `LwPpocrQueueFullException` | **429** QUEUE_FULL | | 等到超时还没结果 | `LwPpocrEngineBusyException` | **503** ENGINE_WAIT_TIMEOUT | | 引擎已不可用 | `LwPpocrEngineUnavailableException` | **503** ENGINE_UNAVAILABLE | > **队列满必须立刻失败**:排队的地方是这块有界队列,不是 HTTP 线程池。让请求继续堆在线程池里, > 会把「装不下」放大成「整个服务不可用」。 > > **引擎故障后整体标记不可用**:native 返回非 OK(掉卡、显存不足)或抛 `Error` 时,队列被一次性 > 标记为 `broken`,待处理任务全部立刻失败,之后所有提交直接拒绝——不让每个请求各等一个超时周期。 > 业务错误(坏图)不会触发。恢复只能重建引擎(重启进程)。 > > **退出前释放**:`close()` 立刻返回,正在跑的任务跑完后由最后一个退出的 worker 销毁引擎; > 但容器接着退出就会漏掉那些 handle(约 60MiB 显存)。容器关闭 / `@PreDestroy` 请用 > `queue.closeAndAwait()`(最多等 10s,见 `LwPpocrQueue.DEFAULT_DRAIN_TIMEOUT_MS`), > Spring 的队列 bean 已经默认这么关。忘记 close 时还有 Cleaner 兜底,但它是兜底不是确定性释放。 > > **不要在任务里再次提交**(worker 线程重入):worker 数量有限,每个 worker 都等自己的子任务时会 > 互等至死,因此重入直接抛 `IllegalStateException`。 > > **不要 close() 队列持有的引擎**(例如 `service.nativeEngine().close()`):句柄已 destroy, > 再碰就是 use-after-free,队列会把整个服务标成不可用。 > > 运维可观测:`GET /api/ocr/info` 返回 `workers` / `maxQueued` / `pending` / `active` / `broken`。 > > **为什么默认单引擎**:同一 handle 的推理必须串行,吞吐上限就是 `1 / 单次耗时`。本机实测 > (640×320 图、ppocrv6-tiny):GTX 1650 单实例 28.0ms/次时 GPU 已占 83%,2 实例 → 98% / +18%, > 4 实例到头(44.1 QPS);Intel UHD 630 单实例就把引擎吃到 97–99%,多实例吞吐不涨。 > 多开的代价是每实例约 60MiB 权重显存。需要更高并发请先跑 `tools/gpubench` 确认 GPU 有余量。 ### OcrResult(识别结果) ```java OcrResult result = ocr.ocr(imageBytes); // 获取所有文本 String fullText = result.text(); // 获取逐行文本 List lines = result.lines(); // 获取详细信息 List items = result.getItems(); Timing timing = result.getTiming(); double elapsedMs = result.getElapsedMs(); ``` ## 性能测试 项目提供了 GPU 性能测试工具,位于 `tools/gpubench` 目录: ```bash cd tools/gpubench go run main.go -image ../test-images/sample.jpg -devices 0,1 ``` ## 模型文件 项目包含 PPOCRv6-tiny 模型,位于 `models/ppocrv6-tiny` 目录: - `det.onnx` - 文本检测模型 - `rec.onnx` - 文本识别模型 - `cls.onnx` - 方向分类模型 - `dictionary.txt` - 字典文件 ## 系统要求 - Java 8 或更高版本 - 支持 Vulkan 1.0+ 的 GPU 驱动 - Windows 或 Linux 操作系统 ## 许可证 本项目基于 Apache License 2.0 许可证开源。