Fix image facade to safely compile

This commit is contained in:
Blizzard Finnegan 2023-05-24 14:52:45 -04:00
parent d62de8524c
commit a5204b865b
Signed by: blizzardfinnegan
GPG key ID: 61C1E13067E0018E
4 changed files with 212 additions and 46 deletions

92
Cargo.lock generated
View file

@ -22,6 +22,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "async-channel"
version = "1.8.0"
@ -234,6 +243,21 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b"
dependencies = [
"iana-time-zone",
"js-sys",
"num-integer",
"num-traits",
"time",
"wasm-bindgen",
"winapi",
]
[[package]]
name = "clang"
version = "2.0.0"
@ -283,6 +307,12 @@ dependencies = [
"yaml-rust",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "cpufeatures"
version = "0.2.7"
@ -527,7 +557,7 @@ checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
dependencies = [
"cfg-if",
"libc",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
@ -563,6 +593,29 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "iana-time-zone"
version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "instant"
version = "0.1.12"
@ -731,6 +784,16 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
@ -961,6 +1024,7 @@ name = "rust_ocr"
version = "0.1.0"
dependencies = [
"async-std",
"chrono",
"config",
"derivative",
"fern",
@ -1136,6 +1200,17 @@ dependencies = [
"syn 2.0.16",
]
[[package]]
name = "time"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "toml"
version = "0.5.11"
@ -1191,6 +1266,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
@ -1306,6 +1387,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.48.0"

View file

@ -7,6 +7,7 @@ edition = "2021"
[dependencies]
async-std = "1.12.0"
chrono = "0.4.24"
config = "0.13.3"
derivative = "2.2.0"
fern = "0.6.2"

View file

@ -1,47 +1,53 @@
use std::sync::Arc;
use std::{sync::Mutex, thread, collections::VecDeque};
use config::*;
#[allow(unused_imports)]
use opencv::imgcodecs::{IMWRITE_PNG_BILEVEL, IMREAD_UNCHANGED};
use opencv::{videoio::{VideoCapture, VideoCaptureTrait, CAP_PROP_FOURCC,
CAP_ANY, VideoWriter, CAP_PROP_FRAME_WIDTH,
CAP_PROP_FRAME_HEIGHT},
imgproc::{THRESH_BINARY, COLOR_BGR2GRAY,threshold,cvt_color},
core::{bitwise_and,Mat},
core::{bitwise_and,Rect_,Mat,MatTraitConst,no_array,Vector},
highgui::{select_roi,imshow},
imgcodecs::{imread,imwrite,imdecode}};
#[allow(unused_imports)]
use leptess::{leptonica::{pix_read,Pix},
tesseract::TessApi};
imgcodecs::{imwrite,imread}};
use leptess::LepTess;
const FRAME_WIDTH:i32 = 800;
const FRAME_HEIGHT:i32 = 600;
const MJPG_FOURCC_CODE:i32 = VideoWriter::fourcc('m','j','p','g').unwrap();
const CROP_X:&str = "crop x";
const CROP_Y:&str = "crop y";
const CROP_WIDTH:&str = "crop width";
const CROP_HEIGHT:&str = "crop height";
const THRESHOLD:&str = "threshold value";
const COMPOSITE_FRAMES:u16 = 5;
pub struct Camera{
settings: Config,
camera: FrameGrabber,
name: String,
ocr: TessApi,
ocr: LepTess,
active: bool
}
struct FrameGrabber{
camera: VideoCapture,
image_queue: Mutex<VecDeque<Mat>>,
image_queue: Arc<Mutex<VecDeque<Mat>>>,
}
impl FrameGrabber{
fn new(camera:VideoCapture, composite_frames:i64) -> Self{
let mut output = Self{
camera,
image_queue: Mutex::new(VecDeque::with_capacity(composite_frames as usize))
fn new(mut camera:VideoCapture, composite_frames:u16) -> Self{
let output = Self{
image_queue: Arc::new(Mutex::new(VecDeque::with_capacity(composite_frames as usize)))
};
let image_queue = output.image_queue.clone();
thread::spawn(move||{
loop {
let mut image = Mat::default();
let result = output.camera.read(&mut image);
let result = &camera.read(&mut image);
match result{
Ok(true) => {
let mut image_queue = *output.image_queue.lock().unwrap();
let mut converted_image = Mat::default();
_ = cvt_color(&mut image, &mut converted_image, COLOR_BGR2GRAY, 0);
let mut image_queue = image_queue.lock().unwrap();
if image_queue.len() == image_queue.capacity(){
image_queue.pop_back();
}
@ -54,60 +60,130 @@ impl FrameGrabber{
return output;
}
fn grab(&self, mut image:&Mat){
let mut image_queue = *self.image_queue.lock().unwrap();
image = &mut image_queue.pop_front().unwrap();
fn grab(&self) -> Mat{
let mut image_queue = self.image_queue.lock().unwrap();
image_queue.pop_front().unwrap()
}
fn burst(&self) -> Vec<Mat>{
let mut image_queue = *self.image_queue.lock().unwrap();
let image_queue = self.image_queue.lock().unwrap();
return image_queue.clone().into();
}
fn change_composite_frames(&self, composite_frames:u16){
let mut image_queue = self.image_queue.lock().unwrap();
image_queue.resize(composite_frames as usize, Default::default());
}
}
impl Camera{
pub fn new(camera_name:String) -> Option<Self>{
let defaults = Config::builder();
defaults.set_default("crop x", 275);
defaults.set_default("crop y", 200);
defaults.set_default("crop width", 80);
defaults.set_default("crop height", 50);
defaults.set_default("threshold value", 50);
defaults.set_default("composite frames", 5);
defaults.set_default("active", true);
let mut defaults = Config::builder();
defaults = defaults.set_default(CROP_X, 275).unwrap();
defaults = defaults.set_default(CROP_Y, 200).unwrap();
defaults = defaults.set_default(CROP_WIDTH, 80).unwrap();
defaults = defaults.set_default(CROP_HEIGHT, 50).unwrap();
defaults = defaults.set_default(THRESHOLD, 50).unwrap();
let default = defaults.build().unwrap();
let settings = Config::builder().add_source(default).build().unwrap();
let mut camera = VideoCapture::from_file(&camera_name, CAP_ANY).unwrap();
camera.set(CAP_PROP_FOURCC, MJPG_FOURCC_CODE as f64);
camera.set(CAP_PROP_FRAME_WIDTH, FRAME_WIDTH as f64);
camera.set(CAP_PROP_FRAME_HEIGHT, FRAME_HEIGHT as f64);
if let result = camera.open_file(&camera_name, CAP_ANY){
match result {
Ok(_) => {},
Err(error) => return None
}
_ = camera.set(CAP_PROP_FOURCC, VideoWriter::fourcc('m','j','p','g').unwrap() as f64);
_ = camera.set(CAP_PROP_FRAME_WIDTH, FRAME_WIDTH as f64);
_ = camera.set(CAP_PROP_FRAME_HEIGHT, FRAME_HEIGHT as f64);
match camera.open_file(&camera_name, CAP_ANY) {
Ok(_) => {},
Err(_) => return None
};
let frame_grabber = FrameGrabber::new(camera, settings.get_int("composite frames").unwrap_or(1));
let frame_grabber = FrameGrabber::new(camera, COMPOSITE_FRAMES);
let name = camera_name.split('-').last().unwrap().to_string();
let ocr = TessApi::new(Some("tessdata"), "Pro6_temp_test").unwrap();
let ocr = LepTess::new(Some("tessdata"), "Pro6_temp_test").unwrap();
Some(Self{
settings,
camera: frame_grabber,
name,
ocr,
active: true,
})
}
fn take_picture(&mut self) -> Mat{
let mut image = Mat::default();
self.camera.grab(&mut image);
let mut output = Mat::default();
cvt_color(&mut image, &mut output, COLOR_BGR2GRAY, 0);
return output;
pub fn show_image(&self){
_ = imshow("Test image", &imread(&self.complete_process(),IMREAD_UNCHANGED).unwrap());
}
fn complete_process(&self) -> String{
let images = self.camera.burst();
let mut final_image = images[0].clone();
for mut image in images{
image = self.crop(image);
image = self.threshold(image);
_ = bitwise_and(&final_image.clone(), &image, &mut final_image, &no_array());
}
return self.save(final_image).unwrap_or("".to_string());
}
fn crop(&self,image:Mat) -> Mat{
let x = self.settings.get_int(&CROP_X).unwrap();
let y = self.settings.get_int(&CROP_Y).unwrap();
let width = self.settings.get_int(&CROP_WIDTH).unwrap();
let height = self.settings.get_int(&CROP_HEIGHT).unwrap();
let roi = Rect_::new(x as i32, y as i32, width as i32, height as i32);
return image.apply_1(roi).unwrap();
}
fn threshold(&self,image:Mat) -> Mat{
let mut output = image.clone();
let threshold_value = self.settings.get_int(&THRESHOLD).unwrap();
_ = threshold(&image,&mut output, threshold_value as f64, 255 as f64 ,THRESH_BINARY);
return Mat::default();
}
fn save(&self,image:Mat) -> Result<String,opencv::Error>{
let mut write_parameters:Vector<i32> = Vector::new();
write_parameters.push(IMWRITE_PNG_BILEVEL);
let mut filename:String = String::new();
filename.push_str(&chrono::Local::now().to_rfc3339().to_string());
filename.push_str(&self.name);
match imwrite(&filename, &image, &write_parameters){
Ok(_) => Ok(filename),
Err(error) => Err(error)
}
}
pub fn set_crop(&mut self) -> Result<(),opencv::Error>{
match select_roi(&self.camera.grab(), false, false){
Err(error) => { return Err(error); }
Ok(rect) => {
let mut new_settings = Config::builder().add_source(self.settings.clone());
new_settings = new_settings.set_override(CROP_X, rect.x).unwrap();
new_settings = new_settings.set_override(CROP_Y, rect.y).unwrap();
new_settings = new_settings.set_override(CROP_WIDTH, rect.width).unwrap();
new_settings = new_settings.set_override(CROP_HEIGHT, rect.height).unwrap();
self.settings = new_settings.build().unwrap();
Ok(())
}
}
}
pub fn set_threshold(&mut self, thresh:u16){
let new_settings = Config::builder().add_source(self.settings.clone()).set_override(THRESHOLD, thresh);
self.settings = new_settings.expect("Bad config settings!").build().unwrap();
}
pub fn set_composite_frames(&self, composite_frames:u16){
self.camera.change_composite_frames(composite_frames);
}
pub fn deactivate(&mut self){ self.active = false; }
pub fn activate(&mut self) { self.active = true; }
pub fn is_active(&self) -> bool { self.active }
pub fn parse_image(&mut self, file_location:String) -> f64{
_ = self.ocr.set_image(file_location);
return str::parse(&self.ocr.get_utf8_text().unwrap()).unwrap()
}
}

View file

@ -1,4 +1,3 @@
pub mod config_facade;
pub mod gpio_facade;
pub mod image_facade;
pub mod output_facade;