visual_cortex_vision/
frame_diff.rs1use std::hash::{Hash, Hasher};
2
3use visual_cortex_capture::FrameView;
4
5use crate::detector::{Detector, DetectorError, DetectorOutput};
6
7#[derive(Default)]
10pub struct FrameDiff {
11 last_hash: Option<u64>,
12}
13
14impl FrameDiff {
15 pub fn new() -> Self {
16 Self::default()
17 }
18}
19
20impl Detector for FrameDiff {
21 fn evaluate(&mut self, view: &FrameView<'_>) -> Result<DetectorOutput, DetectorError> {
22 let mut hasher = std::collections::hash_map::DefaultHasher::new();
23 for row in view.rows() {
24 row.hash(&mut hasher);
25 }
26 let hash = hasher.finish();
27 let changed = self.last_hash != Some(hash);
28 self.last_hash = Some(hash);
29 Ok(DetectorOutput::Bool(changed))
30 }
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36 use visual_cortex_capture::{Frame, PxRect};
37
38 fn full_view(frame: &Frame) -> FrameView<'_> {
39 frame
40 .view(PxRect {
41 x: 0,
42 y: 0,
43 w: frame.width(),
44 h: frame.height(),
45 })
46 .unwrap()
47 }
48
49 #[test]
50 fn first_evaluation_reports_changed() {
51 let f = Frame::solid(4, 4, [0, 0, 0, 255]);
52 let mut gate = FrameDiff::new();
53 assert_eq!(
54 gate.evaluate(&full_view(&f)).unwrap(),
55 DetectorOutput::Bool(true)
56 );
57 }
58
59 #[test]
60 fn identical_pixels_report_unchanged() {
61 let a = Frame::solid(4, 4, [9, 9, 9, 255]);
62 let b = Frame::solid(4, 4, [9, 9, 9, 255]); let mut gate = FrameDiff::new();
64 gate.evaluate(&full_view(&a)).unwrap();
65 assert_eq!(
66 gate.evaluate(&full_view(&b)).unwrap(),
67 DetectorOutput::Bool(false)
68 );
69 }
70
71 #[test]
72 fn different_pixels_report_changed() {
73 let a = Frame::solid(4, 4, [0, 0, 0, 255]);
74 let b = Frame::solid(4, 4, [255, 0, 0, 255]);
75 let mut gate = FrameDiff::new();
76 gate.evaluate(&full_view(&a)).unwrap();
77 assert_eq!(
78 gate.evaluate(&full_view(&b)).unwrap(),
79 DetectorOutput::Bool(true)
80 );
81 }
82}