fwt_software/include/fgc/GatedCameraSource.h

92 lines
3.8 KiB
C++

#pragma once
#include "fgc/ExposurePolicy.h"
#include "fgc/ExposureStore.h"
#include "fgc/ICameraSource.h"
#include "fgc/ImageQuality.h"
#include <functional>
#include <memory>
#include <string>
namespace fgc {
// Outcome of one gated capture, for logging and the TUI.
struct CaptureReport {
bool captured = false; // a frame was delivered at all
bool degraded = false; // budget exhausted; this is the best effort
int attempts = 0;
std::string reason; // verdict of the attempt we kept
ImageMetrics metrics; // metrics of the frame we kept
CaptureSettings settings; // settings that produced it
double yaw_deg = 0.0, pitch_deg = 0.0;
};
// An ICameraSource that wraps another one and turns a single trigger() into
// "shoot, judge, correct, reshoot until acceptable", seeded from per-angle memory.
//
// It is a DECORATOR so that nothing above it changes: CaptureScheduler still just
// calls trigger(), and the accepted frame still reaches ImagePipeline through the
// ordinary frame callback. Because it depends only on ICameraSource plus the pure
// policy/metric modules, the entire retry loop is unit-testable against a fake
// camera - no hardware, no OpenCV.
class GatedCameraSource : public ICameraSource {
public:
struct Params {
bool enabled = true;
int max_attempts = 3;
int min_attempts = 1; // >1 always shoots extra and keeps the sharpest
int acquire_timeout_ms = 2000;
int settle_delay_ms = 0; // extra pause after the move, before attempt 1
CaptureSettings defaults; // used when the store has nothing
QualityParams quality;
PolicyParams policy;
};
// angle: where the gimbal is pointing now (degrees), used to key the store.
// now_ms: injectable clock, for deterministic tests.
GatedCameraSource(std::unique_ptr<ICameraSource> inner, ExposureStore* store, Params params,
std::function<std::pair<double, double>()> angle,
std::function<long long()> now_ms = {},
std::function<void(int)> sleep_ms = {});
~GatedCameraSource() override;
void open() override;
void close() override;
void start() override;
void stop() override;
bool trigger() override;
bool setFrameRate(double fps) override;
void setFrameCallback(FrameCallback cb) override;
int cameraCount() const override;
std::vector<CameraDeviceInfo> deviceInfo() override;
// Pass-throughs, so the gate can itself be wrapped or inspected.
bool acquireFrame(Frame& out, int timeout_ms) override;
bool setExposure(double us) override;
bool setGain(double db) override;
bool setAutoExposureGain(bool on) override;
double currentGain() override;
// Result of the most recent trigger(), for the log and the TUI.
const CaptureReport& lastReport() const { return last_report_; }
// How many captures this session fell back to a best effort. A rising count is
// the signal that thresholds or the exposure limits need revisiting.
long long degradedTotal() const { return degraded_total_; }
private:
std::unique_ptr<ICameraSource> inner_;
ExposureStore* store_; // not owned; may be null
Params params_;
std::function<std::pair<double, double>()> angle_;
std::function<long long()> now_ms_;
std::function<void(int)> sleep_ms_;
FrameCallback callback_;
CaptureReport last_report_;
long long degraded_total_ = 0;
};
} // namespace fgc