|
|
|
|
|
|
|
|
|
|
|
const VISUALIZATION_CONFIG = { |
|
|
colors: { |
|
|
0: '#ff0000', |
|
|
1: '#00ff00', |
|
|
2: '#0000ff', |
|
|
3: '#ffff00', |
|
|
4: '#ff00ff', |
|
|
5: '#00ffff' |
|
|
}, |
|
|
classNames: { |
|
|
0: 'Persona', |
|
|
1: 'Vehículo', |
|
|
2: 'Animal', |
|
|
3: 'Objeto', |
|
|
4: 'Edificio', |
|
|
5: 'Otro' |
|
|
}, |
|
|
boxThickness: 3, |
|
|
fontSize: 16, |
|
|
fontFamily: 'Arial, sans-serif' |
|
|
}; |
|
|
|
|
|
|
|
|
let sessionData = null; |
|
|
let currentImages = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function loadSessionData(sessionId) { |
|
|
if (!sessionId) { |
|
|
console.error('Session ID is required'); |
|
|
showError('ID de sesión requerido'); |
|
|
return; |
|
|
} |
|
|
|
|
|
console.log('Cargando datos para sesión:', sessionId); |
|
|
|
|
|
try { |
|
|
showLoading(true); |
|
|
|
|
|
|
|
|
const url = `/api/session/${sessionId}/visualize`; |
|
|
console.log('Haciendo fetch a:', url); |
|
|
|
|
|
const response = await fetch(url); |
|
|
console.log('Response status:', response.status); |
|
|
|
|
|
if (!response.ok) { |
|
|
throw new Error(`HTTP error! status: ${response.status}`); |
|
|
} |
|
|
|
|
|
const data = await response.json(); |
|
|
console.log('Datos recibidos:', data); |
|
|
|
|
|
if (data.error) { |
|
|
throw new Error(data.error); |
|
|
} |
|
|
|
|
|
sessionData = data; |
|
|
currentImages = data.images || []; |
|
|
|
|
|
console.log('Número de imágenes:', currentImages.length); |
|
|
|
|
|
|
|
|
updateSessionInfo(data); |
|
|
renderLegend(); |
|
|
renderImages(); |
|
|
|
|
|
} catch (error) { |
|
|
console.error('Error loading session data:', error); |
|
|
showError('Error al cargar los datos de la sesión: ' + error.message); |
|
|
} finally { |
|
|
showLoading(false); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function updateSessionInfo(data) { |
|
|
|
|
|
const titleElement = document.getElementById('session-title'); |
|
|
if (titleElement) { |
|
|
titleElement.textContent = `Visualizador - Sesión: ${data.session_name}`; |
|
|
} |
|
|
|
|
|
|
|
|
const statsElement = document.getElementById('session-stats'); |
|
|
if (statsElement) { |
|
|
|
|
|
const totalImages = data.total_images || 0; |
|
|
const displayedImages = data.returned_images || (data.images ? data.images.length : 0); |
|
|
const totalAnnotations = data.total_labels || 0; |
|
|
|
|
|
statsElement.innerHTML = ` |
|
|
<div>Total de imágenes: <strong>${totalImages}</strong></div> |
|
|
<div>Imágenes mostradas: <strong>${displayedImages}</strong></div> |
|
|
<div>Total de anotaciones: <strong>${totalAnnotations}</strong></div> |
|
|
`; |
|
|
|
|
|
|
|
|
if (displayedImages < totalImages) { |
|
|
const warningMessage = document.createElement('div'); |
|
|
warningMessage.style.cssText = 'color: #ff6b35; font-size: 0.9em; margin-top: 10px; font-style: italic;'; |
|
|
warningMessage.innerHTML = `⚠️ Mostrando solo las primeras ${displayedImages} de ${totalImages} imágenes`; |
|
|
statsElement.appendChild(warningMessage); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function renderLegend() { |
|
|
const legendContainer = document.getElementById('legend-items'); |
|
|
if (!legendContainer) return; |
|
|
|
|
|
legendContainer.innerHTML = ''; |
|
|
|
|
|
Object.keys(VISUALIZATION_CONFIG.colors).forEach(classId => { |
|
|
const color = VISUALIZATION_CONFIG.colors[classId]; |
|
|
const name = VISUALIZATION_CONFIG.classNames[classId]; |
|
|
|
|
|
const legendItem = document.createElement('div'); |
|
|
legendItem.className = 'legend-item'; |
|
|
legendItem.innerHTML = ` |
|
|
<span style="background-color: ${color}; width: 20px; height: 20px; display: inline-block; margin-right: 10px; border-radius: 3px;"></span> |
|
|
${name} |
|
|
`; |
|
|
|
|
|
legendContainer.appendChild(legendItem); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function renderImages() { |
|
|
const imagesContainer = document.getElementById('images-container'); |
|
|
if (!imagesContainer) { |
|
|
console.error('No se encontró el contenedor de imágenes'); |
|
|
return; |
|
|
} |
|
|
|
|
|
console.log('Renderizando imágenes, total:', currentImages.length); |
|
|
|
|
|
imagesContainer.innerHTML = ''; |
|
|
|
|
|
if (!currentImages || currentImages.length === 0) { |
|
|
imagesContainer.innerHTML = '<div class="loading">No hay imágenes anotadas en esta sesión</div>'; |
|
|
return; |
|
|
} |
|
|
|
|
|
currentImages.forEach((imageData, index) => { |
|
|
console.log(`Procesando imagen ${index + 1}:`, imageData.filename); |
|
|
const imageCard = createImageCard(imageData); |
|
|
imagesContainer.appendChild(imageCard); |
|
|
}); |
|
|
|
|
|
console.log('Todas las imágenes han sido renderizadas'); |
|
|
} |
|
|
|
|
|
|
|
|
function createImageCard(imageData) { |
|
|
const card = document.createElement('div'); |
|
|
card.className = 'image-card'; |
|
|
|
|
|
const fileName = imageData.filename || 'imagen.jpg'; |
|
|
const annotations = imageData.annotations || []; |
|
|
|
|
|
|
|
|
if (imageData.image_data) { |
|
|
const img = document.createElement('img'); |
|
|
img.src = imageData.image_data; |
|
|
img.className = 'image-preview'; |
|
|
img.alt = fileName; |
|
|
|
|
|
|
|
|
const imageInfo = document.createElement('div'); |
|
|
imageInfo.className = 'image-info'; |
|
|
imageInfo.innerHTML = ` |
|
|
<strong>${fileName}</strong><br> |
|
|
<small>Anotaciones: ${annotations.length}</small> |
|
|
${imageData.has_labels ? '<br>✅ Etiquetas encontradas' : '<br>❌ Sin etiquetas'} |
|
|
`; |
|
|
|
|
|
|
|
|
if (annotations.length > 0) { |
|
|
const annotationsList = document.createElement('div'); |
|
|
annotationsList.className = 'annotations-list'; |
|
|
|
|
|
annotations.forEach(annotation => { |
|
|
const annotationItem = document.createElement('div'); |
|
|
annotationItem.className = 'annotation-item'; |
|
|
annotationItem.style.borderLeftColor = annotation.color || '#ccc'; |
|
|
|
|
|
annotationItem.innerHTML = ` |
|
|
${annotation.class_name || `Clase ${annotation.class_id}`} (ID: ${annotation.class_id}) |
|
|
<br><small>YOLO: [${annotation.yolo_coords ? annotation.yolo_coords.map(c => c.toFixed(3)).join(', ') : 'N/A'}]</small> |
|
|
`; |
|
|
|
|
|
annotationsList.appendChild(annotationItem); |
|
|
}); |
|
|
|
|
|
card.appendChild(img); |
|
|
card.appendChild(imageInfo); |
|
|
card.appendChild(annotationsList); |
|
|
} else { |
|
|
card.appendChild(img); |
|
|
card.appendChild(imageInfo); |
|
|
} |
|
|
} else { |
|
|
|
|
|
card.innerHTML = ` |
|
|
<div class="image-info"> |
|
|
<strong>${fileName}</strong><br> |
|
|
<small style="color: red;">Error: No se pudo cargar la imagen</small> |
|
|
</div> |
|
|
`; |
|
|
} |
|
|
|
|
|
return card; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function showLoading(show) { |
|
|
const loadingElement = document.getElementById('loading'); |
|
|
const contentElement = document.getElementById('content'); |
|
|
|
|
|
if (loadingElement) { |
|
|
loadingElement.style.display = show ? 'block' : 'none'; |
|
|
} |
|
|
|
|
|
if (contentElement) { |
|
|
contentElement.style.display = show ? 'none' : 'block'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function showError(message) { |
|
|
console.error('Error:', message); |
|
|
|
|
|
const imagesContainer = document.getElementById('images-container'); |
|
|
if (imagesContainer) { |
|
|
imagesContainer.innerHTML = ` |
|
|
<div style="background: #f8d7da; color: #721c24; padding: 20px; border-radius: 5px; text-align: center;"> |
|
|
<strong>Error:</strong> ${message} |
|
|
<br><br> |
|
|
<button onclick="reloadData()" style="background: #dc3545; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer;"> |
|
|
Intentar de nuevo |
|
|
</button> |
|
|
</div> |
|
|
`; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function getUrlParameter(name) { |
|
|
const urlParams = new URLSearchParams(window.location.search); |
|
|
return urlParams.get(name); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function initVisualizer() { |
|
|
console.log('Inicializando visualizador...'); |
|
|
|
|
|
|
|
|
const sessionId = getUrlParameter('session'); |
|
|
|
|
|
if (!sessionId) { |
|
|
showError('No se especificó una sesión para visualizar. Ve al anotador principal y selecciona una sesión.'); |
|
|
return; |
|
|
} |
|
|
|
|
|
console.log('Cargando sesión:', sessionId); |
|
|
|
|
|
|
|
|
loadSessionData(sessionId); |
|
|
} |
|
|
|
|
|
|
|
|
function reloadData() { |
|
|
const sessionId = getUrlParameter('session'); |
|
|
if (sessionId) { |
|
|
loadSessionData(sessionId); |
|
|
} else { |
|
|
showError('No se puede recargar: falta el ID de sesión'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
console.log('DOM cargado, inicializando visualizador...'); |
|
|
|
|
|
|
|
|
renderLegend(); |
|
|
|
|
|
|
|
|
initVisualizer(); |
|
|
|
|
|
|
|
|
const reloadBtn = document.getElementById('reload-btn'); |
|
|
if (reloadBtn) { |
|
|
reloadBtn.addEventListener('click', reloadData); |
|
|
} |
|
|
|
|
|
|
|
|
const backBtn = document.getElementById('back-btn'); |
|
|
if (backBtn) { |
|
|
backBtn.addEventListener('click', function() { |
|
|
window.location.href = '/'; |
|
|
}); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
window.addEventListener('error', function(e) { |
|
|
if (e.target.tagName === 'IMG') { |
|
|
console.error('Error loading image:', e.target.src); |
|
|
e.target.style.display = 'none'; |
|
|
|
|
|
|
|
|
const errorDiv = document.createElement('div'); |
|
|
errorDiv.innerHTML = '⚠️ Error al cargar imagen'; |
|
|
errorDiv.style.cssText = 'padding: 20px; background: #f8d7da; color: #721c24; text-align: center; border-radius: 5px;'; |
|
|
e.target.parentNode.insertBefore(errorDiv, e.target); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
window.visualizerUtils = { |
|
|
loadSessionData, |
|
|
reloadData, |
|
|
showError, |
|
|
showLoading, |
|
|
VISUALIZATION_CONFIG, |
|
|
initVisualizer |
|
|
}; |
|
|
|