use crate::pipeline::Frame;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BoundingBox {
pub x: u32,
pub y: u32,
pub w: u32,
pub h: u32,
}
impl BoundingBox {
pub fn new(x: u32, y: u32, w: u32, h: u32) -> Self {
Self { x, y, w, h }
}
pub fn right(&self) -> u32 {
self.x + self.w
}
pub fn bottom(&self) -> u32 {
self.y + self.h
}
pub fn area(&self) -> u32 {
self.w * self.h
}
}
pub struct DepthFrame {
frame: Frame,
width: u32,
height: u32,
}
const MIN_VALID_MM: u16 = 100;
const MAX_VALID_MM: u16 = 8000;
const MIN_BOX_PIXELS: usize = 16;
impl DepthFrame {
pub fn try_new(frame: Frame) -> Option<Self> {
let width = frame.width();
let height = frame.height();
if width == 0 || height == 0 {
return None;
}
if frame.data_size() as usize != (width * height * 2) as usize {
return None;
}
Some(Self {
frame,
width,
height,
})
}
pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}
pub fn pixels(&self) -> Vec<u16> {
self.frame
.data()
.chunks_exact(2)
.map(|c| u16::from_le_bytes([c[0], c[1]]))
.collect()
}
pub fn pixel(&self, x: u32, y: u32) -> Option<u16> {
if x >= self.width || y >= self.height {
return None;
}
let idx = (y * self.width + x) as usize * 2;
let data = self.frame.data();
if idx + 1 >= data.len() {
return None;
}
Some(u16::from_le_bytes([data[idx], data[idx + 1]]))
}
pub fn center_depth_mm(&self) -> Option<u16> {
self.pixel(self.width / 2, self.height / 2)
}
pub fn center_depth_m(&self) -> Option<f32> {
self.center_depth_mm().map(|v| v as f32 / 1000.0)
}
pub fn box_distance(&self, bbox: &BoundingBox) -> Option<(f32, f32)> {
let x_hi = bbox.right().min(self.width);
let y_hi = bbox.bottom().min(self.height);
if bbox.x >= x_hi || bbox.y >= y_hi {
return None;
}
let mut vals = Vec::with_capacity(bbox.area() as usize);
for y in bbox.y..y_hi {
for x in bbox.x..x_hi {
if let Some(v) = self.pixel(x, y) {
if (MIN_VALID_MM..MAX_VALID_MM).contains(&v) {
vals.push(v);
}
}
}
}
if vals.len() < MIN_BOX_PIXELS {
return None;
}
let total = (x_hi - bbox.x) as f32 * (y_hi - bbox.y) as f32;
let support = vals.len() as f32 / total;
vals.sort_unstable();
Some((vals[vals.len() / 2] as f32 / 1000.0, support))
}
pub fn into_frame(self) -> Frame {
self.frame
}
}
pub struct ColorFrame {
frame: Frame,
width: u32,
height: u32,
format: i32,
}
impl ColorFrame {
pub fn try_new(frame: Frame) -> Option<Self> {
let width = frame.width();
let height = frame.height();
if width == 0 || height == 0 {
return None;
}
let format = frame.format();
let bytes = (width * height) as usize;
let expected = match format {
orbbec_sys::OBFormat_OB_FORMAT_RGB | orbbec_sys::OBFormat_OB_FORMAT_BGR => {
Some(bytes * 3)
}
orbbec_sys::OBFormat_OB_FORMAT_Y8 | orbbec_sys::OBFormat_OB_FORMAT_GRAY => Some(bytes),
orbbec_sys::OBFormat_OB_FORMAT_RGBA | orbbec_sys::OBFormat_OB_FORMAT_BGRA => {
Some(bytes * 4)
}
orbbec_sys::OBFormat_OB_FORMAT_YUYV
| orbbec_sys::OBFormat_OB_FORMAT_YUY2
| orbbec_sys::OBFormat_OB_FORMAT_UYVY => Some(bytes * 2),
_ => None,
};
match expected {
Some(n) if n == frame.data_size() as usize => Some(Self {
frame,
width,
height,
format,
}),
_ => None,
}
}
pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}
pub fn format(&self) -> i32 {
self.format
}
pub fn data(&self) -> &[u8] {
self.frame.data()
}
pub fn pixel_rgb(&self, x: u32, y: u32) -> Option<(u8, u8, u8)> {
if x >= self.width || y >= self.height {
return None;
}
let data = self.frame.data();
match self.format {
orbbec_sys::OBFormat_OB_FORMAT_RGB => {
let i = (y * self.width + x) as usize * 3;
Some((data[i], data[i + 1], data[i + 2]))
}
orbbec_sys::OBFormat_OB_FORMAT_BGR => {
let i = (y * self.width + x) as usize * 3;
Some((data[i + 2], data[i + 1], data[i]))
}
orbbec_sys::OBFormat_OB_FORMAT_RGBA => {
let i = (y * self.width + x) as usize * 4;
Some((data[i], data[i + 1], data[i + 2]))
}
orbbec_sys::OBFormat_OB_FORMAT_BGRA => {
let i = (y * self.width + x) as usize * 4;
Some((data[i + 2], data[i + 1], data[i]))
}
orbbec_sys::OBFormat_OB_FORMAT_Y8 | orbbec_sys::OBFormat_OB_FORMAT_GRAY => {
let i = (y * self.width + x) as usize;
let v = data[i];
Some((v, v, v))
}
_ => None,
}
}
pub fn into_frame(self) -> Frame {
self.frame
}
}