pub struct Det {
pub params: DbParams,
/* private fields */
}Expand description
载入好的检测模型。
Fields§
§params: DbParamsDB 后处理参数;缺省同参考实现,可按需调整。
Implementations§
Source§impl Det
impl Det
Sourcepub fn load(dir: &Path) -> Result<Det, String>
pub fn load(dir: &Path) -> Result<Det, String>
dir 是模型目录:model.safetensors、config.json、preprocessor_config.json。
Examples found in repository?
examples/det_check.rs (line 16)
9fn main() {
10 let a: Vec<String> = std::env::args().skip(1).collect();
11 if a.len() < 5 || !(a.len() - 2).is_multiple_of(3) {
12 eprintln!("用法:det_check <模型目录> <输出目录> <裸图> <宽> <高> ...");
13 std::process::exit(2);
14 }
15 let t = Instant::now();
16 let det = pagesift_ocr::det::Det::load(std::path::Path::new(&a[0])).unwrap();
17 eprintln!("载入 {:.0} ms", t.elapsed().as_secs_f64() * 1e3);
18 let out_dir = std::path::Path::new(&a[1]);
19 for c in a[2..].chunks(3) {
20 let data = std::fs::read(&c[0]).unwrap();
21 let (w, h): (usize, usize) = (c[1].parse().unwrap(), c[2].parse().unwrap());
22 let channels = data.len() / (w * h);
23 assert!(channels == 1 || channels == 3, "文件大小与宽高不符");
24 let img = pagesift_ocr::Image {
25 width: w,
26 height: h,
27 channels,
28 data,
29 };
30 let name = std::path::Path::new(&c[0])
31 .file_name()
32 .unwrap()
33 .to_string_lossy();
34 let t = Instant::now();
35 let (prob, pw, ph) = det.prob_map(&img).unwrap();
36 let net_ms = t.elapsed().as_secs_f64() * 1e3;
37 let boxes = det.boxes_from_prob(&prob, pw, ph, w, h);
38 let ms = t.elapsed().as_secs_f64() * 1e3;
39 eprintln!("{name}: 网络 {net_ms:.0} ms,后处理 {:.0} ms", ms - net_ms);
40 // 设了 DET_DUMP_PROB 就把概率图另存成 8 位 PGM
41 if std::env::var_os("DET_DUMP_PROB").is_some() {
42 let mut pgm = format!("P5\n{pw} {ph}\n255\n").into_bytes();
43 pgm.extend(prob.iter().map(|v| (v * 255.0).round() as u8));
44 std::fs::write(out_dir.join(format!("{name}.prob.pgm")), pgm).unwrap();
45 }
46 let mut f = std::fs::File::create(out_dir.join(format!("{name}.boxes.txt"))).unwrap();
47 for (q, s) in &boxes {
48 for (x, y) in q {
49 write!(f, "{x} {y} ").unwrap();
50 }
51 writeln!(f, "{s:.4}").unwrap();
52 }
53 eprintln!("{name}: {w}×{h},{} 个框,{ms:.0} ms", boxes.len());
54 }
55}Sourcepub fn prob_map(&self, page: &Image) -> Result<(Vec<f32>, usize, usize), String>
pub fn prob_map(&self, page: &Image) -> Result<(Vec<f32>, usize, usize), String>
整页图 → 文字概率图(网络输入尺寸,按行存放)及其宽、高。
Examples found in repository?
examples/det_check.rs (line 35)
9fn main() {
10 let a: Vec<String> = std::env::args().skip(1).collect();
11 if a.len() < 5 || !(a.len() - 2).is_multiple_of(3) {
12 eprintln!("用法:det_check <模型目录> <输出目录> <裸图> <宽> <高> ...");
13 std::process::exit(2);
14 }
15 let t = Instant::now();
16 let det = pagesift_ocr::det::Det::load(std::path::Path::new(&a[0])).unwrap();
17 eprintln!("载入 {:.0} ms", t.elapsed().as_secs_f64() * 1e3);
18 let out_dir = std::path::Path::new(&a[1]);
19 for c in a[2..].chunks(3) {
20 let data = std::fs::read(&c[0]).unwrap();
21 let (w, h): (usize, usize) = (c[1].parse().unwrap(), c[2].parse().unwrap());
22 let channels = data.len() / (w * h);
23 assert!(channels == 1 || channels == 3, "文件大小与宽高不符");
24 let img = pagesift_ocr::Image {
25 width: w,
26 height: h,
27 channels,
28 data,
29 };
30 let name = std::path::Path::new(&c[0])
31 .file_name()
32 .unwrap()
33 .to_string_lossy();
34 let t = Instant::now();
35 let (prob, pw, ph) = det.prob_map(&img).unwrap();
36 let net_ms = t.elapsed().as_secs_f64() * 1e3;
37 let boxes = det.boxes_from_prob(&prob, pw, ph, w, h);
38 let ms = t.elapsed().as_secs_f64() * 1e3;
39 eprintln!("{name}: 网络 {net_ms:.0} ms,后处理 {:.0} ms", ms - net_ms);
40 // 设了 DET_DUMP_PROB 就把概率图另存成 8 位 PGM
41 if std::env::var_os("DET_DUMP_PROB").is_some() {
42 let mut pgm = format!("P5\n{pw} {ph}\n255\n").into_bytes();
43 pgm.extend(prob.iter().map(|v| (v * 255.0).round() as u8));
44 std::fs::write(out_dir.join(format!("{name}.prob.pgm")), pgm).unwrap();
45 }
46 let mut f = std::fs::File::create(out_dir.join(format!("{name}.boxes.txt"))).unwrap();
47 for (q, s) in &boxes {
48 for (x, y) in q {
49 write!(f, "{x} {y} ").unwrap();
50 }
51 writeln!(f, "{s:.4}").unwrap();
52 }
53 eprintln!("{name}: {w}×{h},{} 个框,{ms:.0} ms", boxes.len());
54 }
55}Sourcepub fn prob_on<E: Exec>(&self, e: &E, x: &E::T) -> Result<E::T, String>
pub fn prob_on<E: Exec>(&self, e: &E, x: &E::T) -> Result<E::T, String>
网络部分:[3, H, W] → [1, H, W] 的概率图,在执行器上算。
Sourcepub fn detect(&self, page: &Image) -> Result<Vec<Quad>, String>
pub fn detect(&self, page: &Image) -> Result<Vec<Quad>, String>
检测整页图里的文字行,返回各行的四边形(原图像素坐标),从上到下、从左到右排好。
Sourcepub fn detect_scored(&self, page: &Image) -> Result<Vec<(Quad, f32)>, String>
pub fn detect_scored(&self, page: &Image) -> Result<Vec<(Quad, f32)>, String>
同 Det::detect,并给出每个框的平均概率。
Sourcepub fn boxes_from_prob(
&self,
prob: &[f32],
w: usize,
h: usize,
page_w: usize,
page_h: usize,
) -> Vec<(Quad, f32)>
pub fn boxes_from_prob( &self, prob: &[f32], w: usize, h: usize, page_w: usize, page_h: usize, ) -> Vec<(Quad, f32)>
只做后处理:w × h 的概率图 → 原图(page_w × page_h)坐标下排好序的框和分数。
Examples found in repository?
examples/det_check.rs (line 37)
9fn main() {
10 let a: Vec<String> = std::env::args().skip(1).collect();
11 if a.len() < 5 || !(a.len() - 2).is_multiple_of(3) {
12 eprintln!("用法:det_check <模型目录> <输出目录> <裸图> <宽> <高> ...");
13 std::process::exit(2);
14 }
15 let t = Instant::now();
16 let det = pagesift_ocr::det::Det::load(std::path::Path::new(&a[0])).unwrap();
17 eprintln!("载入 {:.0} ms", t.elapsed().as_secs_f64() * 1e3);
18 let out_dir = std::path::Path::new(&a[1]);
19 for c in a[2..].chunks(3) {
20 let data = std::fs::read(&c[0]).unwrap();
21 let (w, h): (usize, usize) = (c[1].parse().unwrap(), c[2].parse().unwrap());
22 let channels = data.len() / (w * h);
23 assert!(channels == 1 || channels == 3, "文件大小与宽高不符");
24 let img = pagesift_ocr::Image {
25 width: w,
26 height: h,
27 channels,
28 data,
29 };
30 let name = std::path::Path::new(&c[0])
31 .file_name()
32 .unwrap()
33 .to_string_lossy();
34 let t = Instant::now();
35 let (prob, pw, ph) = det.prob_map(&img).unwrap();
36 let net_ms = t.elapsed().as_secs_f64() * 1e3;
37 let boxes = det.boxes_from_prob(&prob, pw, ph, w, h);
38 let ms = t.elapsed().as_secs_f64() * 1e3;
39 eprintln!("{name}: 网络 {net_ms:.0} ms,后处理 {:.0} ms", ms - net_ms);
40 // 设了 DET_DUMP_PROB 就把概率图另存成 8 位 PGM
41 if std::env::var_os("DET_DUMP_PROB").is_some() {
42 let mut pgm = format!("P5\n{pw} {ph}\n255\n").into_bytes();
43 pgm.extend(prob.iter().map(|v| (v * 255.0).round() as u8));
44 std::fs::write(out_dir.join(format!("{name}.prob.pgm")), pgm).unwrap();
45 }
46 let mut f = std::fs::File::create(out_dir.join(format!("{name}.boxes.txt"))).unwrap();
47 for (q, s) in &boxes {
48 for (x, y) in q {
49 write!(f, "{x} {y} ").unwrap();
50 }
51 writeln!(f, "{s:.4}").unwrap();
52 }
53 eprintln!("{name}: {w}×{h},{} 个框,{ms:.0} ms", boxes.len());
54 }
55}Auto Trait Implementations§
impl Forget for Det
impl Freeze for Det
impl RefUnwindSafe for Det
impl Send for Det
impl Sync for Det
impl Unpin for Det
impl UnsafeUnpin for Det
impl UnwindSafe for Det
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more