1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
use anyhow::bail;
use image::imageops::FilterType;
use opencv::core::{Mat, MatTraitConst, MatTraitConstManual, Size_};
use opencv::imgproc::{cvt_color_def, COLOR_BGR2RGB};
use opencv::videoio::{VideoCapture, VideoCaptureTrait, VideoCaptureTraitConst, CAP_ANY};
/// Webcam struct definition
/// The struct wraps the ```VideoCapture``` type, and has custom functions for it.
/// You can create a new instance with the ```new``` functions.
pub struct Webcam(VideoCapture);
impl Webcam {
/// Create new ```Webcam``` instance with api preference and camera index
/// If you want to use the default api_preference you should use ```new_def(i32)``` instead
/// API preference consts are available at the [opencv documentation](https://docs.rs/opencv/latest/opencv/index.html). Some exmaples for this const are: ```CAP_MSMF```, ```CAP_V4L```.
pub fn new(camera_idx: i32, api_preference: i32) -> anyhow::Result<Self> {
let video_capture_handle = VideoCapture::new(camera_idx, api_preference)?;
if !video_capture_handle.is_opened()? {
bail!("Failed to open capture device.")
}
Ok(Self(video_capture_handle))
}
/// Create new ```Webcam``` instance with auto camera detection.
/// Please note that this function tries to auto detect the camera.
/// If you have more than one camera you should use the ```new_def(i32)``` function to define which camera you are wanting to use.
pub fn new_def_auto_detect() -> anyhow::Result<Self> {
let video_capture_handle = VideoCapture::new_def(CAP_ANY)?;
if !video_capture_handle.is_opened()? {
bail!("Failed to open capture device.")
}
Ok(Self(video_capture_handle))
}
/// Create new ```Webcam``` instance from the camera index.
/// The passed in argument defines which camera this function creates a new instance from
pub fn new_def(camera_idx: i32) -> anyhow::Result<Self> {
let video_capture_handle = VideoCapture::new_def(camera_idx)?;
if !video_capture_handle.is_opened()? {
bail!("Failed to open capture device.")
}
Ok(Self(video_capture_handle))
}
/// Reads an image out of the ```VideoCapture``` buffer, this removes the bytes of the image from the buffer.
/// Returns a tuple of the raw image bytes and the size of the image.
/// Please note the image's bytes returned by this function are automaticly converted from [BRG8](https://learn.microsoft.com/en-us/windows/win32/wic/-wic-codec-native-pixel-formats#rgbbgr-color-model) (Which is returned by opencv by default) to RGB8
pub fn get_frame(&mut self) -> anyhow::Result<(Vec<u8>, Size_<i32>)> {
//Create frame which will be overwritten
let mut frame = Mat::default();
//Read frame
self.0.read(&mut frame)?;
//Create corrected_frame
let mut corrected_frame = Mat::default();
//Color correction
cvt_color_def(&frame, &mut corrected_frame, COLOR_BGR2RGB)?;
//Return captured frame
Ok((frame.data_bytes()?.to_vec(), corrected_frame.size()?))
}
/// Get the backend api's name
pub fn get_backend_name(&self) -> anyhow::Result<String> {
Ok(self.0.get_backend_name()?)
}
/// This function drops the inner ```VideoCapture``` instance.
/// If this function is called the instance wont be able to capture any frames, you will need to create a new instance.
pub fn release(&mut self) -> anyhow::Result<()> {
Ok(self.0.release()?)
}
}
/// Resize your images (Raw image bytes are not accepted, since they arent in a format), the resized image's bytes are returned.
/// You have to provide the bytes, width, hight and the preferred filter type of the image (Nearest is the fastest).
pub fn resize_image_from_bytes(formatted_image_bytes: &[u8], width: u32, lenght: u32, filter: FilterType) -> anyhow::Result<Vec<u8>> {
let frame = image::load_from_memory(formatted_image_bytes)?;
Ok(frame.resize_exact(width, lenght, filter).as_bytes().to_vec())
}