Files

119 lines
6.0 KiB
C

/*
* 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 */