Files
@ 9bb0eb587d5b
Branch filter:
Location: light9/web/calibrate/Light9Calibrate.ts - annotation
9bb0eb587d5b
4.1 KiB
video/MP2T
640x480 camera res
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a ae4b90efb55a | import debug from "debug";
import { css, html, LitElement } from "lit";
import { customElement, query, state } from "lit/decorators.js";
import { CollectorClient } from "../collector/CollectorClient";
import { getTopGraph } from "../RdfdbSyncedGraph";
import { SyncedGraph } from "../SyncedGraph";
import { Light9Camera } from "./Light9Camera";
import { XyPlot } from "./XyPlot";
export { RdfdbSyncedGraph } from "../RdfdbSyncedGraph";
export { Light9Camera } from "./Light9Camera";
export { XyPlot } from "./XyPlot";
debug.enable("*");
const log = debug("calibrate");
async function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
@customElement("light9-calibrate")
export class Light9Calibrate extends LitElement {
graph!: SyncedGraph;
static styles = [
css`
button {
min-height: 3em;
min-width: 10em;
}
`,
];
collector: CollectorClient = new CollectorClient("calibrate");
@query("light9-camera", true) cam?: Light9Camera;
@query("xy-plot", true) plot?: XyPlot;
@state() device: string;
constructor() {
super();
this.device = "http://light9.bigasterisk.com/theater/vet/device/parR3";
getTopGraph().then((g) => {
this.graph = g;
});
}
render() {
return html`<rdfdb-synced-graph></rdfdb-synced-graph>
<h1>Calibrate</h1>
<light9-camera></light9-camera>
<p>Device to calibrate: [ ${this.device} ]</p>
<ol>
<li><button @click=${this.setToFull}>Set to full</button></li>
<li><button @click=${this.findSafeExposure}>Find safe exposure</button></li>
<li><button @click=${this.setToZero}>Set to 0</button></li>
<li><button @click=${this.markTare}>Mark tare</button></li>
<li><button @click=${this.calibrateLoop}>Calibrate loop</button></li>
</ol>
<xy-plot label="zebra pixels vs exposure"></xy-plot>
r/g/b/r*g*b lines ,x=send y=seen `;
}
async withButtonSpinner(ev: MouseEvent, fn: () => Promise<void>) {
const btn = ev.target as HTMLButtonElement;
try {
btn.disabled = true;
await fn();
} finally {
btn.disabled = false;
}
}
async setToFull(ev: MouseEvent) {
await this.withButtonSpinner(ev, async () => {
this.collector.updateSettings([
/// device,attr,value
[this.device, "http://light9.bigasterisk.com/color", "#ffffff"],
[this.device, "http://light9.bigasterisk.com/white", 1],
]);
});
}
async findSafeExposure(ev: MouseEvent) {
await this.withButtonSpinner(ev, async () => {
const gatherSample = async (expo: number) => {
await this.cam?.set("exposureTime", expo);
const settleUntil = Date.now() + 1000;
let miny = this.cam?.saturatedPixelCount!;
while (Date.now() < settleUntil) {
await sleep(50);
miny = Math.min(miny, this.cam?.saturatedPixelCount!);
}
this.plot!.insertPoint(expo, miny);
};
// todo: drive around without big skips, gradually slower, looking for the max workable expo
let fixedSteps = 8;
const expoMin = 1;
const expoMax = 200;
let expo = 0;
const data=this.plot!.data;
while (data.length < 20) {
if (data.length < fixedSteps + 1) {
expo = expoMin + ((expoMax - expoMin) / fixedSteps) * data.length;
} else {
let x2 = data.findIndex(([_, y]) => y > 2);
if (x2 < 1) x2 = 1;
const x1 = x2 - 1;
log(JSON.stringify([x1, data[x1], x2, data[x2]]));
expo = (data[x1][0] + data[x2][0]) / 2;
log(data);
}
await gatherSample(expo);
}
});
}
async setToZero(ev: MouseEvent) {
await this.withButtonSpinner(ev, async () => {
this.collector.updateSettings([
[this.device, "http://light9.bigasterisk.com/color", "#000000"],
[this.device, "http://light9.bigasterisk.com/white", 0],
]);
});
}
async markTare(ev: MouseEvent) {
await this.withButtonSpinner(ev, async () => {});
}
async calibrateLoop(ev: MouseEvent) {
await this.withButtonSpinner(ev, async () => {});
}
}
|