Skip to main content

Det

Struct Det 

Source
pub struct Det {
    pub params: DbParams,
    /* private fields */
}
Expand description

载入好的检测模型。

Fields§

§params: DbParams

DB 后处理参数;缺省同参考实现,可按需调整。

Implementations§

Source§

impl Det

Source

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}
Source

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}
Source

pub fn preprocess(&self, page: &Image) -> Result<Tensor, String>

预处理整页图成网络输入 [3, H, W]。

Source

pub fn prob_on<E: Exec>(&self, e: &E, x: &E::T) -> Result<E::T, String>

网络部分:[3, H, W] → [1, H, W] 的概率图,在执行器上算。

Source

pub fn detect(&self, page: &Image) -> Result<Vec<Quad>, String>

检测整页图里的文字行,返回各行的四边形(原图像素坐标),从上到下、从左到右排好。

Source

pub fn detect_scored(&self, page: &Image) -> Result<Vec<(Quad, f32)>, String>

同 Det::detect,并给出每个框的平均概率。

Source

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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.