Vision Uncertainty Quantifier

<!DOCTYPE html>


<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Vuq - Vision Uncertainty Quantifier | Quinsim-Vision</title>

<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">

<style>

* {

margin: 0;

padding: 0;

box-sizing: border-box;

}

body {

font-family: 'Inter', sans-serif;

background: #0f1115;

color: #f9fafb;

overflow: hidden;

}


/* Header */

.header {

background: #1a1d24;

border-bottom: 1px solid #374151;

padding: 16px 24px;

display: flex;

align-items: center;

justify-content: space-between;

height: 73px;

}


.header-left {

display: flex;

align-items: center;

gap: 32px;

}


.logo {

font-size: 20px;

font-weight: 700;

background: linear-gradient(to right, #3b82f6, #8b5cf6);

-webkit-background-clip: text;

-webkit-text-fill-color: transparent;

background-clip: text;

}


.breadcrumb {

color: #9ca3af;

font-size: 14px;

display: flex;

align-items: center;

gap: 8px;

}


.breadcrumb .active {

color: #f9fafb;

}


.header-right {

display: flex;

align-items: center;

gap: 16px;

}


.icon-btn {

background: none;

border: none;

color: #9ca3af;

cursor: pointer;

padding: 8px;

transition: color 0.2s;

}


.icon-btn:hover {

color: #f9fafb;

}


.btn-secondary {

background: #252932;

border: none;

color: #f9fafb;

padding: 8px 16px;

border-radius: 8px;

font-size: 14px;

cursor: pointer;

transition: background 0.2s;

}


.btn-secondary:hover {

background: #2d323d;

}


/* Main Layout */

.main-container {

display: flex;

height: calc(100vh - 73px);

}


/* Left Panel */

.left-panel {

flex: 1;

padding: 24px;

display: flex;

flex-direction: column;

}


.image-container {

background: #1a1d24;

border: 1px solid #374151;

border-radius: 8px;

flex: 1;

display: flex;

flex-direction: column;

overflow: hidden;

}


.image-display {

flex: 1;

display: flex;

align-items: center;

justify-content: center;

position: relative;

padding: 16px;

}


.upload-zone {

text-align: center;

}


.upload-icon {

width: 64px;

height: 64px;

background: #252932;

border-radius: 50%;

display: flex;

align-items: center;

justify-content: center;

margin: 0 auto 16px;

}


.upload-icon svg {

width: 32px;

height: 32px;

stroke: #3b82f6;

}


.upload-zone h3 {

font-size: 18px;

margin-bottom: 8px;

}


.upload-zone p {

color: #9ca3af;

font-size: 14px;

margin-bottom: 16px;

}


.btn-primary {

background: #3b82f6;

border: none;

color: #f9fafb;

padding: 10px 24px;

border-radius: 8px;

font-size: 14px;

font-weight: 500;

cursor: pointer;

transition: background 0.2s;

}


.btn-primary:hover {

background: #2563eb;

}


.btn-primary:disabled {

background: #374151;

cursor: not-allowed;

}


.upload-hint {

color: #9ca3af;

font-size: 12px;

margin-top: 16px;

}


#uploadInput {

display: none;

}


#uploadedImage {

max-width: 100%;

max-height: 100%;

object-fit: contain;

display: none;

}


.uncertainty-overlay {

position: absolute;

top: 0;

left: 0;

right: 0;

bottom: 0;

pointer-events: none;

display: none;

background:

radial-gradient(circle at 30% 40%, rgba(239, 68, 68, 0.4) 0%, transparent 40%),

radial-gradient(circle at 70% 60%, rgba(239, 68, 68, 0.3) 0%, transparent 35%),

radial-gradient(circle at 50% 80%, rgba(239, 68, 68, 0.2) 0%, transparent 30%);

mix-blend-mode: multiply;

}


.image-controls {

background: #252932;

padding: 12px 16px;

border-top: 1px solid #374151;

display: none;

justify-content: space-between;

align-items: center;

}


