use anyhow::{Result, bail, ensure};
use realsense_rust;
use realsense_rust::frame::{ColorFrame, PointsFrame};
use realsense_rust::pipeline::ActivePipeline;
use realsense_rust::{
config::Config,
context::Context,
frame::DepthFrame,
kind::{Rs2CameraInfo, Rs2Format, Rs2ProductLine, Rs2StreamKind},
pipeline::InactivePipeline,
};
use std::process::{Command, Stdio};
use std::{collections::HashSet, convert::TryFrom, time::Duration};
use crate::backend::realsense::rs2_process_frame::{FrameProc, FrameProcBlock, create_color_image};
pub struct RealsenseCam {
pub cam_no: usize,
pipeline: ActivePipeline,
pcl_block: FrameProcBlock<PointsFrame>,
}
impl RealsenseCam {
pub fn initialise_raw(cam_no: usize) -> Result<Self, anyhow::Error> {
let (pipeline, config) = Self::setup(cam_no)?;
Ok(Self {
cam_no,
pipeline: pipeline.start(Some(config))?,
pcl_block: FrameProcBlock::make_raw_points_block(1)?,
})
}
fn setup(cam_no: usize) -> Result<(InactivePipeline, Config), anyhow::Error> {
let mut queried_devices = HashSet::new();
queried_devices.insert(Rs2ProductLine::D400);
let context = Context::new()?;
let devices = context.query_devices(queried_devices);
ensure!(!devices.is_empty(), "No devices found");
if cam_no > devices.len() {
bail!("Invalid camera selection");
}
let pipeline = InactivePipeline::try_from(&Context::new()?)?;
let mut config = Config::new();
config
.enable_device_from_serial(devices[cam_no].info(Rs2CameraInfo::SerialNumber).unwrap())?
.disable_all_streams()?
.enable_stream(Rs2StreamKind::Depth, None, 1280, 0, Rs2Format::Z16, 30)?
.enable_stream(Rs2StreamKind::Color, None, 1280, 0, Rs2Format::Rgb8, 30)?;
Ok((pipeline, config))
}
pub fn get_depth_pnts(&mut self, max_range: f32) -> Result<Vec<[f32; 3]>> {
let frame = self.pipeline.wait(None)?;
let mut depth_frame = frame.frames_of_type::<DepthFrame>();
if depth_frame.is_empty() {
bail!("No depth frame to read!");
}
self.pcl_block
.queue(depth_frame.pop().unwrap())
.expect("FAILED TO QUEUE DEPTH FRAME");
let point_frame: PointsFrame = self.pcl_block.wait(Duration::from_millis(1000))?;
let mut points: Vec<[f32; 3]> = vec![];
for vertex in point_frame.vertices().iter() {
let vertex = vertex.xyz;
if vertex[2] == 0.0 || vertex[2] > max_range {
continue;
}
points.push(vertex)
}
Ok(points)
}
pub fn get_image(&mut self, filename: &str) -> Result<(), anyhow::Error> {
let frame = self.pipeline.wait(None)?;
let color_frame = frame.frames_of_type::<ColorFrame>();
if color_frame.is_empty() {
bail!("No color frame to read!");
}
let image = create_color_image(color_frame.first().unwrap())?;
let fp = format!("appdata\\{}.png", filename);
image.save(fp)?;
println!("Image saved!");
Ok(())
}
pub fn get_aruco_tags(&mut self) -> Result<Vec<(usize, [(i32, i32); 4])>, anyhow::Error> {
let tag_img_fp = format!("aruco_detect_{}", self.cam_no);
self.get_image(&tag_img_fp)?;
let py_cmd = Command::new(
"cmd",
)
.args([
"/C",
&format!(
"py src\\aruco_detection\\detect_aruco_id.py appdata\\{}.png",
tag_img_fp
),
])
.stdout(Stdio::piped())
.output()
.unwrap();
let out_string = String::from_utf8(py_cmd.stdout).unwrap();
let line_split: Vec<&str> = out_string.split("\n").collect();
let no_of_ids: usize = line_split[1]
.trim()
.replace("ID_COUNT:", "")
.parse()
.unwrap();
println!("Number of IDs detected: {}", no_of_ids);
if no_of_ids == 0 {
bail!("No ids detected")
}
let mut id_info: Vec<(usize, [(i32, i32); 4])> = vec![];
let lines_per_id = 4;
for i in 0..no_of_ids {
let start_line = i + 2 + (i * lines_per_id);
println!("{}", line_split[start_line]);
let id_no: usize = line_split[start_line]
.trim()
.replace("MARK:[[", "")
.replace("]]", "")
.parse()
.unwrap();
let mut corners: [(i32, i32); 4] = [(0, 0), (0, 0), (0, 0), (0, 0)];
for j in 1..=4 {
let corner_str: &str = line_split[start_line + j];
let corner_split = corner_str
.trim()
.replace("CORN:", "")
.replace("[", "")
.replace("]", "");
let corner_split: Vec<&str> = corner_split.split(".").collect();
corners[j - 1] = (
corner_split[0].trim().parse().unwrap(),
corner_split[1].trim().parse().unwrap(),
);
}
id_info.push((id_no, corners));
}
Ok(id_info)
}
}