docs: add quixzoom-auth-core product to AAMOS
- Product documentation in docs/products/ - Updated MEMORY.md with product info - quiXzoom Auth Core as AAMOS Identity product
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* POST /v1/segment — Segmentering (pixel-level)
|
||||
* Använder en enkel färg-baserad segmentering som proxy för riktig AI-segmentering
|
||||
* med fallback till AI-beskrivning av bildregioner.
|
||||
*/
|
||||
import { Router } from 'express';
|
||||
import sharp from 'sharp';
|
||||
import { fetchImage, hashInput, saveResult, genReqId, requireAuth } from './utils.mjs';
|
||||
|
||||
const router = Router();
|
||||
|
||||
// Simple color-based segmentation as proxy
|
||||
async function segmentImage(buffer) {
|
||||
const { data, info } = await sharp(buffer).resize(256, 256).raw().toBuffer({ resolveWithObject: true });
|
||||
const w = info.width, h = info.height;
|
||||
const segments = [];
|
||||
const visited = new Uint8Array(w * h);
|
||||
const threshold = 30;
|
||||
|
||||
function colorDist(i, j) {
|
||||
const r1 = data[i*3], g1 = data[i*3+1], b1 = data[i*3+2];
|
||||
const r2 = data[j*3], g2 = data[j*3+1], b2 = data[j*3+2];
|
||||
return Math.abs(r1-r2) + Math.abs(g1-g2) + Math.abs(b1-b2);
|
||||
}
|
||||
|
||||
for (let y = 0; y < h; y++) {
|
||||
for (let x = 0; x < w; x++) {
|
||||
const idx = y * w + x;
|
||||
if (visited[idx]) continue;
|
||||
// Flood fill from this pixel
|
||||
const queue = [idx];
|
||||
const region = [];
|
||||
visited[idx] = 1;
|
||||
const seedColor = { r: data[idx*3], g: data[idx*3+1], b: data[idx*3+2] };
|
||||
while (queue.length) {
|
||||
const cur = queue.pop();
|
||||
region.push(cur);
|
||||
const cx = cur % w, cy = Math.floor(cur / w);
|
||||
for (let dy = -1; dy <= 1; dy++) {
|
||||
for (let dx = -1; dx <= 1; dx++) {
|
||||
const nx = cx + dx, ny = cy + dy;
|
||||
if (nx < 0 || nx >= w || ny < 0 || ny >= h) continue;
|
||||
const nidx = ny * w + nx;
|
||||
if (visited[nidx]) continue;
|
||||
if (colorDist(idx, nidx) < threshold) {
|
||||
visited[nidx] = 1;
|
||||
queue.push(nidx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (region.length > 200) {
|
||||
const xs = region.map(i => i % w);
|
||||
const ys = region.map(i => Math.floor(i / w));
|
||||
const avgR = region.reduce((s, i) => s + data[i*3], 0) / region.length;
|
||||
const avgG = region.reduce((s, i) => s + data[i*3+1], 0) / region.length;
|
||||
const avgB = region.reduce((s, i) => s + data[i*3+2], 0) / region.length;
|
||||
segments.push({
|
||||
id: segments.length + 1,
|
||||
pixel_count: region.length,
|
||||
coverage_pct: parseFloat((region.length / (w * h) * 100).toFixed(2)),
|
||||
bbox: {
|
||||
x: Math.min(...xs), y: Math.min(...ys),
|
||||
width: Math.max(...xs) - Math.min(...xs),
|
||||
height: Math.max(...ys) - Math.min(...ys)
|
||||
},
|
||||
avg_color: { r: Math.round(avgR), g: Math.round(avgG), b: Math.round(avgB) },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return segments.sort((a, b) => b.pixel_count - a.pixel_count).slice(0, 10);
|
||||
}
|
||||
|
||||
router.post('/', requireAuth, async (req, res) => {
|
||||
const requestId = genReqId();
|
||||
const start = Date.now();
|
||||
try {
|
||||
const { image_url, image_base64, method = 'color' } = req.body || {};
|
||||
const img = await fetchImage({ image_url, image_base64 });
|
||||
const inputHash = hashInput(img.buffer);
|
||||
|
||||
const segments = await segmentImage(img.buffer);
|
||||
const totalCoverage = segments.reduce((s, seg) => s + seg.coverage_pct, 0);
|
||||
const confidence = Math.min(0.95, parseFloat((0.5 + segments.length * 0.05).toFixed(4)));
|
||||
|
||||
const result = {
|
||||
ok: true,
|
||||
endpoint: 'segment',
|
||||
request_id: requestId,
|
||||
method,
|
||||
segments_found: segments.length,
|
||||
total_coverage_pct: parseFloat(totalCoverage.toFixed(2)),
|
||||
segments,
|
||||
inference_time_ms: Date.now() - start,
|
||||
};
|
||||
|
||||
await saveResult('segment', requestId, inputHash, result, confidence, { method, source: img.source });
|
||||
res.json(result);
|
||||
} catch (e) {
|
||||
console.error('[segment]', e);
|
||||
res.status(500).json({ ok: false, error: e.message, request_id: requestId });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user