import { clamp } from "lodash";
import { sleep } from "./Light9Calibrate";
import { Light9Camera } from "./Light9Camera";
import { XyPlot } from "./XyPlot";
export class FindSafeExposure {
expoMin: number;
expoMax: number;
expo: number;
expoStep: number;
sameStateSteps: number;
constructor(public cam: Light9Camera, public plot: XyPlot) {
const fixedSteps = 5;
this.plot.clear();
this.expoMin = 1;
this.expoMax = 800;
this.expo = this.expoMin;
this.expoStep = (this.expoMax - this.expoMin) / fixedSteps;
this.sameStateSteps = 0;
}
async run() {
while (true) {
const currentOverexposed = await this.gatherSample();
this.step(currentOverexposed);
if (this.plot.data.length > 50 || Math.abs(this.expoStep) < 1) {
this.expo = this.expoMin;
await this.gatherSample();
break;
}
}
return this.expo;
}
step(currentOverexposed: number) {
const maxAllowedOverexposedPixels = 5;
const turnaroundScale = 0.6;
const stepsPerSide = 3;
const overexposed = currentOverexposed > maxAllowedOverexposedPixels;
if (this.expoStep > 0) {
if (overexposed) {
this.sameStateSteps += 1;
}
} else {
if (!overexposed) {
this.sameStateSteps += 1;
}
}
this.plot.setXMarklines([
{ txt: "min", x: this.expoMin },
{ txt: "max", x: this.expoMax },
{ txt: "expo", x: this.expo },
]);
const nextExpo = clamp(this.expo + this.expoStep, this.expoMin, this.expoMax);
if (this.sameStateSteps > stepsPerSide || nextExpo <= this.expoMin || nextExpo >= this.expoMax) {
if (this.expoStep > 0) {
this.expoMax = this.expo;
} else {
this.expoMin = this.expo;
}
this.expoStep = this.expoStep * -1 * turnaroundScale;
this.sameStateSteps = 0;
}
this.expo = clamp(this.expo + this.expoStep, this.expoMin, this.expoMax);
}
async gatherSample() {
const settleMs = 200;
await this.cam.set("exposureTime", this.expo);
const settleUntil = Date.now() + settleMs;
let miny = this.cam.saturatedPixelCount!;
while (Date.now() < settleUntil) {
await sleep(1000 / this.cam.videoSettings.frameRate);
miny = Math.min(miny, this.cam.saturatedPixelCount!);
}
this.plot!.insertPoint(this.expo, clamp(miny, 0, 100));
return miny;
}
}