kinect_v2/
body_index_capture.rs1use std::sync::Arc;
2
3use kinect_v2_sys::{
4 DEFAULT_FRAME_WAIT_TIMEOUT_MS, WAITABLE_HANDLE,
5 body_index::{BodyIndexFrame, BodyIndexFrameReader},
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 BodyIndexFrameCapture {
17 kinect: KinectSensor, }
19
20impl BodyIndexFrameCapture {
21 pub fn new() -> Result<Self, Error> {
31 let kinect = kinect::get_default_kinect_sensor()?;
32 kinect.open()?;
33
34 Ok(BodyIndexFrameCapture { kinect })
35 }
36
37 pub fn iter(&self) -> Result<BodyIndexFrameCaptureIter, Error> {
48 let source = self.kinect.body_index_frame_source()?;
49 let reader = source.open_reader()?;
51 if !source.get_is_active()? {
54 log::warn!(
55 "Body index frame source is not active, cannot subscribe to frame arrived event."
56 );
57 return Err(Error::from_hresult(E_FAIL));
58 }
59
60 let mut waitable_handle = WAITABLE_HANDLE::default();
61 reader.subscribe_frame_arrived(&mut waitable_handle)?;
62 Ok(BodyIndexFrameCaptureIter {
63 reader,
64 waitable_handle,
65 timeout_ms: DEFAULT_FRAME_WAIT_TIMEOUT_MS,
66 })
67 }
68}
69
70pub struct BodyIndexFrameCaptureIter {
75 reader: BodyIndexFrameReader,
76 waitable_handle: WAITABLE_HANDLE,
77 timeout_ms: u32,
78}
79
80impl Drop for BodyIndexFrameCaptureIter {
81 fn drop(&mut self) {
82 if let Err(e) = self.reader.unsubscribe_frame_arrived(self.waitable_handle) {
85 log::warn!("Failed to unsubscribe body index frame arrived event: {e:?}");
86 }
87 }
88}
89
90impl Iterator for BodyIndexFrameCaptureIter {
91 type Item = Result<BodyIndexFrameData, Error>;
92
93 fn next(&mut self) -> Option<Self::Item> {
94 loop {
95 let wait_status: WAIT_EVENT =
96 unsafe { WaitForSingleObject(self.waitable_handle, self.timeout_ms) };
97
98 if wait_status == WAIT_OBJECT_0 {
99 let result = (|| {
102 let event_args = self
103 .reader
104 .get_frame_arrived_event_data(self.waitable_handle)?;
105 let frame_reference = event_args.get_frame_reference()?;
106 let body_index_frame = frame_reference.acquire_frame()?;
107 BodyIndexFrameData::new(&body_index_frame)
108 })(); return Some(result);
110 } else if wait_status == WAIT_TIMEOUT {
111 continue;
114 } else {
115 return Some(Err(Error::from_hresult(E_FAIL)));
116 }
117 }
118 }
119}
120
121#[derive(Debug, Clone)]
122pub struct BodyIndexStatistics {
123 pub body_pixel_counts: [u32; 6],
125 pub background_pixels: u32,
127 pub unknown_pixels: u32,
129 pub total_body_pixels: u32,
131 pub total_pixels: u32,
133 pub body_coverage_percentage: f32,
135}
136
137impl BodyIndexStatistics {
138 pub fn active_body_count(&self) -> usize {
140 self.body_pixel_counts
141 .iter()
142 .filter(|&&count| count > 0)
143 .count()
144 }
145
146 pub fn dominant_body_index(&self) -> Option<usize> {
148 self.body_pixel_counts
149 .iter()
150 .enumerate()
151 .max_by_key(|(_, count)| *count)
152 .and_then(|(index, count)| if *count > 0 { Some(index) } else { None })
153 }
154}
155
156#[derive(Debug, Clone)]
157pub struct BodyIndexFrameData {
158 pub width: u32,
159 pub height: u32,
160 pub timestamp: u64,
161 pub data: Arc<[u8]>,
162}
163
164impl BodyIndexFrameData {
165 pub fn new(body_index_frame: &BodyIndexFrame) -> Result<Self, Error> {
166 let frame_description = body_index_frame.get_frame_description()?;
167 let width = frame_description.get_width()? as u32;
168 let height = frame_description.get_height()? as u32;
169 let timestamp = body_index_frame.get_relative_time()? as u64;
170
171 let buffer_size = width * height;
174 let mut data = Vec::with_capacity(buffer_size as usize);
175
176 let raw_buffer = body_index_frame.access_underlying_buffer()?;
177 assert!(
178 raw_buffer.len() as u32 == buffer_size,
179 "Raw buffer size does not match expected size"
180 );
181 data.extend_from_slice(raw_buffer);
182
183 Ok(Self {
184 width,
185 height,
186 timestamp,
187 data: Arc::from(data),
188 })
189 }
190
191 pub fn get_body_index_at(&self, x: u32, y: u32) -> Option<u8> {
196 if x >= self.width || y >= self.height {
197 return None;
198 }
199 let index = (y * self.width + x) as usize;
200 self.data.get(index).copied()
201 }
202
203 pub fn is_body_pixel(&self, x: u32, y: u32) -> bool {
205 self.get_body_index_at(x, y)
206 .map(|body_index| body_index < 6) .unwrap_or(false)
208 }
209
210 pub fn is_background_pixel(&self, x: u32, y: u32) -> bool {
212 self.get_body_index_at(x, y)
213 .map(|body_index| body_index == 255) .unwrap_or(false)
215 }
216
217 pub fn get_body_statistics(&self) -> BodyIndexStatistics {
219 let mut body_pixel_counts = [0u32; 6]; let mut background_pixels = 0u32;
221 let mut unknown_pixels = 0u32;
222
223 for &body_index in self.data.iter() {
224 match body_index {
225 0..=5 => body_pixel_counts[body_index as usize] += 1,
226 255 => background_pixels += 1,
227 _ => unknown_pixels += 1,
228 }
229 }
230
231 let total_pixels = self.width * self.height;
232 let total_body_pixels: u32 = body_pixel_counts.iter().sum();
233
234 BodyIndexStatistics {
235 body_pixel_counts,
236 background_pixels,
237 unknown_pixels,
238 total_body_pixels,
239 total_pixels,
240 body_coverage_percentage: (total_body_pixels as f32 / total_pixels as f32) * 100.0,
241 }
242 }
243}
244
245impl Default for BodyIndexFrameData {
246 fn default() -> Self {
247 Self {
248 width: 0,
249 height: 0,
250 timestamp: 0,
251 data: Arc::from([]),
252 }
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use super::*;
259 use anyhow::anyhow;
260 use std::sync::mpsc;
261
262 #[test]
263 fn body_index_capture_test() -> anyhow::Result<()> {
264 let (tx, rx) = mpsc::channel::<BodyIndexFrameData>();
265 let max_frames_to_capture = 10;
266 let capture_thread = std::thread::spawn(move || -> anyhow::Result<()> {
267 let capture = BodyIndexFrameCapture::new()?;
268 for (frame_count, frame) in capture.iter()?.enumerate() {
269 if frame_count >= max_frames_to_capture {
270 break;
271 }
272 let data = frame.map_err(|e| anyhow!("Error capturing body index frame: {}", e))?;
273 if tx.send(data).is_err() {
274 break;
275 }
276 }
277 Ok(())
278 });
279
280 let processing_thread = std::thread::spawn(move || -> anyhow::Result<()> {
281 for _ in 0..max_frames_to_capture {
282 let frame_data = match rx.recv() {
283 Ok(data) => data,
284 Err(_) => break,
285 };
286 println!(
287 "Received body index frame: {}x{}, {} bytes, timestamp: {}",
288 frame_data.width,
289 frame_data.height,
290 frame_data.data.len(),
291 frame_data.timestamp
292 );
293 anyhow::ensure!(
294 frame_data.width > 0,
295 "Unexpected width: {}",
296 frame_data.width
297 );
298 anyhow::ensure!(
299 frame_data.height > 0,
300 "Unexpected height: {}",
301 frame_data.height
302 );
303 anyhow::ensure!(!frame_data.data.is_empty(), "Frame data is empty");
304 anyhow::ensure!(frame_data.timestamp > 0, "Timestamp is not positive");
305 }
306 Ok(())
307 });
308
309 capture_thread
310 .join()
311 .map_err(|e| anyhow!("Body index capture thread join error: {:?}", e))??;
312 processing_thread
313 .join()
314 .map_err(|e| anyhow!("Processing thread join error: {:?}", e))??;
315 Ok(())
316 }
317}