Spaces:
Sleeping
Sleeping
Add SIFT+FLANN registration, Siamese U-Net, multi-scale detection, ExG vegetation, Hybrid AI mode, confidence maps
aa4d14b | <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>AI Change Detection</title> | |
| <link rel="stylesheet" href="/static/css/style.css?v=25" /> | |
| </head> | |
| <body> | |
| <div class="app"> | |
| <!-- Login view --> | |
| <section id="view-login" class="view"> | |
| <div class="auth-container"> | |
| <div class="auth-logo"> | |
| <div class="auth-logo-icon"> | |
| <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z"/></svg> | |
| </div> | |
| <span>AI Change Detection</span> | |
| </div> | |
| <div class="card"> | |
| <h2>Welcome back</h2> | |
| <p class="sub">Sign in to your account to continue.</p> | |
| <div id="login-error" class="alert alert-error hidden"></div> | |
| <form id="form-login"> | |
| <div class="form-group"> | |
| <label for="login-email">Email</label> | |
| <input type="email" id="login-email" required placeholder="you@example.com" /> | |
| </div> | |
| <div class="form-group"> | |
| <label for="login-password">Password</label> | |
| <div class="input-password-wrap"> | |
| <input type="password" id="login-password" required placeholder="Enter your password" /> | |
| <button type="button" class="password-toggle" data-target="login-password" aria-label="Toggle password visibility"> | |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="auth-actions"> | |
| <button type="submit" class="btn btn-primary btn-block">Sign in</button> | |
| </div> | |
| </form> | |
| <p class="forgot-link"><a href="#" data-view="forgot">Forgot your password?</a></p> | |
| <p class="toggle-auth">Don't have an account? <a href="#" data-view="register">Create one</a></p> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Register view --> | |
| <section id="view-register" class="view"> | |
| <div class="auth-container"> | |
| <div class="auth-logo"> | |
| <div class="auth-logo-icon"> | |
| <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z"/></svg> | |
| </div> | |
| <span>AI Change Detection</span> | |
| </div> | |
| <div class="card"> | |
| <h2>Create account</h2> | |
| <p class="sub">Register to save and manage your detection runs.</p> | |
| <div id="register-error" class="alert alert-error hidden"></div> | |
| <form id="form-register"> | |
| <div class="form-group"> | |
| <label for="register-name">Full name</label> | |
| <input type="text" id="register-name" placeholder="Your name" /> | |
| </div> | |
| <div class="form-group"> | |
| <label for="register-email">Email</label> | |
| <input type="email" id="register-email" required placeholder="you@example.com" /> | |
| </div> | |
| <div class="form-group"> | |
| <label for="register-password">Password</label> | |
| <div class="input-password-wrap"> | |
| <input type="password" id="register-password" required placeholder="Min. 6 characters" minlength="6" /> | |
| <button type="button" class="password-toggle" data-target="register-password" aria-label="Toggle password visibility"> | |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="auth-actions"> | |
| <button type="submit" class="btn btn-primary btn-block">Create account</button> | |
| </div> | |
| </form> | |
| <p class="toggle-auth">Already have an account? <a href="#" data-view="login">Sign in</a></p> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Forgot password view --> | |
| <section id="view-forgot" class="view"> | |
| <div class="auth-container"> | |
| <div class="auth-logo"> | |
| <div class="auth-logo-icon"> | |
| <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z"/></svg> | |
| </div> | |
| <span>AI Change Detection</span> | |
| </div> | |
| <div class="card"> | |
| <div class="forgot-header-icon"> | |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg> | |
| </div> | |
| <h2 style="text-align:center;">Reset your password</h2> | |
| <p class="sub" style="text-align:center;">Enter the email you registered with and choose a new password.</p> | |
| <div id="forgot-error" class="alert alert-error hidden"></div> | |
| <div id="forgot-success" class="alert alert-success hidden"></div> | |
| <form id="form-forgot"> | |
| <div class="form-group"> | |
| <label for="forgot-email">Email address</label> | |
| <input type="email" id="forgot-email" required placeholder="you@example.com" /> | |
| </div> | |
| <div class="form-group"> | |
| <label for="forgot-password">New password</label> | |
| <div class="input-password-wrap"> | |
| <input type="password" id="forgot-password" required placeholder="Min. 6 characters" minlength="6" /> | |
| <button type="button" class="password-toggle" data-target="forgot-password" aria-label="Toggle password visibility"> | |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="auth-actions"> | |
| <button type="submit" class="btn btn-primary btn-block">Reset password</button> | |
| </div> | |
| </form> | |
| <div style="text-align:center;"> | |
| <a href="#" class="back-to-login" data-view="login"> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg> | |
| Back to sign in | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Dashboard view --> | |
| <section id="view-dashboard" class="view"> | |
| <div class="topbar"> | |
| <div class="nav-user"> | |
| <button type="button" class="nav-avatar" id="btn-avatar" aria-label="Account menu"> | |
| <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg> | |
| </button> | |
| <div class="nav-dropdown hidden" id="nav-dropdown"> | |
| <div class="nav-dropdown-email" id="user-email"></div> | |
| <div class="nav-dropdown-divider"></div> | |
| <button type="button" class="nav-dropdown-item" id="btn-logout"> | |
| <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg> | |
| Log out | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="dashboard-error" class="alert alert-error hidden"></div> | |
| <div id="dashboard-success" class="alert alert-success hidden"></div> | |
| <!-- Section 1: Upload / Detection --> | |
| <div class="card section-upload"> | |
| <div class="card-header"> | |
| <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--grad-start)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg> | |
| <h3>Upload / Detection</h3> | |
| </div> | |
| <form id="form-detect"> | |
| <div class="location-row"> | |
| <div class="form-group"> | |
| <label for="detect-zone"> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z"/><circle cx="12" cy="10" r="3"/></svg> | |
| Zone | |
| </label> | |
| <select id="detect-zone"> | |
| <option value="">— Select Zone —</option> | |
| </select> | |
| </div> | |
| <div class="form-group"> | |
| <label for="detect-village"> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg> | |
| Village / Area | |
| </label> | |
| <select id="detect-village" disabled> | |
| <option value="">— Select Zone first —</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="upload-grid"> | |
| <div class="upload-zone" id="zone-before"> | |
| <input type="file" id="file-before" accept="image/png,image/jpeg,image/jpg" /> | |
| <div class="upload-icon"> | |
| <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg> | |
| </div> | |
| <label for="file-before">Before image <span class="dim">(older)</span></label> | |
| <div class="filename" id="name-before">No file chosen</div> | |
| <img class="upload-preview hidden" id="preview-before" alt="" /> | |
| </div> | |
| <div class="upload-zone" id="zone-after"> | |
| <input type="file" id="file-after" accept="image/png,image/jpeg,image/jpg" /> | |
| <div class="upload-icon"> | |
| <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg> | |
| </div> | |
| <label for="file-after">After image <span class="dim">(current)</span></label> | |
| <div class="filename" id="name-after">No file chosen</div> | |
| <img class="upload-preview hidden" id="preview-after" alt="" /> | |
| </div> | |
| </div> | |
| <div class="options-row"> | |
| <div class="form-group"> | |
| <label for="detect-title">Title</label> | |
| <input type="text" id="detect-title" value="Untitled run" placeholder="Run title" /> | |
| </div> | |
| <div class="form-group"> | |
| <label for="detect-method">Method</label> | |
| <select id="detect-method"> | |
| <option value="AI-Based Deep Learning">AI-Based Deep Learning</option> | |
| <option value="Image Difference">Image Difference</option> | |
| <option value="Feature-Based">Feature-Based</option> | |
| <option value="Hybrid Approach">Hybrid Approach</option> | |
| <option value="Hybrid AI">Hybrid AI (DL + Multi-Scale)</option> | |
| </select> | |
| </div> | |
| <div class="form-group checkbox-group"> | |
| <label><input type="checkbox" id="detect-registration" checked /> Image Registration</label> | |
| </div> | |
| <div class="form-group checkbox-group"> | |
| <label><input type="checkbox" id="detect-normalization" checked /> Radiometric Normalization</label> | |
| </div> | |
| </div> | |
| <div class="options-row"> | |
| <div class="form-group"> | |
| <label for="detect-sensitivity">Detection Sensitivity (0-1)</label> | |
| <input type="number" id="detect-sensitivity" min="0" max="1" step="0.05" value="0.5" /> | |
| </div> | |
| <div class="form-group"> | |
| <label for="detect-min-area">Min Region Area (px, optional)</label> | |
| <input type="number" id="detect-min-area" min="50" max="10000" step="50" placeholder="Auto" /> | |
| </div> | |
| </div> | |
| <div class="notify-row"> | |
| <div class="form-group checkbox-group"> | |
| <label><input type="checkbox" id="detect-notify" /> Notify via Email</label> | |
| </div> | |
| <div class="form-group notify-email-group hidden" id="notify-email-group"> | |
| <label for="notify-email"> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg> | |
| Recipient Email | |
| </label> | |
| <div class="notify-email-actions"> | |
| <input type="email" id="notify-email" placeholder="recipient@example.com" /> | |
| <button type="button" class="btn btn-secondary" id="notify-send-btn">Send Test</button> | |
| </div> | |
| <div class="notify-help" id="notify-help">Use Send Test to verify email delivery, or run detection to send the report automatically.</div> | |
| </div> | |
| </div> | |
| <div class="run-btn-wrap"> | |
| <button type="submit" class="btn btn-primary btn-lg" id="btn-run"> | |
| <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"/></svg> | |
| Run Detection | |
| </button> | |
| <span class="loading hidden" id="run-loading"><span class="spinner"></span> Analyzing images...</span> | |
| </div> | |
| </form> | |
| </div> | |
| <!-- Result View lives in a modal (opened from detection or history "View") --> | |
| <!-- Section 3: History View (tabular, click row to open result) --> | |
| <div class="card mt-2 section-history"> | |
| <div class="card-header"> | |
| <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--grad-start)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> | |
| <h3>History View</h3> | |
| </div> | |
| <div class="history-table-wrap"> | |
| <table class="history-table" id="history-table"> | |
| <thead> | |
| <tr> | |
| <th>Timestamp</th> | |
| <th>Before</th> | |
| <th>After</th> | |
| <th>Result</th> | |
| <th>Regions</th> | |
| <th>% Change</th> | |
| <th>Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody id="history-tbody"></tbody> | |
| </table> | |
| </div> | |
| <div id="history-empty" class="history-empty hidden">No detection runs yet. Upload images above to get started.</div> | |
| </div> | |
| </section> | |
| </div> | |
| <!-- Result modal (full-screen overlay opened from detection or history) --> | |
| <div class="result-modal-backdrop hidden" id="result-modal"> | |
| <div class="result-modal"> | |
| <div class="result-modal-header"> | |
| <h3 id="result-modal-title">Result View</h3> | |
| <button type="button" class="btn-close-modal" id="result-modal-close" aria-label="Close"> | |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> | |
| </button> | |
| </div> | |
| <div class="result-stats" id="result-stats"></div> | |
| <div class="zoom-slider-section"> | |
| <div class="zoom-controls"> | |
| <button type="button" class="btn btn-zoom" id="zoom-out" title="Zoom out" aria-label="Zoom out">−</button> | |
| <span class="zoom-level" id="zoom-level">100%</span> | |
| <button type="button" class="btn btn-zoom" id="zoom-in" title="Zoom in" aria-label="Zoom in">+</button> | |
| </div> | |
| <div class="zoom-wrapper" id="zoom-wrapper"> | |
| <div class="compare-slider compare-slider-zoomed" id="compare-slider"> | |
| <div class="compare-before"> | |
| <img id="compare-before-img" alt="Before" draggable="false" /> | |
| <span class="compare-label compare-label-left">Before</span> | |
| </div> | |
| <div class="compare-after" id="compare-after-clip"> | |
| <img id="compare-after-img" alt="Changes detected" draggable="false" /> | |
| <span class="compare-label compare-label-right">Changes</span> | |
| </div> | |
| <div class="compare-handle" id="compare-handle"> | |
| <div class="compare-handle-line"></div> | |
| <div class="compare-handle-knob"> | |
| <svg width="20" height="20" viewBox="0 0 20 20"><path d="M6 10l4-5v10z" fill="currentColor"/><path d="M14 10l-4-5v10z" fill="currentColor"/></svg> | |
| </div> | |
| <div class="compare-handle-line"></div> | |
| </div> | |
| <div class="region-highlight-overlay" id="region-highlight-overlay"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="regions-table-wrap"> | |
| <table class="regions-table" id="regions-table"> | |
| <thead> | |
| <tr> | |
| <th>#</th> | |
| <th>Change Type</th> | |
| <th>Sub-Type</th> | |
| <th>Severity</th> | |
| <th>Confidence</th> | |
| <th>Area (px)</th> | |
| <th>Coordinates</th> | |
| <th>Stories</th> | |
| <th>Height</th> | |
| <th>Stage</th> | |
| </tr> | |
| </thead> | |
| <tbody id="regions-tbody"></tbody> | |
| </table> | |
| <div class="pagination" id="regions-pagination"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Delete confirm modal --> | |
| <div class="modal-backdrop hidden" id="modal-delete"> | |
| <div class="modal"> | |
| <h3>Delete detection run?</h3> | |
| <p>This will permanently remove this run and its overlay image. This cannot be undone.</p> | |
| <div class="modal-actions"> | |
| <button class="btn btn-secondary" id="modal-cancel">Cancel</button> | |
| <button class="btn btn-danger" id="modal-confirm">Delete</button> | |
| </div> | |
| </div> | |
| </div> | |
| <script src="/static/js/app.js?v=40"></script> | |
| </body> | |
| </html> | |