silence_core/cam/
mod.rs

1//! Offers the ability to receive camera input.
2
3use anyhow::bail;
4use opencv::{
5    core::{Mat, MatTraitConst, MatTraitConstManual, Size_},
6    videoio::{VideoCapture, VideoCaptureTrait, VideoCaptureTraitConst, CAP_ANY},
7};
8
9//Reinport important functions
10pub use opencv::imgproc::{cvt_color_def, COLOR_BGR2RGB};
11//Re-export the opencv crate.
12pub use opencv;
13
14/// Webcam struct definition.
15/// The struct wraps the ```VideoCapture``` type, and has custom functions for it.
16/// You can create a new instance with the ```new``` functions.
17#[derive(Debug)]
18pub struct Webcam(VideoCapture);
19
20impl Webcam {
21    ///
22    /// Create new ```Webcam``` instance with api preference and camera index.
23    ///
24    /// **If you want to use the default api_preference you should use ```new_def(i32)``` instead**
25    ///
26    /// # Behavior
27    /// Creates a new webcam instance with a set index and an [api_preference](https://docs.rs/opencv/0.93.4/opencv/videoio/enum.VideoCaptureAPIs.html).
28    ///
29    /// # Error
30    /// Returns an error if the inpt device could not be found based on the camera_idx, or if the api preference was invalid.
31    ///
32    /// # Information
33    /// 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```.
34    ///
35    pub fn new(camera_idx: i32, api_preference: i32) -> anyhow::Result<Self> {
36        let video_capture_handle = VideoCapture::new(camera_idx, api_preference)?;
37
38        if !video_capture_handle.is_opened()? {
39            bail!("Failed to open capture device.")
40        }
41
42        Ok(Self(video_capture_handle))
43    }
44
45    ///
46    /// Create new ```Webcam``` instance with automatic camera detection.
47    ///
48    /// **If you have more than one camera you should use the [`Self::new_def`] function to define which camera you are wanting to use.**
49    ///
50    /// # Behavior
51    /// Creates a new [`Webcam`] instance while automaticly detecting the camera input.
52    ///
53    /// # Error
54    /// This returns an error if it could not find the input device.
55    ///
56    pub fn new_def_auto_detect() -> anyhow::Result<Self> {
57        let video_capture_handle = VideoCapture::new_def(CAP_ANY)?;
58
59        if !video_capture_handle.is_opened()? {
60            bail!("Failed to open capture device.")
61        }
62
63        Ok(Self(video_capture_handle))
64    }
65
66    ///
67    /// Create new ```Webcam``` instance with api preference and camera index.
68    ///
69    /// # Behavior
70    /// Creates a new webcam instance with a set index and the default ```api_preference``` ([`CAP_ANY`]).
71    ///
72    /// # Error
73    /// Returns an error if the inpt device could not be found based on the camera_idx.
74    pub fn new_def(camera_idx: i32) -> anyhow::Result<Self> {
75        let video_capture_handle = VideoCapture::new_def(camera_idx)?;
76
77        if !video_capture_handle.is_opened()? {
78            bail!("Failed to open capture device.")
79        }
80
81        Ok(Self(video_capture_handle))
82    }
83
84    ///
85    /// Requests a frame from the [`Webcam`] instance.
86    ///
87    /// # Behavior
88    /// Reads an image out of the ```VideoCapture``` buffer, this removes the bytes of the image from the buffer.
89    /// Returns a tuple of the raw image bytes and the size of the image.
90    ///
91    /// # Information
92    /// 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
93    ///
94    /// # Error
95    /// Returns an error if it:
96    ///     * failed to read from the webcam.
97    ///     * the color format conversion failed.
98    ///     * there was some kind of error when getting the image bytes / the size of the image from the [`Mat`].
99    ///     * the Webcam instance was invalid. (It got released before requesting this frame)
100    ///
101    pub fn get_frame(&mut self) -> anyhow::Result<(Vec<u8>, Size_<i32>)> {
102        //Create frame which will be overwritten
103        let mut frame = Mat::default();
104
105        //Read frame
106        self.0.read(&mut frame)?;
107
108        //Create corrected_frame
109        let mut corrected_frame = Mat::default();
110
111        //Color correction
112        cvt_color_def(&frame, &mut corrected_frame, COLOR_BGR2RGB)?;
113
114        //Return captured frame
115        Ok((
116            corrected_frame.data_bytes()?.to_vec(),
117            corrected_frame.size()?,
118        ))
119    }
120
121    ///
122    /// Get the backend api's name.
123    ///
124    /// # Behavior
125    /// Gets the backend api's name.
126    ///
127    /// # Error
128    /// Returns an error if it failed to get the backend api's name.
129    ///
130    pub fn get_backend_name(&self) -> anyhow::Result<String> {
131        Ok(self.0.get_backend_name()?)
132    }
133
134    ///
135    /// This function drops the inner ```VideoCapture``` instance.
136    ///
137    /// # Behavior
138    /// This function releases the [`Webcam`]'s underlying [`VideoCapture`] instance.
139    ///
140    /// # Information
141    /// The underlying [`VideoCapture`] instance is invalidated, thus requesting frames on this [`Webcam`] instance will be unsuccessful.
142    ///
143    /// # Error
144    /// Returns an error if it could not invalidate the instance.
145    ///
146    pub fn release(&mut self) -> anyhow::Result<()> {
147        Ok(self.0.release()?)
148    }
149}