#pragma once #include "fgc/ICameraSource.h" namespace fgc { // Image-quality metrics over a raw captured frame. Pure (no OpenCV, no I/O) so it // lives in fgc_core and is unit-testable against synthetic buffers - mirrors // MtiProtocol / Sht41Protocol. The app target links OpenCV, but fgc_core and the // test target do not, and these metrics are a few dozen lines by hand. struct QualityParams { // Exposure/clipping stats sample every Nth pixel: 16x cheaper at stride 4 and // statistically indistinguishable on a 5 MP natural scene. Note it CAN alias on // strictly periodic detail whose period divides the stride (a synthetic // checkerboard is the pathological case), biasing the mean; set stride = 1 if a // scene ever turns out to be regular enough for that to matter. int stride = 4; // Sharpness is measured at FULL resolution on a centre square of this size - // subsampling destroys exactly the high-frequency content it measures. int sharpness_roi_px = 512; // A pixel at or above this counts as clipped (blown highlight). int clip_level = 254; // A pixel at or below this counts as crushed black. int dark_level = 1; }; struct ImageMetrics { bool valid = false; // false when the frame was empty/malformed double mean_luma = 0.0; // 0..255 double clipped_fraction = 0.0; // pixels with ANY channel >= clip_level double dark_fraction = 0.0; // pixels with ALL channels <= dark_level double sharpness = 0.0; // variance of the Laplacian over the centre ROI // Filled in by the caller from the camera's own Gain feature, not derived from // pixels: the camera reports gain exactly, whereas estimating noise from a // textured scene is unreliable. double gain_db = 0.0; }; // Compute the metrics for one frame. Supports 1 channel (mono) and 3 (RGB8). // Returns `valid = false` for anything else or for an empty buffer. ImageMetrics analyzeFrame(const Frame& frame, const QualityParams& params = {}); } // namespace fgc