Archived
1

py bindings

This commit is contained in:
Evan Pratten 2021-05-29 14:45:44 -04:00
parent 2b12cbaa9b
commit 498eb7623c
10 changed files with 167 additions and 128 deletions

View File

@ -1,2 +1,2 @@
[workspace]
members = ["libodm", "leapdebug"]
members = ["libodm", "pylibodm"]

View File

@ -1,7 +1,7 @@
# OpenDepthMap
Point cloud streams from Leap Motion cameras
```
clang libclang-dev libopencv-dev
clang libclang-dev libopencv-dev python3-dev python-dev
```

View File

@ -1,21 +0,0 @@
pub fn start_fern() {
fern::Dispatch::new()
// Perform allocation-free log formatting
.format(|out, message, record| {
out.finish(format_args!(
"{}[{}][{}] {}",
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
record.target(),
record.level(),
message
))
})
// Add blanket level filter -
.level(log::LevelFilter::Debug)
// Output to stdout, files, and other Dispatch configurations
.chain(std::io::stdout())
// Apply globally
.apply().unwrap();
}

View File

@ -1 +0,0 @@
pub mod logging;

View File

@ -1,24 +0,0 @@
use std::time::Duration;
use cli::logging::start_fern;
use libodm::leapmotion::device::LeapMotionDevice;
mod cli;
fn main() {
start_fern();
// Init a device
let mut device = LeapMotionDevice::create_device(Duration::from_secs(4)).unwrap();
log::info!("Got data");
log::info!("Press CTRL+C to exit");
loop {
// Read a single frame
let frame = device.get_frame().unwrap();
// Show data
frame.debug_show();
}
}

View File

@ -10,9 +10,8 @@ build = "build.rs"
[dependencies]
libc = "0.2.95"
log = "0.4.14"
glam = "0.15.2"
opencv = "0.53.0"
# glam = "0.15.2"
# opencv = "0.53.0"
[build-dependencies]
cc = "1.0"
pkg-config = "0.3.19"

View File

@ -1,56 +1,32 @@
use glam::UVec2;
use opencv::{core::{Image2D, Mat, Mat_AUTO_STEP, Size, CV_8U}, highgui::{imshow, named_window, wait_key}};
pub struct Image {
size: UVec2,
raw_data: *const u8,
img: Mat,
pub struct Image<'a> {
width: u32,
height: u32,
buffer: &'a [u8],
}
impl Image {
impl Image<'_> {
/// Create a new image from raw data
pub fn new_raw(width: i32, height: i32, raw_data: *const u8) -> Result<Self, opencv::Error> {
// Build a CV size
let size = Size::new(width, height);
let image;
unsafe {
image =
Mat::new_size_with_data(size, CV_8U, raw_data as *mut libc::c_void, Mat_AUTO_STEP)?;
pub fn new(width: i32, height: i32, raw_data: *const u8) -> Self {
Self {
width: width as u32,
height: height as u32,
buffer: unsafe { std::slice::from_raw_parts(raw_data, (width * height) as usize) },
}
}
Ok(Self {
size: UVec2::new(width as u32, height as u32),
raw_data,
img: image,
})
/// Get the image width
pub fn get_width(&self) -> u32 {
self.width
}
/// Get the image size
pub fn get_size(&self) -> &UVec2 {
&self.size
/// Get the image height
pub fn get_height(&self) -> u32 {
self.height
}
/// Get the internal OpenCV image
pub fn get_image(&self) -> &Mat {
&self.img
}
/// Show this image in a debug window
pub fn debug_show(&self){
// Create a debug window
imshow("Debug", &self.img).unwrap();
wait_key(0).unwrap();
pub fn get_image(&self) -> &[u8] {
&self.buffer
}
}
// impl Drop for Image {
// fn drop(&mut self) {
// unsafe {
// libc::free(self.raw_data as *mut libc::c_void);
// }
// }
// }

View File

@ -2,8 +2,6 @@
use std::time::{Duration, SystemTime};
use opencv::highgui::{imshow, wait_key};
use crate::image::Image;
use super::ffi;
@ -25,23 +23,15 @@ pub enum DeviceError {
}
/// Represents a single data frame generated by the LeapMotion device
pub struct DeviceFrame {
pub struct DeviceFrame<'a> {
/// Number of bytes per pixel
pub bytes_per_pixel: u8,
/// Image from the left camera
pub left_camera: Image,
pub left_camera: Image<'a>,
/// Image from the right camera
pub right_camera: Image,
}
impl DeviceFrame {
pub fn debug_show(&self){
imshow("Left Camera", self.left_camera.get_image()).unwrap();
imshow("Right Camera", self.right_camera.get_image()).unwrap();
wait_key(25).unwrap();
}
pub right_camera: Image<'a>,
}
/// Represents a LeapMotion device, and provides safe wrappers around its FFI
@ -128,28 +118,30 @@ impl LeapMotionDevice {
let image_width;
let image_height;
let bytes_per_pixel;
let mut left_image_raw;
let mut right_image_raw;
let left_image_raw;
let right_image_raw;
unsafe {
image_width = ffi::getImageWidth();
image_height = ffi::getImageHeight();
bytes_per_pixel = ffi::getImageBPP();
if self.cameras_flipped {
left_image_raw = ffi::getImageRight();
right_image_raw = ffi::getImageLeft();
} else {
left_image_raw = ffi::getImageLeft();
right_image_raw = ffi::getImageRight();
}
}
// Build two images
let left_image = Image::new_raw(image_width, image_height, left_image_raw);
let right_image = Image::new_raw(image_width, image_height, right_image_raw);
if left_image.is_err() || right_image.is_err() {
return Err(DeviceError::DecodeError);
}
let left_image = Image::new(image_width, image_height, left_image_raw);
let right_image = Image::new(image_width, image_height, right_image_raw);
Ok(DeviceFrame {
bytes_per_pixel: bytes_per_pixel as u8,
left_camera: left_image.unwrap(),
right_camera: right_image.unwrap(),
left_camera: left_image,
right_camera: right_image,
})
}
}

View File

@ -1,13 +1,17 @@
[package]
name = "leapdebug"
name = "pylibodm"
version = "0.1.0"
authors = ["Evan Pratten <ewpratten@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "pylibodm"
crate-type = ["cdylib"]
[dependencies]
libodm = { version = "0.1.0", path = "../libodm"}
fern = "0.6.0"
log = "0.4.14"
chrono = "0.4.19"
[dependencies.pyo3]
version = "0.13.2"
features = ["extension-module"]

114
pylibodm/src/lib.rs Normal file
View File

@ -0,0 +1,114 @@
use libodm::leapmotion::device::LeapMotionDevice;
pub(crate) static mut DEVICE_INSTANCE: Option<LeapMotionDevice> = None;
mod errors {
use libodm::leapmotion::device::DeviceError;
use pyo3::{exceptions::PyOSError, prelude::*};
#[derive(Debug)]
pub struct PyDeviceError(DeviceError);
impl From<DeviceError> for PyDeviceError {
fn from(e: DeviceError) -> Self {
Self { 0: e }
}
}
impl std::convert::From<PyDeviceError> for PyErr {
fn from(err: PyDeviceError) -> PyErr {
PyOSError::new_err(format!("{:?}", err.0))
}
}
}
mod device {
use std::time::Duration;
use libodm::{
image::Image,
leapmotion::device::{DeviceFrame, LeapMotionDevice},
};
use pyo3::prelude::*;
use crate::{errors::PyDeviceError, DEVICE_INSTANCE};
#[pyclass]
struct PyImage {
pub width: u32,
pub height: u32,
pub buffer: Vec<u8>,
}
impl IntoPy<PyImage> for Image<'_> {
fn into_py(self, py: Python) -> PyImage {
PyImage {
width: self.get_width(),
height: self.get_height(),
buffer: self.get_image().into_iter().map(|e| *e).collect(),
}
}
}
#[pyclass]
struct PyDeviceFrame {
pub bytes_per_pixel: u8,
pub left_camera: PyImage,
pub right_camera: PyImage,
}
impl IntoPy<PyDeviceFrame> for DeviceFrame<'_> {
fn into_py(self, py: Python) -> PyDeviceFrame {
PyDeviceFrame {
bytes_per_pixel: self.bytes_per_pixel,
left_camera: self.left_camera.into_py(py),
right_camera: self.right_camera.into_py(py),
}
}
}
#[pymodule]
pub fn leap_device(py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "connect")]
fn connect(timeout_secs: u64) -> Result<(), PyDeviceError> {
// Create a leap device
let device = LeapMotionDevice::create_device(Duration::from_secs(timeout_secs))?;
// Override the instance
unsafe {
DEVICE_INSTANCE = Some(device);
}
Ok(())
}
#[pyfn(m, "set_cameras_flipped")]
fn set_cameras_flipped(flipped: bool) -> PyResult<()> {
unsafe {
DEVICE_INSTANCE
.as_mut()
.unwrap()
.set_cameras_flipped(flipped);
}
Ok(())
}
#[pyfn(m, "get_cameras_flipped")]
fn get_cameras_flipped() -> PyResult<bool> {
Ok(unsafe { DEVICE_INSTANCE.as_ref().unwrap().cameras_flipped() })
}
#[pyfn(m, "has_frame")]
fn has_frame() -> PyResult<bool> {
Ok(unsafe { DEVICE_INSTANCE.as_mut().unwrap().has_frame() })
}
#[pyfn(m, "get_frame")]
fn get_frame(py: Python) -> Result<PyDeviceFrame, PyDeviceError> {
Ok(unsafe { DEVICE_INSTANCE.as_mut().unwrap().get_frame()?.into_py(py) })
}
Ok(())
}
}