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}