119 lines
6.0 KiB
C
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 */
|