Skip to content

Commit 5bebbf6

Browse files
committed
Add hard hat detection boxes to AI Safety construction mode
- Add second detect('hard hat') call in analyzeConstructionSafety() - Draw cyan bounding boxes with '⛑ Hard Hat' labels on each detected helmet - Hard hat boxes drawn separately from person boxes for clear visual distinction - Person boxes: green (safe) / red dashed (unsafe) - Hard hat boxes: bright cyan with black text label
1 parent ef72c00 commit 5bebbf6

File tree

1 file changed

+54
-6
lines changed

1 file changed

+54
-6
lines changed

16-ai-safety/app.js

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -381,16 +381,37 @@ If you see a hard hat AND a safety vest, safe=true. Otherwise safe=false.`;
381381
return null;
382382
}
383383

384+
// Step 1b: Detect hard hats in the frame
385+
let hardHatDetections = [];
386+
try {
387+
updateStatus('Detecting hard hats...');
388+
window.reasoningConsole.logApiCall('/detect (hard hat)', 0);
389+
const hatStart = Date.now();
390+
const hatResult = await client.detect(imageDataUrl, 'hard hat');
391+
hardHatDetections = (hatResult.objects || []).map(h => ({
392+
x_min: h.x_min || 0,
393+
y_min: h.y_min || 0,
394+
x_max: h.x_max || 0,
395+
y_max: h.y_max || 0
396+
}));
397+
const hatLatency = Date.now() - hatStart;
398+
window.reasoningConsole.logApiCall('/detect (hard hat)', hatLatency);
399+
window.reasoningConsole.logInfo(`Detected ${hardHatDetections.length} hard hat(s) [${hatLatency}ms]`);
400+
} catch (e) {
401+
window.reasoningConsole.logError('Hard hat detection failed: ' + e.message);
402+
}
403+
384404
if (detections.length === 0) {
385405
// No people — scene is safe
386-
drawPersonOverlays([], imageDataUrl);
406+
drawPersonOverlays([], imageDataUrl, hardHatDetections);
387407
return {
388408
safetyRating: 5,
389409
status: 'all_clear',
390410
primaryConcern: 'No personnel detected',
391411
recommendedAction: 'Continue monitoring',
392412
detectedHazards: [],
393-
people: []
413+
people: [],
414+
hardHats: hardHatDetections
394415
};
395416
}
396417

@@ -443,7 +464,7 @@ If you see a hard hat AND a safety vest, safe=true. Otherwise safe=false.`;
443464
}
444465

445466
// Step 3: Draw visual overlays + update summary
446-
drawPersonOverlays(people, imageDataUrl);
467+
drawPersonOverlays(people, imageDataUrl, hardHatDetections);
447468
drawCanvasSummaryBadge(people);
448469
updatePPESummary(people);
449470

@@ -490,7 +511,8 @@ If you see a hard hat AND a safety vest, safe=true. Otherwise safe=false.`;
490511
primaryConcern: concern,
491512
recommendedAction: action,
492513
detectedHazards: hazards,
493-
people: people
514+
people: people,
515+
hardHats: hardHatDetections
494516
};
495517
}
496518

@@ -536,10 +558,11 @@ If you see a hard hat AND a safety vest, safe=true. Otherwise safe=false.`;
536558
}
537559
}
538560

539-
function drawPersonOverlays(people, imageDataUrl) {
561+
function drawPersonOverlays(people, imageDataUrl, hardHats) {
540562
overlayCtx.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height);
563+
hardHats = hardHats || [];
541564

542-
if (people.length === 0) return;
565+
if (people.length === 0 && hardHats.length === 0) return;
543566

544567
// Get image dimensions for coordinate scaling
545568
const img = new Image();
@@ -619,6 +642,31 @@ If you see a hard hat AND a safety vest, safe=true. Otherwise safe=false.`;
619642
});
620643
});
621644

645+
// Draw hard hat detection boxes
646+
hardHats.forEach(function(hat) {
647+
const hx = hat.x_min * iw * scaleX;
648+
const hy = hat.y_min * ih * scaleY;
649+
const hw = (hat.x_max - hat.x_min) * iw * scaleX;
650+
const hh = (hat.y_max - hat.y_min) * ih * scaleY;
651+
652+
// Bright cyan box for hard hats
653+
overlayCtx.strokeStyle = '#00E5FF';
654+
overlayCtx.lineWidth = 2;
655+
overlayCtx.setLineDash([]);
656+
overlayCtx.strokeRect(hx, hy, hw, hh);
657+
658+
// Label
659+
const hatLabel = '⛑ Hard Hat';
660+
overlayCtx.font = 'bold 11px sans-serif';
661+
const hatLabelW = overlayCtx.measureText(hatLabel).width + 8;
662+
overlayCtx.fillStyle = '#00E5FF';
663+
overlayCtx.beginPath();
664+
overlayCtx.roundRect(hx, hy - 16, hatLabelW, 16, 3);
665+
overlayCtx.fill();
666+
overlayCtx.fillStyle = '#000';
667+
overlayCtx.fillText(hatLabel, hx + 4, hy - 3);
668+
});
669+
622670
// Overall border based on safety
623671
const unsafeCount = people.filter(p => !p.safe).length;
624672
if (unsafeCount > 0) {

0 commit comments

Comments
 (0)