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

  1. Polling example ```rust fn main() { let mut camera = Camera::new().unwrap(); camera.useautoexposure().unwrap(); // exposure will be automatically determined by camera camera.setprepareimagetimeout(1000); // how long to wait for one capture before fail // reserve inner buffer for one image. You can skip this, and camera will allocate this // on fly with warning camera.reserveimage_buf(1).unwrap();

    let nimages = 10; for _ in 0..nimages { // Fails if camera can't make capture camera.prepareimg().unwrap(); let (imagebuf, imageinfo) = camera.getimg().unwrap(); let (width, height) = (imageinfo.width, imageinfo.height); // Now do whatever you want to do with images. // Make sure you copied buffer before calling next camera.get_img() // -- snip -- } } ```

  2. Default callback example

You can create your own callback (example 3), but usually default callback is enough.

  1. 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 ```rust struct AverageCallbackCtx { avg: f64, buf: Rc>>, imgsize: usize, nimages: usize, } impl AverageCallbackCtx { pub fn new() -> AverageCallbackCtx { AverageCallbackCtx { avg: 0f64, buf: Rc::new(RefCell::new(Vec::new())), imgsize: 0, nimages: 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 { // This will be called once when applying callback. Make sure to allocate enough memory fn allocatecambuf(&mut self, imgsize: usize, nimages: usize) -> CamRes<()> { let mut bufref = self.buf.borrowmut(); bufref.resize(imgsize, 0); self.imgsize = imgsize; self.nimages = nimages; Ok(()) }

// Camera will write in the buffer returned by this function on each callback
fn get_cam_buf(&mut self) -> Rc<RefCell<Vec<u8>>> {
    return Rc::clone(&self.buf);
}

// Thus function will be called after camera buffer is filled.
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(); // use software trigger mode, some settings (The same as in Example 2) // -- snip --

let n_images = 10;
let wait_time = 33;
let avg_ctx = AverageCallbackCtx::new();

// reserve memory for images. Camera takes ownership of context.
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));
}
// return ownership of the context
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());
    }
}

} ```