Skip to content

Commit

Permalink
Tweak boundary box sizes, add more info to webpage and fix logging (#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
xnorpx authored Jan 4, 2025
1 parent bc8148a commit eede306
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 41 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

<div style="display: flex; justify-content: space-between;">
<img src="assets/logo_medium.png" alt="blue_onyx" style="width:30%;" />
<img src="assets/demo.jpg" alt="blue_onyx" style="width:60%;" />
<div style="display: flex; justify-content: space-between; align-items: flex-start; width: 100%;">
<img src="assets/logo_medium.png" alt="blue_onyx" style="height: 200px;" />
<img src="assets/demo.jpg" alt="blue_onyx" style="height: 200px;" />
</div>


# Object Detection Service

Object detection service written in Rust with Onnx inference engine.
Expand Down
4 changes: 2 additions & 2 deletions src/bin/blue_onyx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion src/bin/blue_onyx_benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion src/bin/blue_onyx_download_models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
6 changes: 4 additions & 2 deletions src/bin/blue_onyx_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ mod blue_onyx_service {

pub fn my_service_main(service_name: Vec<OsString>) {
let arguments: Vec<OsString> = 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!(
"{}\\{}",
Expand All @@ -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) {
Expand Down
44 changes: 34 additions & 10 deletions src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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<DynamicImage> {
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,
Expand All @@ -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!(
Expand All @@ -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,
Expand Down Expand Up @@ -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(
Expand Down
42 changes: 32 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -118,23 +123,40 @@ pub fn direct_ml_available() -> bool {

pub fn init_logging(
log_level: LogLevel,
log_path: Option<PathBuf>,
log_path: &mut Option<PathBuf>,
) -> Option<tracing_appender::non_blocking::WorkerGuard> {
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))
Expand Down
25 changes: 22 additions & 3 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use reqwest;
use serde::Deserialize;
use std::{
net::{Ipv4Addr, SocketAddr},
path::PathBuf,
sync::Arc,
time::Instant,
};
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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<Arc<ServerState>>) -> 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(),
Expand Down Expand Up @@ -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,
Expand All @@ -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<PathBuf>,
) -> 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,
Expand Down
11 changes: 3 additions & 8 deletions templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,7 @@
<meta charset="UTF-8">
<title>{% block title %}Blue Onyx{% endblock %}</title>
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<!-- Font Awesome CDN for Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
integrity="sha512-pIVD4rryZb+7ATbL9dwJhKfeJnV9L9zdjVc7axUjxQbMvR5ZYH3Ns1tklXq0uwxVzX33X7lXWbIjPsrZZIbj2w=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- Google Fonts - Montserrat -->
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/static/css/bootstrap-icons.css" />
<style>
/* CSS Variables for Consistency */
:root {
Expand All @@ -35,7 +30,7 @@

/* Global Styles */
body {
font-family: 'Montserrat', sans-serif;
font-family: 'Futura', 'Helvetica', sans-serif;
background-color: var(--background-color);
color: var(--text-color);
margin: 0;
Expand Down Expand Up @@ -299,7 +294,7 @@
</div>

<div class="footer">
&copy; 2024 Blue Onyx. All rights reserved.
Thank you for using Blue Onyx.
</div>
</body>

Expand Down
7 changes: 7 additions & 0 deletions templates/welcome.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@

<h1>Welcome to Blue Onyx</h1>
<p>Object Detection</p>
<p>Version: {{ metrics.version }}</p>
<p>Uptime: {{ metrics.uptime() }}</p>
<p>Requests: {{ metrics.number_of_requests }}</p>
<p>Model: {{ metrics.model_name }}</p>
<p>Device: {{ metrics.device_name }}</p>
<p>Onnx Execution Provider: {{ metrics.execution_provider_name }}</p>
<p>Log path: {{ metrics.log_path }}</p>
{% endblock %}

{% block links %}
Expand Down

0 comments on commit eede306

Please sign in to comment.