# 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 许可证开源。