visual-cortex-vision 0.10.0

Detectors for visual-cortex: pixel/color conditions, template matching, the OcrEngine contract, and OCR text parsers.
Documentation
use std::hash::{Hash, Hasher};

use visual_cortex_capture::FrameView;

use crate::detector::{Detector, DetectorError, DetectorOutput};

/// Boolean gate: did the region's pixels change since the last evaluation?
/// Hashes the region's bytes; the first evaluation always reports changed.
#[derive(Default)]
pub struct FrameDiff {
    last_hash: Option<u64>,
}

impl FrameDiff {
    pub fn new() -> Self {
        Self::default()
    }
}

impl Detector for FrameDiff {
    fn evaluate(&mut self, view: &FrameView<'_>) -> Result<DetectorOutput, DetectorError> {
        let mut hasher = std::collections::hash_map::DefaultHasher::new();
        for row in view.rows() {
            row.hash(&mut hasher);
        }
        let hash = hasher.finish();
        let changed = self.last_hash != Some(hash);
        self.last_hash = Some(hash);
        Ok(DetectorOutput::Bool(changed))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use visual_cortex_capture::{Frame, PxRect};

    fn full_view(frame: &Frame) -> FrameView<'_> {
        frame
            .view(PxRect {
                x: 0,
                y: 0,
                w: frame.width(),
                h: frame.height(),
            })
            .unwrap()
    }

    #[test]
    fn first_evaluation_reports_changed() {
        let f = Frame::solid(4, 4, [0, 0, 0, 255]);
        let mut gate = FrameDiff::new();
        assert_eq!(
            gate.evaluate(&full_view(&f)).unwrap(),
            DetectorOutput::Bool(true)
        );
    }

    #[test]
    fn identical_pixels_report_unchanged() {
        let a = Frame::solid(4, 4, [9, 9, 9, 255]);
        let b = Frame::solid(4, 4, [9, 9, 9, 255]); // different Frame, same pixels
        let mut gate = FrameDiff::new();
        gate.evaluate(&full_view(&a)).unwrap();
        assert_eq!(
            gate.evaluate(&full_view(&b)).unwrap(),
            DetectorOutput::Bool(false)
        );
    }

    #[test]
    fn different_pixels_report_changed() {
        let a = Frame::solid(4, 4, [0, 0, 0, 255]);
        let b = Frame::solid(4, 4, [255, 0, 0, 255]);
        let mut gate = FrameDiff::new();
        gate.evaluate(&full_view(&a)).unwrap();
        assert_eq!(
            gate.evaluate(&full_view(&b)).unwrap(),
            DetectorOutput::Bool(true)
        );
    }
}