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; } }