kinect_v2/
depth_capture.rs1use std::sync::Arc;
2
3use kinect_v2_sys::{
4 DEFAULT_FRAME_WAIT_TIMEOUT_MS, WAITABLE_HANDLE,
5 depth::{DepthFrame, DepthFrameReader},
6 kinect::{self, KinectSensor},
7};
8use windows::Win32::Foundation::{E_FAIL, WAIT_OBJECT_0, WAIT_TIMEOUT};
9use windows::Win32::System::Threading::WaitForSingleObject;
10use windows::{Win32::Foundation::WAIT_EVENT, core::Error};
11
12pub struct DepthFrameCapture {
17 kinect: KinectSensor, }
19
20impl DepthFrameCapture {
21 pub fn new() -> Result<Self, Error> {
31 let kinect = kinect::get_default_kinect_sensor()?;
32 kinect.open()?;
33
34 Ok(DepthFrameCapture { kinect })
35 }
36 pub fn iter(&self) -> Result<DepthFrameCaptureIter, Error> {
47 let source = self.kinect.depth_frame_source()?;
48 let reader = source.open_reader()?;
50 if !source.get_is_active()? {
53 log::warn!(
54 "Depth frame source is not active, cannot subscribe to frame arrived event."
55 );
56 return Err(Error::from_hresult(E_FAIL));
57 }
58
59 let waitable_handle = reader.subscribe_frame_arrived()?;
60 Ok(DepthFrameCaptureIter {
61 reader,
62 waitable_handle,
63 timeout_ms: DEFAULT_FRAME_WAIT_TIMEOUT_MS,
64 })
65 }
66}
67
68pub struct DepthFrameCaptureIter {
73 reader: DepthFrameReader,
74 waitable_handle: WAITABLE_HANDLE,
75 timeout_ms: u32,
76}
77
78impl Drop for DepthFrameCaptureIter {
79 fn drop(&mut self) {
80 if let Err(e) = self.reader.unsubscribe_frame_arrived(self.waitable_handle) {
83 log::warn!("Failed to unsubscribe depth frame arrived event: {e:?}");
84 }
85 }
86}
87
88impl Iterator for DepthFrameCaptureIter {
89 type Item = Result<DepthFrameData, Error>;
90
91 fn next(&mut self) -> Option<Self::Item> {
92 loop {
93 let wait_status: WAIT_EVENT =
94 unsafe { WaitForSingleObject(self.waitable_handle, self.timeout_ms) };
95
96 if wait_status == WAIT_OBJECT_0 {
97 let result = (|| {
100 let event_args = self
101 .reader
102 .get_frame_arrived_event_data(self.waitable_handle)?;
103 let frame_reference = event_args.get_frame_reference()?;
104 let depth_frame = frame_reference.acquire_frame()?;
105 DepthFrameData::new(&depth_frame)
106 })(); return Some(result);
108 } else if wait_status == WAIT_TIMEOUT {
109 continue;
112 } else {
113 return Some(Err(Error::from_hresult(E_FAIL)));
114 }
115 }
116 }
117}
118
119#[derive(Debug, Clone)]
120pub struct DepthFrameData {
121 pub width: u32,
122 pub height: u32,
123 pub timestamp: u64,
124 pub depth_min_reliable_distance: u16,
125 pub depth_max_reliable_distance: u16,
126 pub data: Arc<[u16]>, }
128
129impl DepthFrameData {
130 pub fn new(depth_frame: &DepthFrame) -> Result<Self, Error> {
131 let frame_description = depth_frame.get_frame_description()?;
132 let width = frame_description.get_width()? as u32;
133 let height = frame_description.get_height()? as u32;
134 let timestamp = depth_frame.get_relative_time()? as u64;
135 let depth_min_reliable_distance = depth_frame.get_depth_min_reliable_distance()?;
136 let depth_max_reliable_distance = depth_frame.get_depth_max_reliable_distance()?;
137 let raw_buffer = depth_frame.access_underlying_buffer()?;
138
139 Ok(Self {
140 width,
141 height,
142 timestamp,
143 depth_min_reliable_distance,
144 depth_max_reliable_distance,
145 data: Arc::from(raw_buffer.to_vec()),
146 })
147 }
148
149 pub fn depth_to_meters(&self, depth_value: u16) -> f32 {
154 depth_value as f32 / 1000.0
155 }
156
157 pub fn is_depth_reliable(&self, depth_value: u16) -> bool {
162 depth_value >= self.depth_min_reliable_distance
163 && depth_value <= self.depth_max_reliable_distance
164 }
165
166 pub fn get_depth_at(&self, x: u32, y: u32) -> Option<u16> {
170 if x >= self.width || y >= self.height {
171 return None;
172 }
173 let index = (y * self.width + x) as usize;
174 self.data.get(index).copied()
175 }
176}
177
178impl Default for DepthFrameData {
179 fn default() -> Self {
180 Self {
181 width: 0,
182 height: 0,
183 timestamp: 0,
184 depth_min_reliable_distance: 0,
185 depth_max_reliable_distance: 0,
186 data: Arc::from([]),
187 }
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194 use anyhow::anyhow;
195 use std::sync::mpsc;
196
197 #[test]
198 fn depth_capture_test() -> anyhow::Result<()> {
199 let (tx, rx) = mpsc::channel::<DepthFrameData>();
200 let max_frames_to_capture = 10;
201 let capture_thread = std::thread::spawn(move || -> anyhow::Result<()> {
202 let capture = DepthFrameCapture::new()?;
203 for (frame_count, frame) in capture.iter()?.enumerate() {
204 if frame_count >= max_frames_to_capture {
205 break;
206 }
207 let data = frame.map_err(|e| anyhow!("Error capturing depth frame: {}", e))?;
208 if tx.send(data).is_err() {
209 break;
210 }
211 }
212 Ok(())
213 });
214
215 let processing_thread = std::thread::spawn(move || -> anyhow::Result<()> {
216 for _ in 0..max_frames_to_capture {
217 let frame_data = match rx.recv() {
218 Ok(data) => data,
219 Err(_) => break,
220 };
221 println!(
222 "Received depth frame: {}x{}, {} values, timestamp: {}, min: {}, max: {}",
223 frame_data.width,
224 frame_data.height,
225 frame_data.data.len(),
226 frame_data.timestamp,
227 frame_data.depth_min_reliable_distance,
228 frame_data.depth_max_reliable_distance
229 );
230 anyhow::ensure!(
231 frame_data.width > 0,
232 "Unexpected width: {}",
233 frame_data.width
234 );
235 anyhow::ensure!(
236 frame_data.height > 0,
237 "Unexpected height: {}",
238 frame_data.height
239 );
240 anyhow::ensure!(!frame_data.data.is_empty(), "Frame data is empty");
241 anyhow::ensure!(frame_data.timestamp > 0, "Timestamp is not positive");
242 anyhow::ensure!(
243 frame_data.depth_max_reliable_distance > frame_data.depth_min_reliable_distance,
244 "Depth max should be greater than min"
245 );
246 }
247 Ok(())
248 });
249
250 capture_thread
251 .join()
252 .map_err(|e| anyhow!("Depth capture thread join error: {:?}", e))??;
253 processing_thread
254 .join()
255 .map_err(|e| anyhow!("Processing thread join error: {:?}", e))??;
256 Ok(())
257 }
258}