/* * MAG160C display pipeline - pure C, no OS/USB dependencies. * See mag160c_display.c for the pipeline documentation. */ #ifndef MAG160C_DISPLAY_H #define MAG160C_DISPLAY_H #include "mag160c/mag160c.h" #ifdef __cplusplus extern "C" { #endif /* ---- bad pixel map ------------------------------------------------------ */ typedef struct mag160c_display_badmap_t { uint32_t width; uint32_t height; uint32_t pixels; uint32_t feed_count; /* frames fed to mag160c_display_badmap_feed */ uint32_t temporal_thr; /* min/max fluctuation threshold (default 400) */ uint32_t hist_min_dev; /* histogram peak min deviation (default 200) */ uint32_t bad_count; /* detected bad pixels */ uint32_t order_len; /* pixels in the topological fill order */ int ready; /* set by finalize() */ uint8_t *bad; /* pixels bad mask */ uint32_t *order_x; /* fill order x */ uint32_t *order_y; /* fill order y */ uint64_t *ref_sum; /* reference accumulator */ uint16_t *ref_min; uint16_t *ref_max; uint16_t *ref; /* averaged reference (dead pixels filled) */ } mag160c_display_badmap_t; MAG160C_API void mag160c_display_badmap_init(mag160c_display_badmap_t *m, uint32_t w, uint32_t h); MAG160C_API void mag160c_display_badmap_destroy(mag160c_display_badmap_t *m); MAG160C_API mag160c_error_t mag160c_display_badmap_feed(mag160c_display_badmap_t *m, const uint16_t *frame); MAG160C_API mag160c_error_t mag160c_display_badmap_finalize(mag160c_display_badmap_t *m); MAG160C_API mag160c_error_t mag160c_display_badmap_correct(const mag160c_display_badmap_t *m, uint16_t *frame); /* MOG-style per-pixel reference tracking (anti-ghost): background pixels * (|live-ref| < thr) track drift slowly (ref += d/alpha); foreground pixels * are frozen so a static object is never absorbed into the reference. */ MAG160C_API void mag160c_display_ref_track(uint16_t *ref, const uint16_t *live, uint32_t n, int32_t thr, int32_t alpha); /* MOG tracking with self-healing: an *isolated* pixel stuck as foreground * for heal_frames (fewer than min_nbr foreground 8-neighbors) is a * reference error (startup noise, bad pixel) and is reset to the live * value; contiguous objects are never healed. */ MAG160C_API void mag160c_display_ref_track_heal(uint16_t *ref, const uint16_t *live, uint32_t w, uint32_t h, int32_t thr, int32_t alpha, uint8_t *fg_count, uint32_t heal_frames, uint32_t min_nbr); /* Flat-field (NUC) correction: out = live - (ref - mean(ref)). Removes the * fixed sensor mura so the absolute image is smooth; the reference must be * the fixed pattern only (object-free capture + frozen tracking). */ MAG160C_API mag160c_error_t mag160c_display_nuc(const uint16_t *live, const uint16_t *ref, uint32_t n, uint16_t *out); /* Re-align the reference after FFC(1): applies the median of (live-ref) * clamped to max_shift as a global offset (baseline shifts reach +1000). */ MAG160C_API mag160c_error_t mag160c_display_ref_rebase(uint16_t *ref, const uint16_t *live, uint32_t n, int32_t max_shift); /* ---- AGC ---------------------------------------------------------------- */ MAG160C_API mag160c_error_t mag160c_display_agc_range(const uint16_t *frame, uint32_t n, uint32_t lo_pct, uint32_t hi_pct, uint32_t *out_lo, uint32_t *out_hi); MAG160C_API mag160c_error_t mag160c_display_diff_span(const int32_t *diff, uint32_t n, uint32_t min_span, uint32_t max_span, uint32_t *out_span); /* ---- pseudo color ------------------------------------------------------- */ MAG160C_API void mag160c_display_ironbow(uint32_t v, uint8_t *r, uint8_t *g, uint8_t *b); /* ---- FFC scheduler (official demo cadence) ------------------------------ */ typedef struct mag160c_ffc_scheduler_t { uint32_t period; /* frames between FFC pairs (default 400) */ uint32_t gap; /* frames FFC(0) -> FFC(1) (default 9) */ uint32_t frames; /* frames since last FFC event */ uint32_t started; /* first FFC(1) already sent */ uint32_t wait1; /* FFC(0) sent, waiting to send FFC(1) */ } mag160c_ffc_scheduler_t; MAG160C_API void mag160c_ffc_scheduler_init(mag160c_ffc_scheduler_t *s, uint32_t period, uint32_t gap); /* Returns -1 (nothing) or an FFC param (0/1) to send after this frame. */ MAG160C_API int32_t mag160c_ffc_scheduler_tick(mag160c_ffc_scheduler_t *s); /* Force an immediate FFC pair: returns 0 (send FFC(0) now), then tick() * returns 1 (send FFC(1)) after `gap` frames. */ MAG160C_API int32_t mag160c_ffc_scheduler_trigger(mag160c_ffc_scheduler_t *s); /* ---- two-point linear temperature calibration --------------------------- */ /* counts = a*temp + b from two known (counts, tempC) points. */ MAG160C_API mag160c_error_t mag160c_temp_calibrate_linear(double counts0, double temp0, double counts1, double temp1, double *out_a, double *out_b); MAG160C_API double mag160c_temp_apply_linear(double counts, double a, double b); #ifdef __cplusplus } #endif #endif /* MAG160C_DISPLAY_H */