| <!DOCTYPE html> |
| <html lang="en"> |
|
|
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Chassis OCR</title> |
| <link rel="manifest" href="manifest.json"> |
| <link rel="icon" type="image/png" sizes="192x192" href="icons/icon-192.png"> |
| <meta name="theme-color" content="#2563eb"> |
| <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=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> |
| <link rel="stylesheet" href="app.css"> |
| <script src="https://unpkg.com/html5-qrcode" type="text/javascript"></script> |
| </head> |
|
|
| <body> |
| <header class="header"> |
| <div class="header-inner"> |
| <div class="header-brand"> |
| <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" |
| stroke-linecap="round" stroke-linejoin="round"> |
| <rect x="2" y="5" width="20" height="14" rx="2" /> |
| <line x1="2" y1="10" x2="22" y2="10" /> |
| </svg> |
| <span>Chassis OCR</span> |
| </div> |
| <div class="header-right"> |
| <span id="connection-badge" class="status-dot online"></span> |
| <button id="pwa-install-btn" class="btn-install hidden">Add to Home Screen</button> |
| </div> |
| </div> |
| </header> |
|
|
| <main class="main"> |
| <div class="two-col"> |
|
|
| |
| <div class="panel"> |
| <div class="panel-header"> |
| <h2>Input</h2> |
| </div> |
| <div class="panel-body"> |
| <div class="field"> |
| <label>Source</label> |
| <div class="seg-control"> |
| <button class="seg-btn active" data-mode="dataset">Dataset</button> |
| <button class="seg-btn" data-mode="upload">Upload</button> |
| <button class="seg-btn" data-mode="camera">Camera</button> |
| </div> |
| </div> |
|
|
| |
| <div id="mode-dataset" class="mode-panel"> |
| <div class="field"> |
| <label for="dataset-pair-select">Test Pair</label> |
| <select id="dataset-pair-select" class="select"> |
| <option value="">Loading...</option> |
| </select> |
| </div> |
| </div> |
|
|
| |
| <div id="mode-upload" class="mode-panel hidden"> |
| <div class="field"> |
| <label>Barcode Image</label> |
| <div class="dropzone" id="barcode-dropzone"> |
| <input type="file" id="barcode-file" accept="image/*" class="hidden-input"> |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" |
| stroke-width="1.5"> |
| <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M17 8l-5-5-5 5M12 3v12" /> |
| </svg> |
| <span id="barcode-file-name">Drop or click to upload</span> |
| </div> |
| </div> |
| <div class="field"> |
| <label>Chassis Image</label> |
| <div class="dropzone" id="chassis-dropzone"> |
| <input type="file" id="chassis-file" accept="image/*" class="hidden-input"> |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" |
| stroke-width="1.5"> |
| <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M17 8l-5-5-5 5M12 3v12" /> |
| </svg> |
| <span id="chassis-file-name">Drop or click to upload</span> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="mode-camera" class="mode-panel hidden"> |
| <div class="camera-step" id="cam-step-1"> |
| <div class="step-label">Step 1 β Scan Barcode</div> |
| <div id="barcode-reader" class="cam-view"></div> |
| <button id="start-barcode-cam" class="btn btn-secondary">Start Camera</button> |
| </div> |
| <div class="camera-step disabled" id="cam-step-2"> |
| <div class="step-label">Step 2 β Capture Chassis</div> |
| <div class="chassis-video-wrap"> |
| <video id="chassis-video" autoplay playsinline class="cam-view hidden"></video> |
| <div id="chassis-guide-box" class="guide-box hidden"></div> |
| </div> |
| <canvas id="chassis-canvas" class="hidden"></canvas> |
| <div id="chassis-snap-container" class="hidden"> |
| <img id="chassis-snap-img" class="snap-preview" src="" alt="Chassis snapshot"> |
| </div> |
| <div class="cam-actions"> |
| <button id="start-chassis-cam" class="btn btn-secondary" disabled>Start Camera</button> |
| <button id="capture-chassis" class="btn btn-primary hidden">Capture</button> |
| <button id="reset-chassis-snap" class="btn btn-ghost hidden">Retake</button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="field"> |
| <label for="barcode-val">Expected Value (Barcode)</label> |
| <input type="text" id="barcode-val" class="input" placeholder="Auto-filled or enter manually"> |
| </div> |
|
|
| <button id="run-ocr-btn" class="btn btn-primary btn-full" disabled> |
| <span class="spinner hidden"></span> |
| Run OCR & Compare |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div class="panel"> |
| <div class="panel-header"> |
| <h2>Result</h2> |
| </div> |
| <div class="panel-body" id="result-body"> |
| <div id="result-empty" class="empty-state"> |
| <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" |
| stroke-width="1.5"> |
| <circle cx="12" cy="12" r="10" /> |
| <line x1="12" y1="8" x2="12" y2="12" /> |
| <line x1="12" y1="16" x2="12.01" y2="16" /> |
| </svg> |
| <p>Select a pair and run OCR to see results.</p> |
| </div> |
|
|
| <div id="result-content" class="hidden"> |
| <div id="result-banner" class="result-banner"> |
| <div id="banner-icon" class="banner-icon-char"></div> |
| <div> |
| <div id="banner-title" class="banner-title"></div> |
| <div id="banner-sub" class="banner-sub"></div> |
| </div> |
| </div> |
|
|
| <table class="result-table"> |
| <tr> |
| <td class="rt-label">Expected</td> |
| <td class="rt-value mono" id="res-expected">β</td> |
| </tr> |
| <tr> |
| <td class="rt-label">Raw OCR</td> |
| <td class="rt-value mono" id="res-raw">β</td> |
| </tr> |
| <tr> |
| <td class="rt-label">After Correction</td> |
| <td class="rt-value mono" id="res-corrected">β</td> |
| </tr> |
| <tr> |
| <td class="rt-label">Confidence</td> |
| <td class="rt-value" id="res-conf">β</td> |
| </tr> |
| <tr> |
| <td class="rt-label">Best Filter</td> |
| <td class="rt-value" id="res-filter">β</td> |
| </tr> |
| </table> |
|
|
| <div class="section-title">Preprocessing Steps</div> |
| <div class="pre-tabs" id="pre-tabs"> |
| <button class="pre-tab active" data-pre="original">Original</button> |
| <button class="pre-tab" data-pre="clahe">CLAHE</button> |
| <button class="pre-tab" data-pre="bilateral">Bilateral</button> |
| <button class="pre-tab" data-pre="otsu">Otsu</button> |
| <button class="pre-tab" data-pre="adaptive">Adaptive</button> |
| </div> |
| <div class="pre-img-wrap"> |
| <img id="pre-img" src="" alt="Preprocessing step"> |
| <div class="pre-ocr-label">OCR read: <span id="pre-ocr-text" class="mono">β</span></div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| </div> |
| </main> |
|
|
| <div id="toasts" class="toast-stack"></div> |
|
|
| <script src="app.js"></script> |
| </body> |
|
|
| </html> |