water-meter-reader / index.html
kagabo's picture
Remove second model and emphasize visible settings
f8669ab verified
Raw
History Blame Contribute Delete
20 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#06111f" />
<meta name="description" content="A privacy-first AI system for detecting and reading water meters." />
<title>AquaVision AI | Water Meter Reader</title>
<link rel="preconnect" href="https://cdn.jsdelivr.net" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="styles.css" />
<script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.23.2/dist/ort.min.js"></script>
<script src="app.js" defer></script>
</head>
<body>
<div class="ambient ambient-one"></div>
<div class="ambient ambient-two"></div>
<header class="topbar">
<a class="brand" href="#" aria-label="AquaVision AI home">
<span class="brand-icon" aria-hidden="true">
<svg viewBox="0 0 24 24"><path d="M12 2.5S5.7 9.2 5.7 14.2a6.3 6.3 0 0 0 12.6 0C18.3 9.2 12 2.5 12 2.5Z"/><path d="M9.2 15.1a3.1 3.1 0 0 0 3 2.5"/></svg>
</span>
<span><strong>AquaVision</strong><small>AI METER INTELLIGENCE</small></span>
</a>
<nav class="app-tabs" aria-label="Application sections">
<button class="app-tab active" type="button" data-tab="reader" aria-selected="true">Reader</button>
<button class="app-tab" type="button" data-tab="performance" aria-selected="false">Performance</button>
<button class="app-tab" type="button" data-tab="guide" aria-selected="false">Settings guide</button>
<button class="app-tab" type="button" data-tab="history" aria-selected="false">History</button>
<button class="app-tab" type="button" data-tab="team" aria-selected="false">Team</button>
</nav>
<div class="topbar-actions">
<span class="system-pill"><i id="headerStatusDot"></i><span id="headerStatus">Initializing AI</span></span>
<a class="model-link" href="https://huggingface.co/kagabo/hf_water_meter_models" target="_blank" rel="noreferrer" aria-label="Open model on Hugging Face"><span>HF</span> Model</a>
<a class="icon-link" href="https://github.com/kai-lucky72/watermeter-vision" target="_blank" rel="noreferrer" aria-label="View source code">
<svg viewBox="0 0 24 24"><path d="M9 19c-4.5 1.4-4.5-2.2-6.3-2.7M15 21v-3.5c0-1 .1-1.4-.5-2 2.8-.3 5.7-1.4 5.7-6.2A4.9 4.9 0 0 0 19 5.9a4.5 4.5 0 0 0-.1-3.3s-1-.3-3.5 1.3a12 12 0 0 0-6.3 0C6.6 2.3 5.6 2.6 5.6 2.6a4.5 4.5 0 0 0-.1 3.3 4.9 4.9 0 0 0-1.3 3.4c0 4.8 3 5.9 5.8 6.2-.5.5-.7 1.1-.7 2V21"/></svg>
</a>
</div>
</header>
<main class="page-shell">
<div id="tab-reader" class="tab-panel active" data-tab-panel="reader">
<section class="intro">
<div>
<div class="kicker"><span></span> COMPUTER VISION SHOWCASE</div>
<h1>Water Meter AI Reader</h1>
<p>Upload a meter photo, run local AI detection, and review the extracted reading.</p>
</div>
<div class="model-card" aria-label="Model information">
<div class="model-card-head">
<span class="model-orbit"><i></i></span>
<div><small>ACTIVE MODEL</small><strong>YOLO12n · AquaVision</strong></div>
<span class="live-tag">LIVE</span>
</div>
<dl>
<div><dt>Input</dt><dd>960 x 960</dd></div>
<div><dt>Classes</dt><dd>12</dd></div>
<div><dt>Runtime</dt><dd>ONNX Web</dd></div>
</dl>
</div>
</section>
<section class="settings-strip glass-panel" aria-label="Detection settings">
<div class="settings-strip-title"><span class="step-number">02</span><div><small>AI CONTROL</small><h2>Detection settings</h2></div></div>
<label class="range-control">
<span><b>Detection confidence</b><output id="confidenceValue">10%</output></span>
<input id="confidenceSlider" type="range" min="5" max="80" value="10" step="1" />
<small>Lower finds more boxes; higher keeps stronger boxes.</small>
</label>
<label class="range-control">
<span><b>Overlap filtering</b><output id="iouValue">45%</output></span>
<input id="iouSlider" type="range" min="20" max="80" value="45" step="1" />
<small>Removes duplicate boxes covering the same digit.</small>
</label>
<label class="range-control unknown-control">
<span><b>Unknown threshold</b><output id="unknownValue">40%</output></span>
<input id="unknownSlider" type="range" min="20" max="90" value="40" step="1" />
<small>Uncertain retained digits become <b>?</b> for review.</small>
</label>
</section>
<section class="app-grid" aria-label="Water meter analysis workspace">
<aside class="control-column">
<article class="glass-panel upload-panel">
<div class="section-title">
<span class="step-number">01</span>
<div><small>INPUT</small><h2>Add meter image</h2></div>
<button id="clearButton" class="quiet-button" type="button" disabled>Clear</button>
</div>
<label id="dropZone" class="drop-zone" for="fileInput">
<input id="fileInput" type="file" accept="image/png,image/jpeg,image/webp" capture="environment" />
<span class="upload-symbol">
<svg viewBox="0 0 24 24"><path d="M12 16V4m0 0L7.5 8.5M12 4l4.5 4.5M5 14v4a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-4"/></svg>
</span>
<strong>Drop meter image here</strong>
<span>or click to browse / use camera</span>
<small>JPG, PNG, WEBP · max 20 MB</small>
</label>
<div class="photo-guide">
<svg viewBox="0 0 24 24"><path d="M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Z"/><path d="M12 16v-4m0-4h.01"/></svg>
<p><strong>For the best reading</strong> Center the display, reduce glare, and keep all digits sharp.</p>
</div>
</article>
<button id="runButton" class="analyze-button" type="button" disabled>
<span class="button-icon"><svg viewBox="0 0 24 24"><path d="m13 2-2 8h7l-9 12 2-8H4l9-12Z"/></svg></span>
<span><b id="runLabel">Preparing AI model</b><small>Run local computer vision</small></span>
<svg class="button-arrow" viewBox="0 0 24 24"><path d="m9 18 6-6-6-6"/></svg>
</button>
<div id="modelStatus" class="model-status" role="status" aria-live="polite"><i class="loading"></i>Loading model for first use...</div>
</aside>
<section class="results-column">
<article class="glass-panel viewer-panel">
<div class="viewer-toolbar">
<div class="section-title compact">
<span class="step-number">03</span>
<div><small>VISION OUTPUT</small><h2>Analysis viewer</h2></div>
</div>
<div class="viewer-actions">
<div class="view-switch" role="group" aria-label="Image view">
<button id="detectedViewButton" class="active" type="button">Detected</button>
<button id="originalViewButton" type="button">Original</button>
</div>
<button id="downloadButton" class="tool-button" type="button" disabled aria-label="Download annotated result">
<svg viewBox="0 0 24 24"><path d="M12 3v12m0 0 4-4m-4 4-4-4M5 19h14"/></svg><span>Export</span>
</button>
</div>
</div>
<div id="canvasWrap" class="canvas-wrap empty">
<canvas id="resultCanvas" aria-label="Water meter detection result"></canvas>
<div id="canvasPlaceholder" class="canvas-placeholder">
<span class="placeholder-reticle"><i></i><i></i><i></i><i></i><b></b></span>
<strong>Awaiting meter image</strong>
<p>Your AI detection result will appear in this workspace.</p>
</div>
<div class="scan-overlay" aria-hidden="true"><span></span></div>
<div id="imageBadge" class="image-badge">ORIGINAL PREVIEW</div>
</div>
<div class="metric-strip">
<div><small>INFERENCE</small><strong id="timing">--</strong></div>
<div><small>OBJECTS</small><strong id="detectionCount">--</strong></div>
<div><small>AVG. CONFIDENCE</small><strong id="averageConfidence">--</strong></div>
<div><small>DISPLAY WINDOW</small><strong id="windowStatus">--</strong></div>
</div>
</article>
<div class="result-grid">
<article class="reading-panel glass-panel">
<div class="result-heading"><span>EXTRACTED READING</span><b id="readingState">WAITING</b></div>
<div class="reading-line">
<output id="readingOutput">------</output>
<button id="copyButton" type="button" disabled aria-label="Copy meter reading">
<svg viewBox="0 0 24 24"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg>
</button>
</div>
<div class="raw-reading-row"><span>Raw model guess</span><output id="rawReadingOutput">------</output><b id="unknownCount">0 unknown</b></div>
<div class="quality-row">
<span>Reading quality</span>
<div class="quality-track"><i id="qualityBar"></i></div>
<strong id="qualityLabel">Not analyzed</strong>
</div>
</article>
<article class="digits-panel glass-panel">
<div class="result-heading"><span>DIGIT BREAKDOWN</span><b id="digitCount">0 DIGITS</b></div>
<div id="confidenceOutput" class="digit-list"><p class="empty-copy">Run an analysis to inspect every detected digit.</p></div>
</article>
</div>
</section>
</section>
</div>
<div id="tab-team" class="tab-panel" data-tab-panel="team">
<section class="team-section">
<div class="performance-heading">
<div>
<div class="kicker"><span></span> WMRS PROJECT TEAM</div>
<h2>Built by Y3 students.</h2>
<p>The Water Meter Reading System MVP was developed collaboratively by three Year 3 students.</p>
</div>
</div>
<div class="team-grid">
<article class="team-card"><span>BE</span><div><small>Y3 STUDENT</small><h3>Benite</h3><p>Water Meter Reading System project team member.</p></div></article>
<article class="team-card"><span>BS</span><div><small>Y3 STUDENT</small><h3>Beni Samuel</h3><p>Water Meter Reading System project team member.</p></div></article>
<article class="team-card"><span>KL</span><div><small>Y3 STUDENT</small><h3>Kagabo Lucky</h3><p>Water Meter Reading System project team member.</p></div></article>
</div>
<article class="team-project glass-panel"><div><small>OUR SHARED PROJECT</small><h3>Water Meter Reading System MVP</h3></div><p>Computer vision for detecting water meters, locating their reading windows, recognizing digits, and safely flagging uncertain readings for human review.</p></article>
</section>
</div>
<div id="tab-performance" class="tab-panel" data-tab-panel="performance">
<section class="performance-section" id="model-performance">
<div class="performance-heading">
<div>
<div class="kicker"><span></span> AQUAVISION YOLO12N VALIDATION EVIDENCE</div>
<h2>How well does the model perform?</h2>
<p>Aggregate object-detection results from the final clean YOLO12n model on the held-out 52-image combat test set.</p>
</div>
<a class="evidence-link" href="https://github.com/kai-lucky72/watermeter-vision" target="_blank" rel="noreferrer">View evaluation source <span></span></a>
</div>
<div class="metric-card-grid" aria-label="Model validation summary">
<article class="validation-metric"><div><span>PRECISION</span><strong>95.8<small>%</small></strong></div><p>Of the objects predicted, 95.8% were correct.</p><i style="--metric:95.8%"></i></article>
<article class="validation-metric"><div><span>RECALL</span><strong>95.8<small>%</small></strong></div><p>Of the labeled objects, 95.8% were found.</p><i style="--metric:95.8%"></i></article>
<article class="validation-metric featured"><div><span>mAP @ 0.50</span><strong>97.6<small>%</small></strong></div><p>Detection accuracy at 50% box overlap.</p><i style="--metric:97.6%"></i></article>
<article class="validation-metric"><div><span>mAP @ 0.50–0.95</span><strong>60.1<small>%</small></strong></div><p>Stricter score averaged across multiple overlaps.</p><i style="--metric:60.1%"></i></article>
</div>
<article class="metric-comparison glass-panel">
<div class="chart-header"><div><small>AGGREGATE COMPARISON</small><h3>Validation metrics</h3></div><span>52 test images · higher is better</span></div>
<div class="metric-bars" role="img" aria-label="Bar chart: Precision 95.8%, Recall 95.8%, mAP50 97.6%, mAP50-95 60.1%">
<div><span>Precision</span><b><i style="--value:95.8%"></i></b><strong>0.958</strong></div>
<div><span>Recall</span><b><i style="--value:95.8%"></i></b><strong>0.958</strong></div>
<div><span>mAP50</span><b><i style="--value:97.6%"></i></b><strong>0.976</strong></div>
<div><span>mAP50–95</span><b><i style="--value:60.1%"></i></b><strong>0.601</strong></div>
</div>
<div class="chart-axis"><span>0</span><span>0.25</span><span>0.50</span><span>0.75</span><span>1.00</span></div>
</article>
<div class="evidence-heading"><div><small>DETAILED CURVES</small><h3>Explore the validation plots</h3></div><p>Select a plot to open the original full-resolution evidence.</p></div>
<div class="evidence-grid">
<a class="evidence-card" href="metrics/precision-recall-curve.png" target="_blank"><img src="metrics/precision-recall-curve.png" alt="Precision-recall curve for all model classes" loading="lazy" /><div><strong>Precision–Recall curve</strong><span>Trade-off between precision and recall by class</span></div></a>
<a class="evidence-card" href="metrics/f1-curve.png" target="_blank"><img src="metrics/f1-curve.png" alt="F1 confidence curve for all model classes" loading="lazy" /><div><strong>F1–Confidence curve</strong><span>Balance of precision and recall across thresholds</span></div></a>
<a class="evidence-card" href="metrics/precision-curve.png" target="_blank"><img src="metrics/precision-curve.png" alt="Precision confidence curve for all model classes" loading="lazy" /><div><strong>Precision–Confidence</strong><span>Prediction correctness as confidence changes</span></div></a>
<a class="evidence-card" href="metrics/recall-curve.png" target="_blank"><img src="metrics/recall-curve.png" alt="Recall confidence curve for all model classes" loading="lazy" /><div><strong>Recall–Confidence</strong><span>Detection coverage as confidence changes</span></div></a>
<a class="evidence-card wide" href="metrics/confusion-matrix-normalized.png" target="_blank"><img src="metrics/confusion-matrix-normalized.png" alt="Normalized confusion matrix for meter, window, and digit classes" loading="lazy" /><div><strong>Normalized confusion matrix</strong><span>Where meter, window, and digit classes are correctly recognized or confused</span></div></a>
</div>
<p class="metrics-note"><strong>Interpretation note:</strong> These are object-detection validation metrics, not full meter-reading string accuracy. A complete reading also depends on finding the window, filtering digits, ordering them correctly, and applying the unknown rule.</p>
</section>
</div>
<div id="tab-history" class="tab-panel" data-tab-panel="history">
<section class="history-section">
<div class="history-heading">
<div><div class="kicker"><span></span> LOCAL SESSION</div><h2>Recent readings</h2></div>
<button id="clearHistoryButton" class="quiet-button" type="button">Clear history</button>
</div>
<div id="historyList" class="history-list"></div>
</section>
</div>
<div id="tab-guide" class="tab-panel" data-tab-panel="guide">
<section class="guide-section">
<div class="performance-heading guide-heading">
<div>
<div class="kicker"><span></span> SIMPLE SETUP GUIDE</div>
<h2>Choose settings with confidence.</h2>
<p>The model detects objects first, then the application filters duplicates and marks uncertain digits for review.</p>
</div>
<button id="applyRecommendedButton" class="evidence-link" type="button">Apply recommended settings</button>
</div>
<div class="guide-grid">
<article class="guide-card"><span>01</span><div><small>DETECTION CONFIDENCE</small><h3>Should this box be kept?</h3><p><b>Lower</b> values can recover faint digits but may add false boxes. <b>Higher</b> values show fewer, stronger detections.</p><strong>Recommended: 10%</strong></div></article>
<article class="guide-card"><span>02</span><div><small>OVERLAP / IoU</small><h3>Is this a duplicate box?</h3><p>Controls how strongly overlapping predictions are removed. It does not change what digit the model guessed.</p><strong>Recommended: 45%</strong></div></article>
<article class="guide-card"><span>03</span><div><small>UNKNOWN THRESHOLD</small><h3>Can this digit be trusted?</h3><p>A retained digit below this value becomes <b>?</b>. Its raw guess remains visible so a person can review it.</p><strong>Recommended: 40%</strong></div></article>
</div>
<article class="reading-flow glass-panel">
<div><span>1</span><strong>Detect</strong><small>YOLO finds meter, window and digit boxes.</small></div><i></i>
<div><span>2</span><strong>Filter</strong><small>Confidence and IoU remove weak or duplicate boxes.</small></div><i></i>
<div><span>3</span><strong>Order</strong><small>Digits inside the window are sorted left to right.</small></div><i></i>
<div><span>4</span><strong>Review</strong><small>Uncertain digits become ? without becoming a model class.</small></div>
</article>
<div class="guide-note"><strong>Important:</strong> Unknown is post-processing, not one of the 12 trained classes. Changing this setting does not change the model's validation mAP.</div>
</section>
<section class="tech-strip">
<div><span>01</span><p><strong>Private by design</strong>Your image never leaves the device.</p></div>
<div><span>02</span><p><strong>Custom YOLO model</strong>Trained for meter, window and digits.</p></div>
<div><span>03</span><p><strong>Browser inference</strong>ONNX Runtime Web, no paid server.</p></div>
</section>
</div>
</main>
<footer>
<div><strong>AquaVision AI</strong><span>Water Meter Reading System MVP</span></div>
<div class="footer-links"><a href="https://huggingface.co/kagabo/hf_water_meter_models" target="_blank" rel="noreferrer">Model</a><a href="https://github.com/kai-lucky72/watermeter-vision" target="_blank" rel="noreferrer">GitHub</a></div>
</footer>
<div id="toast" class="toast" role="status" aria-live="polite"></div>
</body>
</html>