Skip to content

Commit

Permalink
Cleanup code
Browse files Browse the repository at this point in the history
  • Loading branch information
sgasse committed Sep 14, 2024
1 parent 4db2b6b commit b19d04b
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 52 deletions.
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Client/server face detection from your webcam with [`tokio`][tokio],

![Concurrent inference](./resources/Concurrent_Inference_Example.png)

In the example image above, we use two laptops. Both run a `cam_sender` client
In the example image above, we use two laptops. Both run a `socket_sender` client
and send image streams to the second laptop, which runs the inference for
face detection on both of those streams concurrently with the `infer_server`. We
access both streams from the first laptop. This show-cases a few features:
Expand All @@ -17,6 +17,18 @@ access both streams from the first laptop. This show-cases a few features:
streams while a performant server does the inference)
- Access to the streams over the network

Run with:

```sh
# server
RUST_LOG=debug cargo run --release --bin infer_server

# client
RUST_LOG=debug cargo run --release --bin socket_sender
```

Then check e.g. http://127.0.0.1:3000/face_stream?name=simon

## Overview

This is my second implementation of this project. Changes to the first version:
Expand All @@ -31,11 +43,8 @@ This is my second implementation of this project. Changes to the first version:
streams and serves endpoints of both the raw streams and streams with faces
infered. The previous version used [`actix-web`][actix-web] as web framework,
switching to [`axum`][axum] was mostly curiosity.
- `socket_sender` establishes a TCP connection to the `infer_sender` and streams
- `socket_sender` establishes a TCP connection to the `infer_server` and streams
frames to it which can be shown raw or infered in the browser.
- `multipart_sender` allows us to send a stream as multipart form data via HTTP
to the `infer_server`. It does not yield a good performance in practice and is
only left in here for reference purposes.
- In the first version, opening a tab to either the raw or infered stream
endpoint triggered an independent run of the capture function. So opening four
tabs meant having four streams capture independently. In the refactored
Expand Down
2 changes: 0 additions & 2 deletions cam_sender/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ name = "cam_sender"
version = "0.3.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "1.0.75"
bincode = "1.3.3"
Expand Down
1 change: 0 additions & 1 deletion cam_sender/src/sensors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ pub fn get_max_res_mjpg_capture_fn() -> Result<CameraWrapper<Camera>> {
..Default::default()
})?;

// Ok(Box::new(move || cam.capture().ok()))
Ok(CameraWrapper { inner: cam })
}

Expand Down
2 changes: 0 additions & 2 deletions common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ name = "common"
version = "0.3.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bincode = "1.3.3"
serde = { version = "1.0.145", features = ["derive"] }
8 changes: 0 additions & 8 deletions infer_server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@ name = "infer_server"
version = "0.3.2"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "infer_server"
path = "src/lib.rs"

[dependencies]
anyhow = "1.0.75"
async-stream = "0.3.3"
Expand Down Expand Up @@ -37,6 +32,3 @@ tokio-stream = { version = "0.1.14", features = ["sync"] }
tokio-util = { version = "0.7.4", features = ["net", "codec"] }
tract-onnx = "0.19.2"
turbojpeg = { version = "0.5.2", features = ["image"] }

[profile.release]
debug = true
4 changes: 2 additions & 2 deletions infer_server/src/bin/infer_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ use infer_server::{
#[derive(Parser, Debug)]
#[clap(author, version)]
struct Args {
/// Address of the infer server to connect to
/// Address of the HTTP server
#[clap(long, default_value = "127.0.0.1:3000")]
server_address: String,

/// Address of the infer server to connect to
/// Address of the data socket
#[clap(long, default_value = "127.0.0.1:3001")]
socket_address: String,
}
Expand Down
2 changes: 1 addition & 1 deletion infer_server/src/inferer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl Inferer {
let width = recv_ref.0;
let height = recv_ref.1;

let image: RgbImage = turbojpeg::decompress_image(&recv_ref.2.as_slice())
let image: RgbImage = turbojpeg::decompress_image(recv_ref.2.as_slice())
.expect("failed to decompress");
if let Ok(bboxes_with_confidences) = self.infer_faces(&image) {
let frame = draw_bboxes_on_image(image, bboxes_with_confidences, width, height);
Expand Down
2 changes: 1 addition & 1 deletion infer_server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fn as_jpeg_stream_item(data: &[u8]) -> Bytes {
Bytes::copy_from_slice(
&[
"--frame\r\nContent-Type: image/jpeg\r\n\r\n".as_bytes(),
&data[..],
data,
"\r\n\r\n".as_bytes(),
]
.concat(),
Expand Down
1 change: 1 addition & 0 deletions infer_server/src/meter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use tokio::{task::JoinHandle, time::interval};

pub static METER: Meter = Meter::new();

#[derive(Default)]
pub struct Meter {
raw_frames: AtomicU64,
infered_frames: AtomicU64,
Expand Down
60 changes: 30 additions & 30 deletions infer_server/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,37 @@ use std::path::Path;

use infer_server::nn::{InferModel, UltrafaceModel};

// #[tokio::test]
// async fn test_ultraface_640() -> Result<(), Box<dyn std::error::Error>> {
// let current_workdir = std::env::current_dir()?;
// println!("Running with workdir {}", current_workdir.display());
// let model = UltrafaceModel::new(infer_server::nn::UltrafaceVariant::W640H480, 0.5, 0.5).await?;
#[tokio::test]
async fn test_ultraface_640() -> Result<(), Box<dyn std::error::Error>> {
let current_workdir = std::env::current_dir()?;
println!("Running with workdir {}", current_workdir.display());
let model = UltrafaceModel::new(infer_server::nn::UltrafaceVariant::W640H480, 0.5, 0.5).await?;

// // `cargo test` and debugging the test via IDE have differing work dirs
// let test_pic_dir = {
// let base_dir = "resources/test_pics";
// match Path::new(base_dir).is_dir() {
// true => base_dir.to_owned(),
// false => format!("../{}", base_dir),
// }
// };
// `cargo test` and debugging the test via IDE have differing work dirs
let test_pic_dir = {
let base_dir = "resources/test_pics";
match Path::new(base_dir).is_dir() {
true => base_dir.to_owned(),
false => format!("../{}", base_dir),
}
};

// let images_with_num_faces = vec![
// ("bruce-mars-ZXq7xoo98b0-unsplash.jpg", 3),
// ("clarke-sanders-ybPJ47PMT_M-unsplash.jpg", 6),
// ("helena-lopes-e3OUQGT9bWU-unsplash.jpg", 4),
// ("kaleidico-d6rTXEtOclk-unsplash.jpg", 3),
// ("michael-dam-mEZ3PoFGs_k-unsplash.jpg", 1),
// ("mika-W0i1N6FdCWA-unsplash.jpg", 1),
// ("omar-lopez-T6zu4jFhVwg-unsplash.jpg", 10),
// ("ken-cheung-KonWFWUaAuk-unsplash.jpg", 0),
// ];
// for (filename, expected_num_faces) in images_with_num_faces {
// let image = image::open(Path::new(&test_pic_dir).join(Path::new(filename)))?.to_rgb8();
// let bboxes_with_confidences = model.run(image)?;
let images_with_num_faces = vec![
("bruce-mars-ZXq7xoo98b0-unsplash.jpg", 3),
("clarke-sanders-ybPJ47PMT_M-unsplash.jpg", 6),
("helena-lopes-e3OUQGT9bWU-unsplash.jpg", 4),
("kaleidico-d6rTXEtOclk-unsplash.jpg", 3),
("michael-dam-mEZ3PoFGs_k-unsplash.jpg", 1),
("mika-W0i1N6FdCWA-unsplash.jpg", 1),
("omar-lopez-T6zu4jFhVwg-unsplash.jpg", 10),
("ken-cheung-KonWFWUaAuk-unsplash.jpg", 0),
];
for (filename, expected_num_faces) in images_with_num_faces {
let image = image::open(Path::new(&test_pic_dir).join(Path::new(filename)))?.to_rgb8();
let bboxes_with_confidences = model.run(&image)?;

// assert_eq!(bboxes_with_confidences.len(), expected_num_faces);
// }
assert_eq!(bboxes_with_confidences.len(), expected_num_faces);
}

// Ok(())
// }
Ok(())
}

0 comments on commit b19d04b

Please sign in to comment.