From eede3067e75851f5100f5097a1c8f8a02d781f54 Mon Sep 17 00:00:00 2001 From: Marcus Asteborg Date: Sat, 4 Jan 2025 13:10:42 -0800 Subject: [PATCH] Tweak boundary box sizes, add more info to webpage and fix logging (#81) --- README.md | 8 ++--- src/bin/blue_onyx.rs | 4 +-- src/bin/blue_onyx_benchmark.rs | 2 +- src/bin/blue_onyx_download_models.rs | 2 +- src/bin/blue_onyx_service.rs | 6 ++-- src/image.rs | 44 +++++++++++++++++++++------- src/lib.rs | 42 +++++++++++++++++++------- src/server.rs | 25 ++++++++++++++-- templates/base.html | 11 ++----- templates/welcome.html | 7 +++++ 10 files changed, 110 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index e4056d7..e6fa748 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ - -
- blue_onyx - blue_onyx +
+ blue_onyx + blue_onyx
+ # Object Detection Service Object detection service written in Rust with Onnx inference engine. diff --git a/src/bin/blue_onyx.rs b/src/bin/blue_onyx.rs index c67c428..754eb06 100644 --- a/src/bin/blue_onyx.rs +++ b/src/bin/blue_onyx.rs @@ -4,8 +4,8 @@ use tracing::info; fn main() -> anyhow::Result<()> { let parse = Cli::parse(); - let args = parse; - init_logging(args.log_level, args.log_path.clone()); + let mut args = parse; + let _guard = init_logging(args.log_level, &mut args.log_path); system_info()?; if args.download_model_path.is_some() { diff --git a/src/bin/blue_onyx_benchmark.rs b/src/bin/blue_onyx_benchmark.rs index bbdc10b..8c9743e 100644 --- a/src/bin/blue_onyx_benchmark.rs +++ b/src/bin/blue_onyx_benchmark.rs @@ -113,7 +113,7 @@ struct Cli { fn main() -> anyhow::Result<()> { let args = Cli::parse(); - init_logging(args.log_level, None); + let _guard = init_logging(args.log_level, &mut None); system_info()?; if args.download_model_path.is_some() { diff --git a/src/bin/blue_onyx_download_models.rs b/src/bin/blue_onyx_download_models.rs index a017099..0980aed 100644 --- a/src/bin/blue_onyx_download_models.rs +++ b/src/bin/blue_onyx_download_models.rs @@ -14,7 +14,7 @@ fn main() { return; } - init_logging(blue_onyx::LogLevel::Info, None); + init_logging(blue_onyx::LogLevel::Info, &mut None); let download_model_path: PathBuf = if args.len() > 1 && args[1] != "custom-model" { PathBuf::from(&args[1]) diff --git a/src/bin/blue_onyx_service.rs b/src/bin/blue_onyx_service.rs index 4a6d636..bc4775e 100644 --- a/src/bin/blue_onyx_service.rs +++ b/src/bin/blue_onyx_service.rs @@ -54,7 +54,7 @@ mod blue_onyx_service { pub fn my_service_main(service_name: Vec) { let arguments: Vec = env::args_os().collect(); - let args = Cli::try_parse_from(arguments.clone()).unwrap(); + let mut args = Cli::try_parse_from(arguments.clone()).unwrap(); let default_log_path = std::path::PathBuf::from(format!( "{}\\{}", @@ -67,8 +67,10 @@ mod blue_onyx_service { .clone() .unwrap_or_else(|| default_log_path.clone()); + args.log_path = Some(log_path.clone()); + println!("Logs will be written to log path: {}", log_path.display()); - let _guard = init_logging(args.log_level, Some("c:\\git\\".into())); + let _guard = init_logging(args.log_level, &mut args.log_path); info!("Starting blue onyx service with args: {:#?}", arguments); let (blue_onyx_service, cancellation_token, thread_handle) = match blue_onyx_service(args) { diff --git a/src/image.rs b/src/image.rs index 9c4b7b1..79a1ab4 100644 --- a/src/image.rs +++ b/src/image.rs @@ -81,7 +81,7 @@ pub fn encode_maybe_draw_boundary_boxes_and_save_jpeg( ) -> anyhow::Result<()> { let encode_image_start_time = Instant::now(); - let image = create_dynamic_image_maybe_with_boundary_box(predictions, image, 20)?; + let image = create_dynamic_image_maybe_with_boundary_box(predictions, image)?; let encoder = Encoder::new_file(jpeg_file, 100)?; encoder.encode( @@ -140,8 +140,9 @@ pub fn create_od_image_name(image_name: &str, strip_path: bool) -> anyhow::Resul pub fn create_dynamic_image_maybe_with_boundary_box( predictions: Option<&[Prediction]>, decoded_image: &Image, - legend_size: u32, ) -> anyhow::Result { + let (thickness, legend_size) = + boundary_box_config(decoded_image.width as u32, decoded_image.height as u32); let mut img = ImageBuffer::from_vec( decoded_image.width as u32, decoded_image.height as u32, @@ -161,18 +162,25 @@ pub fn create_dynamic_image_maybe_with_boundary_box( let dy = prediction.y_max - prediction.y_min; if dx > 0 && dy > 0 { - imageproc::drawing::draw_hollow_rect_mut( - &mut img, - imageproc::rect::Rect::at(prediction.x_min as i32, prediction.y_min as i32) - .of_size(dx as u32, dy as u32), - image::Rgb([255, 0, 0]), - ); + for t in 0..thickness { + let x_min = prediction.x_min + t; + let y_min = prediction.y_min + t; + let rect_width = dx - 2 * t; + let rect_height = dy - 2 * t; + + imageproc::drawing::draw_hollow_rect_mut( + &mut img, + imageproc::rect::Rect::at(x_min as i32, y_min as i32) + .of_size(rect_width as u32, rect_height as u32), + image::Rgb([255, 0, 0]), + ); + } } if let Some(font) = font.as_ref() { imageproc::drawing::draw_filled_rect_mut( &mut img, imageproc::rect::Rect::at(prediction.x_min as i32, prediction.y_min as i32) - .of_size(dx as u32, legend_size), + .of_size(dx as u32, legend_size as u32), image::Rgb([170, 0, 0]), ); let legend = format!( @@ -195,6 +203,22 @@ pub fn create_dynamic_image_maybe_with_boundary_box( Ok(DynamicImage::ImageRgb8(img)) } +fn boundary_box_config(width: u32, height: u32) -> (usize, u64) { + let base_width = 640.0; + let base_height = 480.0; + let base_thickness = 1.0; + let base_fontsize = 20.0; + + let scale_width = width as f32 / base_width; + let scale_height = height as f32 / base_height; + let scale = scale_width.max(scale_height).max(1.0); + + let thickness = (base_thickness * scale).ceil() as usize; + let fontsize = (base_fontsize + (scale.ceil() * 3.)) as u64; + + (thickness.max(1), fontsize) +} + pub struct Resizer { resizer: fast_image_resize::Resizer, target_width: usize, @@ -267,7 +291,7 @@ pub fn draw_boundary_boxes_on_encoded_image( let mut image = Image::default(); decode_jpeg(None, data, &mut image)?; let dynamic_image_with_boundary_box = - create_dynamic_image_maybe_with_boundary_box(Some(predictions), &image, 20)?; + create_dynamic_image_maybe_with_boundary_box(Some(predictions), &image)?; let mut encoded_image = Vec::new(); let encoder = Encoder::new(&mut encoded_image, 100); encoder.encode( diff --git a/src/lib.rs b/src/lib.rs index d81c323..5712aa1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,7 +63,12 @@ pub fn blue_onyx_service( } else { system_info::cpu_model() }; - let metrics = server::Metrics::new(model_name.clone(), device_name, execution_providers_name); + let metrics = server::Metrics::new( + model_name.clone(), + device_name, + execution_providers_name, + args.log_path, + ); let cancel_token = CancellationToken::new(); let server_future = run_server(args.port, cancel_token.clone(), sender, metrics); @@ -118,23 +123,40 @@ pub fn direct_ml_available() -> bool { pub fn init_logging( log_level: LogLevel, - log_path: Option, + log_path: &mut Option, ) -> Option { setup_ansi_support(); - if let Some(log_path) = log_path { - println!( - "Starting Blue Onyx, logging into: {}/blue_onyx.log", - log_path.display() - ); - let file_appender = tracing_appender::rolling::daily(&log_path, "blue_onyx.log"); - let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender); + let guard = log_path.clone().map(|path| { + let log_directory = if path.starts_with(".") { + let stripped = path.strip_prefix(".").unwrap_or(&path).to_path_buf(); + std::env::current_exe() + .ok() + .and_then(|exe| exe.parent().map(|p| p.join(stripped.clone()))) + .unwrap_or(stripped) + } else { + path + }; + + *log_path = Some(log_directory.clone()); + + let log_file = log_directory.join("blue_onyx.log"); + println!("Starting Blue Onyx, logging into: {}", log_file.display()); + + let file_appender = tracing_appender::rolling::daily(&log_directory, "blue_onyx.log"); + let (non_blocking, guard) = tracing_appender::non_blocking(file_appender); + tracing_subscriber::fmt() .with_writer(non_blocking) .with_max_level(Level::from(log_level)) .with_ansi(false) .init(); - Some(_guard) + + guard + }); + + if guard.is_some() { + guard } else { tracing_subscriber::fmt() .with_max_level(Level::from(log_level)) diff --git a/src/server.rs b/src/server.rs index b9a1732..e745811 100644 --- a/src/server.rs +++ b/src/server.rs @@ -23,6 +23,7 @@ use reqwest; use serde::Deserialize; use std::{ net::{Ipv4Addr, SocketAddr}, + path::PathBuf, sync::Arc, time::Instant, }; @@ -62,6 +63,7 @@ pub async fn run_server( let blue_onyx = Router::new() .route("/", get(welcome_handler)) + .with_state(server_state.clone()) .route( "/v1/status/updateavailable", get(v1_status_update_available), @@ -102,14 +104,19 @@ pub async fn run_server( #[template(path = "welcome.html")] struct WelcomeTemplate { logo_data: String, + metrics: Metrics, } -async fn welcome_handler() -> impl IntoResponse { +async fn welcome_handler(State(server_state): State>) -> impl IntoResponse { const LOGO: &[u8] = include_bytes!("../assets/logo_large.png"); let encoded_logo = general_purpose::STANDARD.encode(LOGO); let logo_data = format!("data:image/png;base64,{}", encoded_logo); + let metrics = { + let metrics_guard = server_state.metrics.lock().await; + metrics_guard.clone() + }; - let template = WelcomeTemplate { logo_data }; + let template = WelcomeTemplate { logo_data, metrics }; ( [(CACHE_CONTROL, "no-store, no-cache, must-revalidate")], template.into_response(), @@ -287,6 +294,8 @@ pub async fn get_latest_release_info() -> anyhow::Result<(String, String)> { #[derive(Debug, Clone)] pub struct Metrics { + version: String, + log_path: String, start_time: Instant, model_name: String, device_name: String, @@ -305,8 +314,18 @@ pub struct Metrics { } impl Metrics { - pub fn new(model_name: String, device_name: String, execution_provider: String) -> Self { + pub fn new( + model_name: String, + device_name: String, + execution_provider: String, + log_path: Option, + ) -> Self { Self { + version: env!("CARGO_PKG_VERSION").to_string(), + log_path: log_path + .unwrap_or_else(|| PathBuf::from("stdout")) + .to_string_lossy() + .to_string(), start_time: Instant::now(), model_name, device_name, diff --git a/templates/base.html b/templates/base.html index 743a94e..f38d96b 100644 --- a/templates/base.html +++ b/templates/base.html @@ -5,12 +5,7 @@ {% block title %}Blue Onyx{% endblock %} - - - - +