yscv-cli 0.1.7

CLI for inference, benchmarking, and evaluation
Documentation
use yscv_detect::BoundingBox;
use yscv_recognize::Recognizer;
use yscv_tensor::Tensor;
use yscv_video::{
    CameraConfig, CameraFrameSource, Frame, FrameSource, InMemoryFrameSource, resolve_camera_device,
};

use crate::config::{CliConfig, DetectTarget};
use crate::error::AppError;
use crate::util::embedding_from_bbox;

pub fn open_camera_source(cli: &CliConfig) -> Result<CameraFrameSource, AppError> {
    let device_index = if let Some(query) = cli.device_name_query.as_deref() {
        let selected = resolve_camera_device(query)?;
        println!(
            "camera device resolved: query=`{}` -> {}: {}",
            query, selected.index, selected.label
        );
        selected.index
    } else {
        cli.device_index
    };

    let source = CameraFrameSource::open(CameraConfig {
        device_index,
        width: cli.width,
        height: cli.height,
        fps: cli.fps,
    })?;
    Ok(source)
}

pub fn build_source(
    cli: &CliConfig,
    recognizer: &mut Recognizer,
) -> Result<Box<dyn FrameSource>, AppError> {
    if cli.camera {
        let source = open_camera_source(cli)?;
        return Ok(Box::new(source));
    }

    let frame_height = 6usize;
    let frame_width = 6usize;
    let frames = match cli.detect_target {
        DetectTarget::People => vec![
            frame_with_boxes(0, 0, frame_height, frame_width, &[(1, 1, 3, 3, 0.9)])?,
            frame_with_boxes(1, 33_333, frame_height, frame_width, &[(1, 2, 3, 4, 0.85)])?,
            frame_with_boxes(
                2,
                66_666,
                frame_height,
                frame_width,
                &[(1, 3, 3, 5, 0.9), (4, 0, 6, 2, 0.88)],
            )?,
        ],
        DetectTarget::Faces => vec![
            frame_with_rgb_boxes(
                0,
                0,
                frame_height,
                frame_width,
                &[(1, 1, 3, 3, [0.78, 0.60, 0.46])],
                [0.10, 0.10, 0.12],
            )?,
            frame_with_rgb_boxes(
                1,
                33_333,
                frame_height,
                frame_width,
                &[(1, 2, 3, 4, [0.79, 0.61, 0.47])],
                [0.10, 0.10, 0.12],
            )?,
            frame_with_rgb_boxes(
                2,
                66_666,
                frame_height,
                frame_width,
                &[
                    (1, 3, 3, 5, [0.78, 0.60, 0.46]),
                    (4, 0, 6, 2, [0.72, 0.55, 0.41]),
                ],
                [0.10, 0.10, 0.12],
            )?,
        ],
    };

    if recognizer.identities().is_empty() {
        let known_embedding = embedding_from_bbox(
            BoundingBox {
                x1: 1.0,
                y1: 1.0,
                x2: 3.0,
                y2: 3.0,
            },
            frame_width as f32,
            frame_height as f32,
        )?;
        recognizer.enroll("alice", known_embedding)?;
    }

    Ok(Box::new(InMemoryFrameSource::new(frames)))
}

fn frame_with_boxes(
    index: u64,
    ts_us: u64,
    height: usize,
    width: usize,
    boxes: &[(usize, usize, usize, usize, f32)],
) -> Result<Frame, AppError> {
    let mut data = vec![0.0f32; height * width];
    for (x1, y1, x2, y2, value) in boxes {
        for y in *y1..*y2 {
            for x in *x1..*x2 {
                data[y * width + x] = *value;
            }
        }
    }
    Ok(Frame::new(
        index,
        ts_us,
        Tensor::from_vec(vec![height, width, 1], data)?,
    )?)
}

fn frame_with_rgb_boxes(
    index: u64,
    ts_us: u64,
    height: usize,
    width: usize,
    boxes: &[(usize, usize, usize, usize, [f32; 3])],
    background_rgb: [f32; 3],
) -> Result<Frame, AppError> {
    let mut data = vec![0.0f32; height * width * 3];
    for y in 0..height {
        for x in 0..width {
            let base = (y * width + x) * 3;
            data[base] = background_rgb[0];
            data[base + 1] = background_rgb[1];
            data[base + 2] = background_rgb[2];
        }
    }

    for (x1, y1, x2, y2, rgb) in boxes {
        for y in *y1..*y2 {
            for x in *x1..*x2 {
                let base = (y * width + x) * 3;
                data[base] = rgb[0];
                data[base + 1] = rgb[1];
                data[base + 2] = rgb[2];
            }
        }
    }

    Ok(Frame::new(
        index,
        ts_us,
        Tensor::from_vec(vec![height, width, 3], data)?,
    )?)
}