Merge branch 'master' of ssh://git.spruett.net:2282/scott/supper

This commit is contained in:
Scott Pruett 2022-06-02 19:41:27 -04:00
commit d3dfa83f32
4 changed files with 110 additions and 0 deletions

109
src/local_ocr.rs Normal file
View File

@ -0,0 +1,109 @@
use image::{RgbImage, DynamicImage, Rgb};
use img_hash::{image::GenericImageView, ImageHash};
use crate::image_processing;
#[derive(Debug)]
struct BoundingBox {
x: u32,
y: u32,
width: u32,
height: u32
}
fn column_has_any_dark(image: &RgbImage, x: u32) -> bool {
for y in 0..image.height() {
let [r, g, b] = image.get_pixel(x, y).0;
if r < 100 && g < 100 && b < 100 {
return true;
}
}
false
}
fn row_has_any_dark(image: &RgbImage, y: u32, start_x: u32, width: u32) -> bool {
for x in start_x..(start_x + width) {
let [r, g, b] = image.get_pixel(x, y).0;
if r < 100 && g < 100 && b < 100 {
return true
}
}
false
}
fn take_while<F: Fn(u32) -> bool>(image: &RgbImage, x: &mut u32, max: u32, f: F) {
while *x < max && f(*x) {
*x = *x + 1;
}
}
fn get_character_bounding_boxes(image: &RgbImage) -> Vec<BoundingBox> {
let mut x = 0;
let mut boxes = Vec::new();
while x < image.width() {
take_while(image, &mut x, image.width(), |x| !column_has_any_dark(image, x));
let start_x = x;
take_while(image, &mut x, image.width(), |x| column_has_any_dark(image, x));
let width = x - start_x;
if width > 2 {
let mut y = 0;
take_while(image, &mut y, image.height(), |y| !row_has_any_dark(image, y, start_x, width));
let start_y = y;
let mut inverse_y = 1;
take_while(image, &mut inverse_y, image.height(), |y| !row_has_any_dark(image, image.height() - y, start_x, width));
let end_y = image.height() - inverse_y - 1;
boxes.push(BoundingBox{
x,
y: start_y,
width,
height: end_y - start_y,
});
}
}
boxes
}
fn trim_to_bounding_box(image: &RgbImage, bounding_box: &BoundingBox) -> RgbImage {
let mut buffer = RgbImage::new(bounding_box.width, bounding_box.height);
for y in 0..bounding_box.height {
for x in 0..bounding_box.width {
buffer.put_pixel(x, y, *image.get_pixel(bounding_box.x + x, bounding_box.y + y));
}
}
buffer
}
fn compute_box_hashes(image: &RgbImage) -> Vec<String> {
let mut hashes = Vec::new();
let boxes = get_character_bounding_boxes(image);
for bounding_box in boxes {
let trimmed = trim_to_bounding_box(image, &bounding_box);
hashes.push(image_processing::hash_image(&trimmed))
}
hashes
}
#[test]
fn test_bounding_boxes() {
let image_bytes = include_bytes!("test_data/test-image-2.png");
let image = image::load_from_memory(image_bytes).unwrap().to_rgb8();
let boxes = get_character_bounding_boxes(&image);
assert_eq!(boxes.len(), 10);
assert_ne!(boxes[0].x, 0);
assert_ne!(boxes[0].y, 0);
assert_ne!(boxes[0].height, 0);
assert_ne!(boxes[0].width, 0);
}
#[test]
fn test_box_hashes() {
let image_bytes = include_bytes!("test_data/test-image-2.png");
let image = image::load_from_memory(image_bytes).unwrap().to_rgb8();
let hashes = compute_box_hashes(&image);
assert_eq!(hashes.len(), 10);
}

View File

@ -7,6 +7,7 @@ mod image_processing;
mod ocr;
mod state;
mod stats_writer;
mod local_ocr;
use std::{
collections::HashMap,

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB