MVSDK-Rust
rust wrapper on raw bindings of MVSDK - Mindvision industrial camera SDK
Compile bindings:
cargo build --features compile_bindings
Tests:
cargo test
Demos
cargo run --release --features polling_example
cargo run --release --features default_callback_example
cargo run --release --features custom_callback_example
API example
- Polling example
fn main() {
let mut camera = Camera::new().unwrap();
camera.use_auto_exposure().unwrap(); camera.set_prepare_image_timeout(1000); camera.reserve_image_buf(1).unwrap();
let n_images = 10;
for _ in 0..n_images {
camera.prepare_img().unwrap();
let (image_buf, image_info) = camera.get_img().unwrap();
let (width, height) = (image_info.width, image_info.height);
}
}
- Default callback example
You can create your own callback (example 3), but usually default callback is enough.
- There is inner buffer, that is preallocated with Camera::prepare_trigger.
- Default callback makes camera write to this buffer, them moves pointer on camera.img_size bytes.
- Later you can get immutable reference to this buffer, for you needs
fn main() {
let mut camera = Camera::new().unwrap();
let n_images = 10;
let wait_time_ms = 60;
camera.set_trigger_mode(TriggerMode::SoftWareTrigger).unwrap();
camera.use_manual_exposure().unwrap();
camera.set_analog_gain(1).unwrap();
camera.set_exposure_time(16777f64).unwrap();
camera.set_trigger_delay_time(0).unwrap();
camera.set_lut_mode(LutMode::PRESET).unwrap();
camera.set_lut_preset(3).unwrap();
camera.set_callback_context(n_images, None).unwrap();
for i in 0..n_images {
camera.software_trigger().unwrap();
thread::sleep(time::Duration::from_millis(wait_time_ms));
}
let images_buf = camera.get_img_buf();
let image_size = camera.get_image_size();
assert_eq!(images_buf.len(), image_size * n_images);
let CameraResolution {width, height, ..} = camera.get_current_resolution().unwrap();
}
- Custom callback example
This is example of custom callback that calculates average value of all captures.
Note, that in this case using custom callback is more memory efficient, than default callback,
since you don't have to preallocate memory for all images beforehand, and there is no copying.
You have to implemet camera::CamCallBackCtx trait
struct AverageCallbackCtx {
avg: f64,
buf: Rc<RefCell<Vec<u8>>>,
img_size: usize,
n_images: usize,
}
impl AverageCallbackCtx {
pub fn new() -> AverageCallbackCtx {
AverageCallbackCtx {
avg: 0f64,
buf: Rc::new(RefCell::new(Vec::new())),
img_size: 0,
n_images: 0,
}
}
pub fn get_avg(&self) -> f64 {
if self.n_images > 0 {
return self.avg / self.n_images as f64;
}
return 0f64;
}
}
impl CamCallBackCtx for AverageCallbackCtx {
fn allocate_cam_buf(&mut self, img_size: usize, n_images: usize) -> CamRes<()> {
let mut buf_ref = self.buf.borrow_mut();
buf_ref.resize(img_size, 0);
self.img_size = img_size;
self.n_images = n_images;
Ok(())
}
fn get_cam_buf(&mut self) -> Rc<RefCell<Vec<u8>>> {
return Rc::clone(&self.buf);
}
fn process_cam_buf(&mut self, buf_is_valid: bool, image_info: ImageInfo) {
if buf_is_valid {
let buf_ref = self.buf.borrow();
let mut local_avg = 0f64;
for i in 0..self.img_size {
local_avg += buf_ref[i] as f64;
}
local_avg /= self.img_size as f64;
self.avg += local_avg;
}
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
fn main() {
let mut camera = Camera::new().unwrap();
let n_images = 10;
let wait_time = 33;
let avg_ctx = AverageCallbackCtx::new();
camera.set_callback_context(n_images, Some(Box::new(avg_ctx))).unwrap();
for i in 0..n_images {
camera.software_trigger().unwrap();
thread::sleep(time::Duration::from_millis(wait_time));
}
if let Some(avg_ctx) = camera.get_callback_context() {
if let Some(avg_ctx) = avg_ctx.as_any().downcast_ref::<AverageCallbackCtx>() {
println!("Average value: {}", avg_ctx.get_avg());
}
}
}