Rust语言封装chineseocr_lite:安全高效的系统级OCR库
chineseocr_lite是一个超轻量级中文OCR项目,支持竖排文字识别,总模型仅4.7M,包含dbnet(1.8M)、crnn(2.5M)和anglenet(378KB)三个模型。本文将介绍如何使用Rust语言封装chineseocr_lite,构建安全高效的系统级OCR库。
项目概述
chineseocr_lite项目提供了多种推理框架的支持,包括ncnn、mnn、tnn等。项目结构清晰,包含多个子项目,如C++ Demo、Jvm Demo、Android Demo等。原始项目使用Python实现,部署简单,支持多种操作系统。
核心模型文件
项目的核心模型文件位于models/目录下,包括:
- dbnet.onnx:用于文本检测的模型
- crnn_lite_lstm.onnx:用于文本识别的模型
- angle_net.onnx:用于文本角度检测的模型
这些模型文件是OCR功能的核心,Rust封装将基于这些模型进行推理实现。
现有C++实现参考
项目中已经提供了C++版本的实现,位于cpp_projects/目录下,包括OcrLiteMnn、OcrLiteNcnn和OcrLiteOnnx等子项目。这些实现可以作为Rust封装的重要参考,特别是:
- cpp_projects/OcrLiteNcnn/include/OcrLite.h:OCR核心类定义
- cpp_projects/OcrLiteNcnn/src/OcrLite.cpp:OCR核心实现
- cpp_projects/OcrLiteOnnx/include/DbNet.h:文本检测网络定义
- cpp_projects/OcrLiteOnnx/include/CrnnNet.h:文本识别网络定义
Rust封装方案
整体架构设计
Rust封装chineseocr_lite将采用以下架构:
- FFI层:使用Rust的FFI(Foreign Function Interface)能力,封装现有的C++推理代码
- 安全抽象层:在FFI之上构建Rust安全抽象,提供类型安全的API
- 高层API:设计易用的Rust API,支持文本检测、识别等核心功能
依赖选择
- ncnn-rs:ncnn的Rust绑定,用于模型推理
- image:Rust图像处理库,用于图像加载和预处理
- ndarray:Rust数值计算库,用于张量操作
- thiserror:错误处理库,定义清晰的错误类型
核心模块设计
- ocr_engine:OCR引擎核心模块,封装检测、识别等功能
- preprocess:图像预处理模块,实现图像缩放、归一化等操作
- postprocess:后处理模块,实现文本框提取、识别结果处理等
- model_loader:模型加载模块,负责加载和管理ONNX或ncnn模型
实现步骤
1. 模型加载
使用ncnn-rs加载ncnn模型文件,模型文件位于models_ncnn/目录下:
use ncnn::Net;
pub struct ModelLoader {
dbnet: Net,
crnn: Net,
anglenet: Net,
}
impl ModelLoader {
pub fn new() -> Self {
let mut dbnet = Net::new();
dbnet.load_param("models_ncnn/dbnet_op.param").unwrap();
dbnet.load_model("models_ncnn/dbnet_op.bin").unwrap();
let mut crnn = Net::new();
crnn.load_param("models_ncnn/crnn_lite_op.param").unwrap();
crnn.load_model("models_ncnn/crnn_lite_op.bin").unwrap();
let mut anglenet = Net::new();
anglenet.load_param("models_ncnn/angle_op.param").unwrap();
anglenet.load_model("models_ncnn/angle_op.bin").unwrap();
ModelLoader { dbnet, crnn, anglenet }
}
}
2. 图像预处理
使用image库加载图像并进行预处理:
use image::{DynamicImage, GenericImageView, ImageBuffer, Luma};
pub fn preprocess_image(image: &DynamicImage, target_size: (u32, u32)) -> ImageBuffer<Luma<u8>, Vec<u8>> {
// 调整图像大小
let resized = image.resize(target_size.0, target_size.1, image::imageops::FilterType::Triangle);
// 转换为灰度图
let gray = resized.to_luma8();
// 归一化处理
let mut processed = ImageBuffer::new(gray.width(), gray.height());
for (x, y, pixel) in gray.enumerate_pixels() {
processed.put_pixel(x, y, Luma([pixel.0[0] as f32 / 255.0 * 2.0 - 1.0]));
}
processed
}
3. 文本检测与识别
实现文本检测和识别的核心功能:
pub struct OcrEngine {
model_loader: ModelLoader,
}
impl OcrEngine {
pub fn new() -> Self {
OcrEngine {
model_loader: ModelLoader::new(),
}
}
pub fn detect_text(&self, image: &DynamicImage) -> Vec<TextBox> {
// 图像预处理
let processed = preprocess_image(image, (640, 640));
// 使用dbnet进行文本检测
let mut input = ncnn::Mat::from_bytes(
processed.as_raw(),
processed.width() as i32,
processed.height() as i32,
1,
ncnn::PixelType::PIXEL_GRAY,
).unwrap();
let mut output = ncnn::Mat::new();
self.model_loader.dbnet.forward(&mut input, &mut output).unwrap();
// 后处理获取文本框
let text_boxes = postprocess_dbnet_output(&output);
text_boxes
}
pub fn recognize_text(&self, image: &DynamicImage, text_boxes: &[TextBox]) -> Vec<String> {
let mut results = Vec::new();
for box in text_boxes {
// 裁剪文本区域
let cropped = crop_image(image, box);
// 预处理
let processed = preprocess_crnn_input(&cropped);
// 使用crnn进行文本识别
let result = self.model_loader.crnn.forward(&processed).unwrap();
// 解码识别结果
let text = decode_crnn_output(&result);
results.push(text);
}
results
}
}
性能优化
多线程处理
利用Rust的并发特性,实现图像预处理和文本识别的并行处理:
use rayon::prelude::*;
pub fn recognize_text_parallel(&self, image: &DynamicImage, text_boxes: &[TextBox]) -> Vec<String> {
text_boxes.par_iter()
.map(|box| {
let cropped = crop_image(image, box);
let processed = preprocess_crnn_input(&cropped);
let result = self.model_loader.crnn.forward(&processed).unwrap();
decode_crnn_output(&result)
})
.collect()
}
内存管理优化
使用Rust的所有权系统,优化内存管理,避免内存泄漏:
// 使用RAII模式管理模型资源
struct ModelResource<T> {
inner: T,
}
impl<T> Drop for ModelResource<T> {
fn drop(&mut self) {
// 释放模型资源
unsafe {
// 调用C++析构函数或释放函数
release_model(&mut self.inner);
}
}
}
应用示例
基本OCR功能
use chineseocr_lite_rs::OcrEngine;
use image::open;
fn main() {
// 创建OCR引擎
let engine = OcrEngine::new();
// 加载图像
let image = open("test.jpg").unwrap();
// 检测文本
let text_boxes = engine.detect_text(&image);
// 识别文本
let texts = engine.recognize_text(&image, &text_boxes);
// 输出结果
for text in texts {
println!("识别结果: {}", text);
}
}
实际识别效果
chineseocr_lite项目提供了多个测试图像和识别效果展示,例如:
这些动图展示了OCR在不同场景下的识别效果,Rust封装将保持类似的识别精度和性能。
总结与展望
Rust语言封装chineseocr_lite可以充分发挥Rust的安全、高效特性,为系统级OCR应用提供可靠的解决方案。未来可以进一步优化:
- 纯Rust实现:逐步替换C++依赖,实现纯Rust的推理引擎
- WebAssembly支持:编译为WebAssembly,支持浏览器端OCR
- 移动端支持:结合Rust的跨平台能力,支持Android和iOS平台
通过Rust封装,chineseocr_lite将获得更好的安全性、性能和跨平台能力,为更多场景提供高质量的OCR解决方案。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考






