docs(core): 精简 lib/types/error 文档注释并新增快速开始示例

This commit is contained in:
2026-08-05 09:43:46 +08:00
parent a3c4614574
commit 84cc97b201
11 changed files with 60 additions and 196 deletions

View File

@@ -3,4 +3,3 @@ mod executor;
pub use builder::DetBuilder; pub use builder::DetBuilder;
pub use executor::{DetectionResult, Detector}; pub use executor::{DetectionResult, Detector};
// pub use ddddocr_tract::det::session::DetSession;

View File

@@ -5,7 +5,7 @@ use crate::traits::DetEngine;
pub struct DetBuilder; pub struct DetBuilder;
impl DetBuilder { impl DetBuilder {
fn build<E: DetEngine>(self, session: &E) -> Detector<'_> { fn build_with<E: DetEngine>(self, session: &E) -> Detector<'_> {
Detector { session } Detector { session }
} }
} }

View File

@@ -1,130 +1,44 @@
pub(crate) const MODEL_DOWNLOAD_HELP: &str = "\ //! 分层错误类型:预处理、推理、解码三阶段的强类型错误。
================================================================================
[ddddocr-rust] 错误:未找到默认的模型文件!
--------------------------------------------------------------------------------
由于打包体积限制,本库未内置 ONNX 模型。请按照以下步骤操作:
1. 前往官方 GitHub 下载对应的模型权重:
- OCR 模型: https://github.com/sml2h3/ddddocr/raw/master/ddddocr/common_sml2h3_f32.onnx
- DET 模型: https://github.com/sml2h3/ddddocr/raw/master/ddddocr/common_det.onnx
2. 配置加载方式(二选一):
A. 【推荐】设置环境变量指向您下载的文件:
Linux/macOS: export DDDD_OCR_MODEL=\"/path/to/common_sml2h3_f32.onnx\"
Windows (CMD): set DDDD_OCR_MODEL=C:\\path\\to\\common_sml2h3_f32.onnx
Windows (PowerShell): $env:DDDD_OCR_MODEL=\"C:\\path\\to\\common_sml2h3_f32.onnx\"
B. 或者直接将模型文件重命名并放置在您运行程序的“当前工作目录”或“可执行文件同级目录”下。
================================================================================";
use thiserror::Error; use thiserror::Error;
//
// #[derive(Error, Debug)]
// pub enum DdddError {
// // 【新增】专门处理文件读取、路径不存在等原生 I/O 错误
// #[error("系统网络或文件 I/O 异常: {0}")]
// Io(#[from] std::io::Error),
//
// #[error("图像预处理失败: {0}")]
// PreprocessError(#[from] ImagePreprocessReason),
//
// #[error("模型推理引擎内部发生异常: {0}")]
// EngineError(#[from] anyhow::Error),
//
// #[error("CTC 解码错误: {0}")]
// DecodeError(String),
//
// #[error("维度转换失败,预期维度 {expected},实际形状为 {actual:?}")]
// DimensionMismatch {
// expected: String,
// actual: Vec<usize>,
// },
//
// #[error("内存不连续,无法执行零拷贝操作")]
// NonContiguousMemory,
//
// #[error("未知的模型输出格式")]
// UnknownOutputFormat,
//
// #[error("解析节点 Fact 失败")]
// InternalError(String),
// }
//
// /// 专门服务于预处理的子错误枚举,保留全部底层上下文
// #[derive(Error, Debug)]
// pub enum ImagePreprocessReason {
// #[error("图片加载或文件 I/O 失败: {0}")]
// ImageIo(#[from] image::ImageError),
//
// #[error("图片转矩阵矩阵(ndarray)失败: {0}")]
// NdarrayError(#[from] ndarray::ShapeError),
//
// #[error("Base64 解码失败: {0}")]
// Base64(#[from] base64::DecodeError),
//
// #[error("Base64 头部格式不正确,缺少 ';base64,' 分隔符")]
// InvalidBase64Header,
//
// #[error("不支持的通道数: {0}")]
// UnsupportedChannels(usize),
//
// #[error("其他预处理错误: {0}")]
// Custom(String),
// }
/// 统一用我们自己的 DdddError 包装 Result /// 全局统一的 `Result` 别名,默认错误类型为 [`DdddError`]。
// pub type Result<T> = std::result::Result<T, DdddError>; // pub type Result<T> = std::result::Result<T, DdddError>;
pub type Result<T, E = DdddError> = std::result::Result<T, E>; pub type Result<T, E = DdddError> = std::result::Result<T, E>;
// =====================================================================
// 1. 顶层全局 Error 分流器 (去 anyhow 化,完全基于标准库/自定义类型)
// =====================================================================
/// 顶层错误类型,聚合本库各阶段错误。
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum DdddError { pub enum DdddError {
// /// 系统文件、网络等原生 I/O 异常 (高优先级自动转换)
// #[error("系统网络或文件 I/O 异常: {0}")]
// Io(#[from] std::io::Error),
/// 图像预处理阶段发生异常
#[error("图像预处理失败: {0}")] #[error("图像预处理失败: {0}")]
Preprocess(#[from] ImagePreprocessError), Preprocess(#[from] ImagePreprocessError),
/// 推理引擎与张量操作阶段发生异常
#[error("推理与模型输入/输出张量异常: {0}")] #[error("推理与模型输入/输出张量异常: {0}")]
Inference(#[from] TensorError), Inference(#[from] TensorError),
/// 算法后处理解码阶段发生异常
#[error("后处理解码错误: {0}")] #[error("后处理解码错误: {0}")]
Decode(#[from] DecodeError), Decode(#[from] DecodeError),
/// 框架内部不可恢复的逻辑断言错误(如解析节点 Fact 失败) /// 框架内部不可恢复的逻辑断言错误(如解析节点 Fact 失败)
#[error("内部严重逻辑错误: {0}")] #[error("内部严重逻辑错误: {0}")]
Internal(String), Internal(String),
/// 【流派核心】接替 anyhow::Error 的用户自定义扩展错误
/// 承载任何第三方扩展、解密、特定预处理插件在执行时产生的自定义错误 /// 用户自定义扩展错误,用于包装第三方插件产生的错误
#[error("用户自定义扩展错误: {0}")] #[error("用户自定义扩展错误: {0}")]
Other(#[source] Box<dyn std::error::Error + Send + Sync>), Other(#[source] Box<dyn std::error::Error + Send + Sync>),
} }
// ===================================================================== /// 图像预处理阶段错误类型。
// 2. 子领域 A: 图像预处理错误类型
// =====================================================================
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ImagePreprocessError { pub enum ImagePreprocessError {
// #[error("图片加载或解码失败: {0}")]
// ImageIo(#[from] image::ImageError),
// image_io
#[error("图片转矩阵(ndarray)基础操作失败: {0}")] #[error("图片转矩阵(ndarray)基础操作失败: {0}")]
Ndarray(#[from] ndarray::ShapeError), Ndarray(#[from] ndarray::ShapeError),
// image_io
#[error("图像矩阵维度不合规!预期: {expected},实际图像形状: {actual:?}")] #[error("图像矩阵维度不合规!预期: {expected},实际图像形状: {actual:?}")]
InvalidDimensions { InvalidDimensions {
expected: String, expected: String,
actual: Vec<usize>, actual: Vec<usize>,
}, },
// image_io
/// 从 ndarray 原始数据构建图像缓冲区时,缓冲区长度与分辨率/通道数不匹配
#[error( #[error(
"图像缓冲区长度不匹配!预期大小: {expected},实际大小: {actual} (分辨率: {width}x{height}, 通道数: {channels})" "图像缓冲区长度不匹配!预期大小: {expected},实际大小: {actual} (分辨率: {width}x{height}, 通道数: {channels})"
)] )]
@@ -135,24 +49,21 @@ pub enum ImagePreprocessError {
height: u32, height: u32,
channels: usize, channels: usize,
}, },
// image_io
#[error("不支持的图像通道数: {0} (仅支持单通道灰度L、3通道RGB、4通道RGBA)")] #[error("不支持的图像通道数: {0} (仅支持单通道灰度L、3通道RGB、4通道RGBA)")]
UnsupportedChannels(usize), UnsupportedChannels(usize),
// ================= 新增:针对 HSV 和 Preset 的强类型错误 =================
/// HSV 颜色区间非法 (例如 H > 180 或 lower > upper)
#[error("HSV 颜色区间参数非法: {0}")] #[error("HSV 颜色区间参数非法: {0}")]
InvalidHsvRange(String), InvalidHsvRange(String),
/// 不支持或未知的颜色预设名称
#[error("不支持的颜色预设名称: {0}")] #[error("不支持的颜色预设名称: {0}")]
UnknownColorPreset(String), UnknownColorPreset(String),
/// 颜色过滤器/预处理规则配置非法导致失败
#[error("颜色过滤器配置无效或初始化失败: {0}")] #[error("颜色过滤器配置无效或初始化失败: {0}")]
FilterConfigInvalid(String), FilterConfigInvalid(String),
#[error("图像维度不匹配!{0}")] #[error("图像维度不匹配!{0}")]
MismatchDimensions (String), MismatchDimensions(String),
#[error("滑块模板尺寸 [{target_w}x{target_h}] 大于背景图 [{bg_w}x{bg_h}]")] #[error("滑块模板尺寸 [{target_w}x{target_h}] 大于背景图 [{bg_w}x{bg_h}]")]
TargetExceedsBackground { TargetExceedsBackground {
@@ -161,88 +72,46 @@ pub enum ImagePreprocessError {
bg_w: usize, bg_w: usize,
bg_h: usize, bg_h: usize,
}, },
// #[error("Base64 解码失败: {0}")]
// Base64(#[from] base64::DecodeError),
//
// #[error("Base64 头部格式不正确,缺少 ';base64,' 分隔符")]
// InvalidBase64Header,
// #[error("其他预处理错误: {0}")]
// Other(String),
} }
// ===================================================================== /// 推理与张量操作阶段错误类型。
// 3. 子领域 B: 推理与张量操作错误类型
// =====================================================================
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum TensorError { pub enum TensorError {
/// 替换原有的 anyhow::Error明确将 Tract/ONNX 引擎底层报错序列化为干净的 String
#[error("推理引擎内部发生异常: {0}")] #[error("推理引擎内部发生异常: {0}")]
Engine(String), Engine(String),
/// 模型张量维度不匹配 (原有的顶层 DimensionMismatch 被优雅地归入本模块)
#[error("模型张量维度不匹配!预期: {expected},实际 Tensor 形状: {actual:?}")] #[error("模型张量维度不匹配!预期: {expected},实际 Tensor 形状: {actual:?}")]
DimensionMismatch { DimensionMismatch {
expected: String, expected: String,
actual: Vec<usize>, actual: Vec<usize>,
}, },
/// 新增:针对后处理 Logits 矩阵变形Reshape失败的精细化错误
/// 直接包装 ndarray::ShapeError保留强类型完美支持 match
#[error("OCR Logits 矩阵变形失败: {0}")] #[error("OCR Logits 矩阵变形失败: {0}")]
LogitsDimensionMismatch(#[from] ndarray::ShapeError), LogitsDimensionMismatch(#[from] ndarray::ShapeError),
/// 张量内存布局不是连续的
#[error("内存不连续,无法执行零拷贝操作")] #[error("内存不连续,无法执行零拷贝操作")]
NonContiguousMemory, NonContiguousMemory,
/// 模型的输出数据类型或格式不受支持
#[error("未知的模型输出格式")] #[error("未知的模型输出格式")]
UnknownOutputFormat, UnknownOutputFormat,
} }
// ===================================================================== /// 算法解码阶段错误类型。
// 4. 子领域 C: 算法解码错误类型
// =====================================================================
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum DecodeError { pub enum DecodeError {
/// CTC 解码器解码过程中的逻辑报错
#[error("CTC 解码异常: {0}")] #[error("CTC 解码异常: {0}")]
Ctc(String), Ctc(String),
} }
// =====================================================================
// 5. 【自定义错误安全注入】不使用全局 `#[from]`,采用显式包装避免特化冲突
// =====================================================================
impl DdddError { impl DdddError {
/// 提供类似 std::io::Error::new 的构造函数,方便手动且无痛地包装任意第三方错误 /// 手动包装任意第三方错误为 [`DdddError::Other`]。
pub fn new<E>(error: E) -> Self pub fn new<E>(error: E) -> Self
where where
E: Into<Box<dyn std::error::Error + Send + Sync>>, E: Into<Box<dyn std::error::Error + Send + Sync>>,
{ {
DdddError::Other(error.into()) DdddError::Other(error.into())
} }
// -----------------------------------------------------------------
// 2.3 优化提供一键判断与转换的快捷方法Downcasting Helpers
// -----------------------------------------------------------------
/// 快速判断是否是系统 I/O 错误
// pub fn is_io_error(&self) -> bool {
// matches!(self, DdddError::Io(_))
// }
/// 尝试将错误转换为引用形式的 `std::io::Error`
// pub fn as_io_error(&self) -> Option<&std::io::Error> {
// match self {
// DdddError::Io(err) => Some(err),
// _ => None,
// }
// }
/// 快速判断是否是预处理阶段的图片维度不合规错误
pub fn is_invalid_dimensions(&self) -> bool { pub fn is_invalid_dimensions(&self) -> bool {
matches!( matches!(
self, self,
@@ -250,25 +119,10 @@ impl DdddError {
) )
} }
/// 快速判断是否是因为图片通道数不合规导致的失败
pub fn is_unsupported_channels(&self) -> bool { pub fn is_unsupported_channels(&self) -> bool {
matches!( matches!(
self, self,
DdddError::Preprocess(ImagePreprocessError::UnsupportedChannels(_)) DdddError::Preprocess(ImagePreprocessError::UnsupportedChannels(_))
) )
} }
// 提取出底层最原始的那个错误(无论是 IO、预处理、推理、还是第三方扩展错误
// 方便外层统一打印更深层的 `source` 链条
// pub fn source_error(&self) -> Option<&(dyn std::error::Error + 'static)> {
// use std::error::Error;
// match self {
// // DdddError::Io(err) => Some(err),
// DdddError::Preprocess(err) => Some(err),
// DdddError::Inference(err) => Some(err),
// DdddError::Decode(err) => Some(err),
// DdddError::Other(err) => Some(err.as_ref()),
// DdddError::Internal(_) => None, // Internal 内部目前只有 String没有底层的 Error source
// }
// }
} }

View File

@@ -1,24 +1,35 @@
//! # ddddocr-core
//!
//! `ddddocr-rs` 的核心库:提供与具体推理引擎解耦的 OCR 识别、目标检测det与滑块匹配slide能力。
//! 推理能力由 [`traits::InferenceEngine`]、[`traits::OcrEngine`]、[`traits::DetEngine`] 抽象,
//! 由 `ddddocr-tract`、`ddddocr-ort` 等引擎 crate 实现。
//!
//! 完整可运行示例见 `ddddocr-core/examples/quick_start.rs`。
mod det; mod det;
/// 分层错误类型。
pub mod error; pub mod error;
mod ocr; mod ocr;
mod slide; mod slide;
/// 图像加载、转换与处理工具。
pub mod utils; pub mod utils;
/// 模型输入输出信息等共享类型。
pub mod types; pub mod types;
/// 推理引擎统一抽象接口。
pub mod traits; pub mod traits;
pub use crate::det::{DetBuilder, DetectionResult, Detector}; pub use crate::det::{DetBuilder, DetectionResult, Detector};
pub use crate::ocr::{Charset, ModelMetadata, Normalization, Ocr, OcrBuilder, OcrResult, Resize}; pub use crate::ocr::{Charset, ModelMetadata, Normalization, Ocr, OcrBuilder, OcrResult, Resize};
pub use crate::slide::{SlideResult, Slider}; pub use crate::slide::{SlideResult, Slider};
/// OCR 模型的统一输出枚举,由推理引擎产出,供 [`Ocr`] 后处理。
// DetSession
pub enum OcrOutput { pub enum OcrOutput {
Indices(ndarray::Array1<i64>), // 拥有完整所有权的 1维数组可任意传递和返回 Indices(ndarray::Array1<i64>),
Logits(ndarray::Array2<f32>), Logits(ndarray::Array2<f32>),
} }
/// 2. 目标检测专属的、编译期安全的输出枚举
/// 目标检测模型的统一输出枚举,由推理引擎产出,供 [`Detector`] 后处理。
pub enum DetOutput { pub enum DetOutput {
Detection(ndarray::Array3<f32>), // 拥有完整所有权的 2维矩阵可任意传递和返回 Detection(ndarray::Array3<f32>),
} }

View File

@@ -10,4 +10,3 @@ pub use charset::Charset;
pub use executor::{Ocr, OcrResult}; pub use executor::{Ocr, OcrResult};
pub use metadata::{ModelMetadata, Normalization, Resize}; pub use metadata::{ModelMetadata, Normalization, Resize};
pub use token_filter::TokenFilter; pub use token_filter::TokenFilter;
// pub use ddddocr_tract::session::OcrSession;

View File

@@ -49,7 +49,7 @@ impl OcrBuilder {
self.charset_restrict = Some(Box::new(restrict)); self.charset_restrict = Some(Box::new(restrict));
self self
} }
pub fn runner<E: OcrEngine>(self, runtime: &E) -> Ocr<'_> { pub fn build_with<E: OcrEngine>(self, runtime: &E) -> Ocr<'_> {
// 1. 原地解析颜色过滤器 // 1. 原地解析颜色过滤器
let final_color_ranges = match &self.color_filter { let final_color_ranges = match &self.color_filter {
Some(filter) => filter.collect_to_vec(), Some(filter) => filter.collect_to_vec(),

View File

@@ -13,7 +13,7 @@ pub trait TokenFilter {
fn estimated_capacity(&self) -> usize { fn estimated_capacity(&self) -> usize {
128 128
} }
/// 【新引入的架构级核心方法】
/// 统一接管全量字符集的密集遍历、CTC Blank放行、去重、排序及空交集退化兜底 /// 统一接管全量字符集的密集遍历、CTC Blank放行、去重、排序及空交集退化兜底
fn apply_to_charset(&self, tokens: &[Cow<str>]) -> Option<Vec<usize>> { fn apply_to_charset(&self, tokens: &[Cow<str>]) -> Option<Vec<usize>> {
let mut has_any_match = false; let mut has_any_match = false;
@@ -127,9 +127,8 @@ impl<'a> TokenFilter for MultiOrRestrict<'a> {
self.filters.iter().map(|f| f.estimated_capacity()).sum() self.filters.iter().map(|f| f.estimated_capacity()).sum()
} }
} }
// =====================================================================
// 声明式宏:替代 `+` 运算符,解决组合扩展痛苦 /// 声明式宏:解决组合扩展痛苦
// =====================================================================
#[macro_export] #[macro_export]
macro_rules! any_of { macro_rules! any_of {
// 场景 A如果用户只传了一个规则免去构建 Vec 的开销,直接返回其引用 // 场景 A如果用户只传了一个规则免去构建 Vec 的开销,直接返回其引用
@@ -137,7 +136,7 @@ macro_rules! any_of {
&$only as &dyn $crate::TokenFilter &$only as &dyn $crate::TokenFilter
}; };
// 场景 B如果用户传入了多个规则自动织成一张静态组合 // 场景 B如果用户传入了多个规则自动组合
($($filter:expr),+ $(,)?) => { ($($filter:expr),+ $(,)?) => {
&$crate::MultiOrRestrict { &$crate::MultiOrRestrict {
filters: vec![ $( &$filter as &dyn $crate::TokenFilter ),+ ] filters: vec![ $( &$filter as &dyn $crate::TokenFilter ),+ ]

View File

@@ -1,25 +1,27 @@
#[derive(Debug,Clone)] //! 模型输入输出信息等共享类型,由 [`crate::traits::Info`] 接口返回。
pub enum TensorType{
/// 张量元素的数据类型标记。
#[derive(Debug, Clone)]
pub enum TensorType {
F32, F32,
I64, I64,
Other Other,
} }
/// 明确命名为 AxisDim代表模型某一个轴的维度特征
/// 模型某个轴的维度特征:静态数值或动态符号。
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]
pub enum AxisDim { pub enum AxisDim {
/// 静态固定维度(如通道数固定为 1高度固定为 64
Static(usize), Static(usize),
/// 动态符号维度(如宽度是动态的 "image_width"
Dynamic(String), Dynamic(String),
} }
impl AxisDim { impl AxisDim {
/// 便捷方法:判断是否为动态维度
pub fn is_dynamic(&self) -> bool { pub fn is_dynamic(&self) -> bool {
matches!(self, AxisDim::Dynamic(_)) matches!(self, AxisDim::Dynamic(_))
} }
} }
/// 自定义 Debug 格式化输出,彻底融化套娃外壳,保证日志干净漂亮
/// 自定义 `Debug` 输出:静态维度显示数值,动态维度显示符号名。
impl std::fmt::Debug for AxisDim { impl std::fmt::Debug for AxisDim {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
@@ -28,19 +30,20 @@ impl std::fmt::Debug for AxisDim {
} }
} }
} }
/// 模拟 Python 的 input_info 和 output_info 结构
/// 单个张量(输入或输出)的名称、形状与数据类型描述。
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TensorInfo { pub struct TensorInfo {
pub name: String, pub name: String,
pub shape: Vec<AxisDim>, // 既包含 Fixed 静态维度,也包含 Dynamic 动态符号 pub shape: Vec<AxisDim>,
pub tensor_type: TensorType, // 对应 Python 的 type pub tensor_type: TensorType,
} }
/// 最终返回的模型完整信息 /// 模型完整输入/输出信息
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ModelInfo { pub struct ModelInfo {
pub inputs: Vec<TensorInfo>, pub inputs: Vec<TensorInfo>,
pub outputs: Vec<TensorInfo>, pub outputs: Vec<TensorInfo>,
/// 硬件执行提供者(采用 Option 兼容不同底层的推理引擎) /// 硬件执行提供者(`None` 表示使用引擎默认后端)。
pub providers: Option<Vec<String>>, pub providers: Option<Vec<String>>,
} }

View File

@@ -5,7 +5,6 @@ use ddddocr_core::traits::{DetEngine, InferenceEngine};
use ndarray::Ix3; use ndarray::Ix3;
use ort::inputs; use ort::inputs;
use ort::value::TensorRef; use ort::value::TensorRef;
// use tract_onnx::prelude::{tvec, IntoTensor, Tensor};
#[derive(Debug)] #[derive(Debug)]
pub struct DetRuntime { pub struct DetRuntime {

View File

@@ -105,7 +105,7 @@ fn save_rust_result(result: &ImageBuffer<Luma<f32>, Vec<f32>>, filename: &str) {
} }
#[test] #[test]
fn test_full_classification() { fn test_full_classification() {
let model = OrtModelLoader::default().use_gpu(false) let session = OrtModelLoader::default().use_gpu(false)
.build_for_path("D:\\CNWei\\CNW\\Rust\\ddddocr-rs\\models\\common_sml2h3_f32.onnx") .build_for_path("D:\\CNWei\\CNW\\Rust\\ddddocr-rs\\models\\common_sml2h3_f32.onnx")
// .build_for_path("D:\\CNWei\\CNW\\Rust\\ddddocr-rs\\models\\common_old.onnx") // .build_for_path("D:\\CNWei\\CNW\\Rust\\ddddocr-rs\\models\\common_old.onnx")
.expect("模型加载失败"); .expect("模型加载失败");
@@ -117,7 +117,7 @@ fn test_full_classification() {
Normalization::MinusOneToOne, Normalization::MinusOneToOne,
); );
// 1. 初始化模型 // 1. 初始化模型
let ocr = OcrRuntime::new(model, metadata); let ocr = OcrRuntime::new(session, metadata);
// 2. 加载测试图片 // 2. 加载测试图片
let img = let img =
image::open("D:/CNWei/CNW/Rust/ddddocr-rs/samples/code2.png").expect("测试图片不存在"); image::open("D:/CNWei/CNW/Rust/ddddocr-rs/samples/code2.png").expect("测试图片不存在");
@@ -132,7 +132,7 @@ fn test_full_classification() {
// .predict(&img) // .predict(&img)
// .expect("识别过程出错") // .expect("识别过程出错")
// .into_text(); // .into_text();
let res=Ocr::builder().runner(&ocr).predict(&img).expect("s").into_text(); let res=Ocr::builder().build_with(&ocr).predict(&img).expect("s").into_text();
// println!("识别结果: {}", result); // println!("识别结果: {}", result);
println!("识别结果: {}", res); println!("识别结果: {}", res);
@@ -141,10 +141,10 @@ fn test_full_classification() {
} }
#[test] #[test]
fn test_det_load() -> anyhow::Result<()> { fn test_det_load() -> anyhow::Result<()> {
let det_model = OrtModelLoader::default() let session = OrtModelLoader::default()
.build_for_path("D:\\CNWei\\CNW\\Rust\\ddddocr-rs\\models\\common_det.onnx") .build_for_path("D:\\CNWei\\CNW\\Rust\\ddddocr-rs\\models\\common_det.onnx")
.expect("模型加载失败"); .expect("模型加载失败");
let det = DetRuntime::new(det_model); let det = DetRuntime::new(session);
let image_path = "D:/CNWei/CNW/Rust/ddddocr-rs/samples/det1.png"; let image_path = "D:/CNWei/CNW/Rust/ddddocr-rs/samples/det1.png";
let image_bytes = let image_bytes =
fs::read(image_path).map_err(|e| anyhow::anyhow!("无法读取图片 {}: {}", image_path, e))?; fs::read(image_path).map_err(|e| anyhow::anyhow!("无法读取图片 {}: {}", image_path, e))?;

View File

@@ -128,7 +128,7 @@ fn test_full_classification() {
// .expect("识别过程出错") // .expect("识别过程出错")
// .into_text(); // .into_text();
let result = Ocr::builder() let result = Ocr::builder()
.runner(&ocr_runtime) .build_with(&ocr_runtime)
.predict(&img) .predict(&img)
.expect("识别过程出错") .expect("识别过程出错")
.into_text(); .into_text();