.control-btn {

background: none;

border: none;

color: #9ca3af;

font-size: 14px;

cursor: pointer;

display: flex;

align-items: center;

gap: 8px;

transition: color 0.2s;

}


.control-btn:hover {

color: #f9fafb;

}


.control-btn:disabled {

opacity: 0.5;

cursor: not-allowed;

}


/* Right Sidebar */

.right-sidebar {

width: 420px;

background: #1a1d24;

border-left: 1px solid #374151;

display: flex;

flex-direction: column;

overflow-y: auto;

}


.sidebar-section {

padding: 24px;

border-bottom: 1px solid #374151;

}


.sidebar-section h2 {

font-size: 18px;

font-weight: 600;

margin-bottom: 16px;

}


.form-group {

margin-bottom: 16px;

}


.form-label {

display: block;

color: #9ca3af;

font-size: 14px;

margin-bottom: 8px;

}


select, input[type="range"] {

width: 100%;

}


select {

background: #252932;

border: 1px solid #374151;

color: #f9fafb;

padding: 10px 12px;

border-radius: 8px;

font-size: 14px;

cursor: pointer;

transition: border-color 0.2s;

}


select:focus {

outline: none;

border-color: #3b82f6;

}


input[type="range"] {

height: 6px;

background: #374151;

border-radius: 3px;

outline: none;

-webkit-appearance: none;

}


input[type="range"]::-webkit-slider-thumb {

-webkit-appearance: none;

width: 16px;

height: 16px;

background: #3b82f6;

border-radius: 50%;

cursor: pointer;

}


input[type="range"]::-moz-range-thumb {

width: 16px;

height: 16px;

background: #3b82f6;

border-radius: 50%;

cursor: pointer;

border: none;

}


.radio-group {

display: flex;

gap: 16px;

}


.radio-label {

display: flex;

align-items: center;

gap: 8px;

cursor: pointer;

font-size: 14px;

}


input[type="radio"] {

accent-color: #3b82f6;

cursor: pointer;

}


.btn-analyze {

width: 100%;

background: #3b82f6;

border: none;

color: #f9fafb;

padding: 14px;

border-radius: 8px;

font-size: 14px;

font-weight: 500;

cursor: pointer;

display: flex;

align-items: center;

justify-content: center;

gap: 8px;

transition: background 0.2s;

margin-top: 8px;

}


.btn-analyze:hover:not(:disabled) {

background: #2563eb;

}


.btn-analyze:disabled {

background: #374151;

cursor: not-allowed;

}


.spinner {

width: 16px;

height: 16px;

border: 2px solid #f9fafb;

border-top-color: transparent;

border-radius: 50%;

animation: spin 0.6s linear infinite;

}


@keyframes spin {

to { transform: rotate(360deg); }

}


/* Results Section */

.results-section {

padding: 24px;

display: none;

flex: 1;

}


.results-section.show {

display: block;

}


.result-card {

background: #252932;

border-radius: 8px;

padding: 24px;

margin-bottom: 24px;

}


.trust-score-card {

text-align: center;

}


.trust-score-label {

color: #9ca3af;

font-size: 14px;

margin-bottom: 12px;

}


.trust-score-gauge {

width: 128px;

height: 128px;

margin: 0 auto 12px;

position: relative;

}


.trust-score-value {

position: absolute;

top: 50%;

left: 50%;

transform: translate(-50%, -50%);

font-size: 32px;

font-weight: 700;

}


.trust-score-status {

color: #9ca3af;

font-size: 12px;

}


.result-card h3 {

color: #9ca3af;

font-size: 14px;

margin-bottom: 12px;

display: flex;

align-items: center;

gap: 8px;

}


.histogram {

height: 128px;

display: flex;

align-items: flex-end;

gap: 2px;

margin-bottom: 8px;

}


