Otsu (bisheriges Verfahren) meldete am echten Foto des Auftraggebers (~20 Schrauben auf Leder, unter 1% Flaechenanteil) 76712 statt rund zwanzig - Otsu taugt nur bei etwa gleich grossen Objekt-/ Untergrundflaechen. countObjects() vergleicht jetzt jeden Bildpunkt mit einem oertlichen Hintergrund (Kastenfilter ueber Summenbild, Radius max(Breite,Hoehe)/12), was Ausleuchtungsunterschiede abfaengt und am echten Foto 18 statt 76712 liefert (Test in test/count-objects-photo.test.js, ~30-49ms Laufzeit). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
58 lines
2.3 KiB
JavaScript
58 lines
2.3 KiB
JavaScript
// Prueffall am echten Foto des Auftraggebers (siehe
|
|
// .superpowers/sdd/counting-rework-report.md): Otsu allein scheiterte hier,
|
|
// weil die Schrauben unter einem Prozent der Bildflaeche belegen - Otsu
|
|
// rutscht in so einem Fall auf den hoechsten Helligkeitswert und erklaert nur
|
|
// die hellsten Punkte der Ledernarbung zum Objekt. Die fruehere Fassung
|
|
// meldete an genau diesem Bild 76712 statt der rund zwanzig tatsaechlich
|
|
// ausgelegten Schrauben. Dieser Test schuetzt vor einem Rueckfall in dieses
|
|
// Verhalten.
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { countObjects } from '../src/count-objects.js';
|
|
import {
|
|
SCREWS_WIDTH,
|
|
SCREWS_HEIGHT,
|
|
SCREWS_GRAY_BASE64,
|
|
} from './fixtures/screws-photo.js';
|
|
|
|
/**
|
|
* Baut aus dem Base64-kodierten Graustufenraster ein ImageData-artiges
|
|
* Objekt: Graustufenwert auf R, G und B gelegt, Alpha 255 - wie eine echte
|
|
* Kameraaufnahme ohne Farbinformation.
|
|
*/
|
|
function grayscaleImage(width, height, base64) {
|
|
const gray = Buffer.from(base64, 'base64');
|
|
const data = new Uint8ClampedArray(width * height * 4);
|
|
for (let p = 0, i = 0; p < width * height; p += 1, i += 4) {
|
|
const value = gray[p];
|
|
data[i] = value;
|
|
data[i + 1] = value;
|
|
data[i + 2] = value;
|
|
data[i + 3] = 255;
|
|
}
|
|
return { width, height, data };
|
|
}
|
|
|
|
test('echtes Foto (~20 Festplattenschrauben auf Leder) ergibt eine Zahl zwischen 15 und 24', () => {
|
|
const imageData = grayscaleImage(SCREWS_WIDTH, SCREWS_HEIGHT, SCREWS_GRAY_BASE64);
|
|
|
|
const start = performance.now();
|
|
const result = countObjects(imageData);
|
|
const durationMs = performance.now() - start;
|
|
|
|
// Nur zur Beobachtung im Testlauf, keine Zusicherung ueber die Konsole -
|
|
// die Laufzeit selbst wird unten geprueft.
|
|
console.log(`countObjects(screws-photo) dauerte ${durationMs.toFixed(2)} ms`);
|
|
|
|
assert.ok(
|
|
result.count >= 15 && result.count <= 24,
|
|
`erwartet 15..24, erhalten ${result.count} (fruehere Fassung meldete 76712)`,
|
|
);
|
|
|
|
// Soll mehrmals je Sekunde laufen koennen (laufende Anzeige waehrend die
|
|
// Kamera laeuft) - grosszuegige Grenze, die auf langsamerer Hardware nicht
|
|
// faelschlich anschlaegt, aber ein grundlegend zu langsames Verfahren
|
|
// (z. B. eine versehentlich quadratische Rechnung) auffangen wuerde.
|
|
assert.ok(durationMs < 500, `erwartet unter 500 ms, gemessen ${durationMs.toFixed(2)} ms`);
|
|
});
|