.histogram-bar {

flex: 1;

background: linear-gradient(to top, #ef4444, #f87171);

border-radius: 2px 2px 0 0;

}


.histogram-labels {

display: flex;

justify-content: space-between;

color: #9ca3af;

font-size: 12px;

}


.alert-item {

display: flex;

justify-content: space-between;

align-items: center;

padding: 8px;

background: #1a1d24;

border-radius: 6px;

margin-bottom: 8px;

font-size: 14px;

cursor: pointer;

transition: background 0.2s;

}


.alert-item:hover {

background: #252932;

}


.alert-confidence {

color: #ef4444;

}


.error-bar-item {

margin-bottom: 12px;

}


.error-bar-header {

display: flex;

justify-content: space-between;

margin-bottom: 4px;

font-size: 12px;

}


.error-bar-uncertainty {

color: #9ca3af;

}


.error-bar-track {

height: 4px;

background: #1a1d24;

border-radius: 2px;

overflow: hidden;

}


.error-bar-fill {

height: 100%;

background: #3b82f6;

border-radius: 2px;

}


.action-buttons {

display: flex;

flex-direction: column;

gap: 12px;

}


.btn-action {

width: 100%;

background: #252932;

border: none;

color: #f9fafb;

padding: 12px;

border-radius: 8px;

font-size: 14px;

font-weight: 500;

cursor: pointer;

display: flex;

align-items: center;

justify-content: center;

gap: 8px;

transition: background 0.2s;

}


.btn-action:hover {

background: #2d323d;

}


.empty-state {

padding: 60px 24px;

text-align: center;

color: #9ca3af;

}


.empty-state p {

font-size: 14px;

line-height: 1.6;

}


.alert-icon {

color: #f59e0b;

}

</style>

```


</head>

<body>

<!-- Header -->

<header class="header">

<div class="header-left">

<div class="logo">Quinsim-Vision</div>

<div class="breadcrumb">

<span class="active">Vuq</span>

<span>|</span>

<span>Vision Uncertainty Quantifier</span>

</div>

</div>

<div class="header-right">

<button class="icon-btn" title="Help">

<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">

<circle cx="12" cy="12" r="10"></circle>

<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>

<line x1="12" y1="17" x2="12.01" y2="17"></line>

</svg>

</button>

<button class="btn-secondary">Back to Dashboard</button>

</div>

</header>



<!-- Main Container -->

<div class="main-container">

<!-- Left Panel -->

<div class="left-panel">

<div class="image-container">

<div class="image-display" id="imageDisplay">

<!-- Upload Zone -->

<div class="upload-zone" id="uploadZone">

<div class="upload-icon">

<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">

<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>

<polyline points="17 8 12 3 7 8"></polyline>

<line x1="12" y1="3" x2="12" y2="15"></line>

</svg>

</div>

<h3>Upload an image</h3>

<p>Drag and drop or click to browse</p>

<button class="btn-primary" onclick="document.getElementById('uploadInput').click()">

Choose File

</button>

<input type="file" id="uploadInput" accept="image" onchange="handleImageUpload(event)">

<p class="upload-hint">Supports: JPG, PNG, BMP</p>

</div>


<!-- Uploaded Image -->

<img id="uploadedImage" alt="Uploaded">

<div class="uncertainty-overlay" id="uncertaintyOverlay"></div>

</div>


<!-- Image Controls -->

<div class="image-controls" id="imageControls">

<button class="control-btn" id="toggleOverlay" onclick="toggleOverlay()" disabled>

<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">

<path id="eyeIcon" d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>

<circle cx="12" cy="12" r="3"></circle>

</svg>

<span id="overlayText">Hide Uncertainty Overlay</span>

</button>

<button class="control-btn" onclick="resetUpload()">

Upload New Image

</button>

</div>

</div>

</div>


<!-- Right Sidebar -->

<div class="right-sidebar">

<!-- Parameters Section -->

<div class="sidebar-section">

<h2>Parameters</h2>


<div class="form-group">

<label class="form-label">Uncertainty Method</label>

<select id="method">

<option value="mc-dropout">MC-Dropout</option>

<option value="deep-ensembles">Deep Ensembles</option>

<option value="bayesian-layers">Bayesian Layers</option>

<option value="surrogate-uq">Surrogate UQ</option>

</select>

</div>


<div class="form-group">

<label class="form-label">

Confidence Threshold: <span id="thresholdValue">0.50</span>

</label>

<input type="range" id="threshold" min="0" max="1" step="0.01" value="0.5" oninput="updateThreshold(this.value)">

</div>


<div class="form-group">

<label class="form-label">Analysis Level</label>

<div class="radio-group">

<label class="radio-label">

<input type="radio" name="level" value="pixel" checked>

<span>Pixel-level</span>

</label>

<label class="radio-label">

<input type="radio" name="level" value="object">

<span>Object-level</span>

</label>

</div>

</div>


<button class="btn-analyze" id="analyzeBtn" onclick="runAnalysis()" disabled>

<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">

<polygon points="5 3 19 12 5 21 5 3"></polygon>

</svg>

<span id="analyzeBtnText">Run Analysis</span>

</button>

</div>


<!-- Results Section -->

<div class="results-section" id="resultsSection">

<h2>Results</h2>


<!-- Trust Score -->

<div class="result-card trust-score-card">

<p class="trust-score-label">Trust Score</p>

<div class="trust-score-gauge">

<svg width="128" height="128" style="transform: rotate(-90deg)">

<circle cx="64" cy="64" r="56" fill="none" stroke="#374151" stroke-width="8"></circle>

<circle id="trustScoreCircle" cx="64" cy="64" r="56" fill="none" stroke="#10b981" stroke-width="8" stroke-dasharray="0 352" stroke-linecap="round"></circle>

</svg>

<div class="trust-score-value" id="trustScoreValue">72</div>

</div>

<p class="trust-score-status" id="trustScoreStatus">High Confidence</p>

</div>


<!-- Uncertainty Distribution -->

<div class="result-card">

<h3>Uncertainty Distribution</h3>

<div class="histogram" id="histogram"></div>

<div class="histogram-labels">

<span>Low</span>

<span>Uncertainty Level</span>

<span>High</span>

</div>

</div>


<!-- Low-Confidence Alerts -->

<div class="result-card">

<h3>

<svg class="alert-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">

<circle cx="12" cy="12" r="10"></circle>

<line x1="12" y1="8" x2="12" y2="12"></line>

<line x1="12" y1="16" x2="12.01" y2="16"></line>

</svg>

Low-Confidence Detections

</h3>

<div id="alertsList"></div>

</div>


<!-- Error Bars -->

<div class="result-card" id="errorBarsCard">

<h3>Error Bars Per Object</h3>

<div id="errorBarsList"></div>

</div>


<!-- Action Buttons -->

<div class="action-buttons">

<button class="btn-action">

<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">

<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>

<polyline points="7 10 12 15 17 10"></polyline>

<line x1="12" y1="15" x2="12" y2="3"></line>

</svg>

Download Report (PDF)

</button>

<button class="btn-action">

<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">

<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>

<polyline points="14 2 14 8 20 8"></polyline>

<line x1="12" y1="18" x2="12" y2="12"></line>

<line x1="9" y1="15" x2="15" y2="15"></line>

</svg>

Export Data (JSON)

</button>

</div>

</div>


<!-- Empty State -->

<div class="empty-state" id="emptyState">

<p>Configure parameters and run analysis<br>to see results here</p>

</div>

</div>

</div>


<script>

let uploadedImageData = null;

let overlayVisible = true;

let analysisComplete = false;


function handleImageUpload(event) {

const file = event.target.files[0];

if (file) {

const reader = new FileReader();

reader.onload = function(e) {

uploadedImageData = e.target.result;

displayImage();

};

reader.readAsDataURL(file);

}

}


function displayImage() {

document.getElementById('uploadZone').style.display = 'none';

document.getElementById('uploadedImage').src = uploadedImageData;

document.getElementById('uploadedImage').style.display = 'block';

document.getElementById('imageControls').style.display = 'flex';

document.getElementById('analyzeBtn').disabled = false;


// Hide results

document.getElementById('resultsSection').classList.remove('show');

document.getElementById('emptyState').style.display = 'block';

document.getElementById('uncertaintyOverlay').style.display = 'none';

document.getElementById('toggleOverlay').disabled = true;

analysisComplete = false;

}


function resetUpload() {

uploadedImageData = null;

document.getElementById('uploadZone').style.display = 'block';

document.getElementById('uploadedImage').style.display = 'none';

document.getElementById('imageControls').style.display = 'none';

document.getElementById('analyzeBtn').disabled = true;

document.getElementById('resultsSection').classList.remove('show');

document.getElementById('emptyState').style.display = 'block';

document.getElementById('uncertaintyOverlay').style.display = 'none';

document.getElementById('uploadInput').value = '';

analysisComplete = false;

}


function updateThreshold(value) {

document.getElementById('thresholdValue').textContent = parseFloat(value).toFixed(2);

}


function toggleOverlay() {

overlayVisible = !overlayVisible;

const overlay = document.getElementById('uncertaintyOverlay');

const icon = document.getElementById('eyeIcon');

const text = document.getElementById('overlayText');


if (overlayVisible) {

overlay.style.display = 'block';

text.textContent = 'Hide Uncertainty Overlay';

icon.setAttribute('d', 'M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z');

} else {

overlay.style.display = 'none';

text.textContent = 'Show Uncertainty Overlay';

icon.setAttribute('d', 'M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24');

}

}


function runAnalysis() {

const btn = document.getElementById('analyzeBtn');

const btnText = document.getElementById('analyzeBtnText');


// Show loading state

btn.disabled = true;

btnText.textContent = 'Analyzing...';

btn.innerHTML = '<div class="spinner"></div><span>Analyzing...</span>';


// Simulate API call

setTimeout(() => {

// Generate random results

const trustScore = Math.floor(Math.random() * 30) + 60;

const uncertaintyData = Array.from({ length: 20 }, () => Math.random() * 100);


// Update trust score

updateTrustScore(trustScore);


// Update histogram

updateHistogram(uncertaintyData);


// Update alerts

updateAlerts([

{ id: 1, object: 'Vehicle', confidence: 0.42 },

{ id: 2, object: 'Pedestrian', confidence: 0.38 },

{ id: 3, object: 'Sign', confidence: 0.35 }

]);


// Update error bars

const level = document.querySelector('input[name="level"]:checked').value;

if (level === 'object') {

updateErrorBars([

{ id: 1, class: 'Vehicle', confidence: 0.85, uncertainty: 0.12 },

{ id: 2, class: 'Pedestrian', confidence: 0.78, uncertainty: 0.18 },

{ id: 3, class: 'Road', confidence: 0.92, uncertainty: 0.06 },

{ id: 4, class: 'Sign', confidence: 0.71, uncertainty: 0.15 }

]);

} else {

document.getElementById('errorBarsCard').style.display = 'none';

}


// Show results

document.getElementById('resultsSection').classList.add('show');

document.getElementById('emptyState').style.display = 'none';

document.getElementById('uncertaintyOverlay').style.display = 'block';

document.getElementById('toggleOverlay').disabled = false;

analysisComplete = true;


// Reset button

btn.disabled = false;

btn.innerHTML = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg><span>Run Analysis</span>';

}, 2000);

}


function updateTrustScore(score) {

const circle = document.getElementById('trustScoreCircle');

const value = document.getElementById('trustScoreValue');

const status = document.getElementById('trustScoreStatus');


const circumference = 2 * Math.PI * 56;

const offset = circumference - (score / 100) * circumference;


let color, statusText;

if (score >= 70) {

color = '#10b981';

statusText = 'High Confidence';

} else if (score >= 40) {

color = '#f59e0b';

statusText = 'Moderate Confidence';

} else {

color = '#ef4444';

statusText = 'Low Confidence';

}


circle.setAttribute('stroke', color);

circle.setAttribute('stroke-dasharray', `${circumference - offset} ${circumference}`);

circle.style.filter = `drop-shadow(0 0 8px ${color}40)`;

value.textContent = score;

status.textContent = statusText;

}