loko/streetup/road_detection/templates/road_detection/detection_result.html
2026-07-22 14:48:40 +02:00

268 lines
12 KiB
HTML

{% extends "base.html" %}
{% load i18n l10n %}
{% block head %}
<style>
.result-card {
border: none;
box-shadow: 0 2px 12px rgba(0,0,0,.10);
border-radius: .75rem;
}
.confidence-bar {
height: 12px;
border-radius: 6px;
}
.image-compare img {
max-height: 220px;
object-fit: contain;
width: 100%;
border-radius: .5rem;
border: 1px solid #dee2e6;
}
.result-image img {
max-width: 100%;
border-radius: .5rem;
border: 2px solid #0d6efd;
}
</style>
{% endblock head %}
{% block content %}
<div class="container py-4">
<!-- En-tête -->
<div class="row mb-4 align-items-center">
<div class="col">
<h2 class="fw-bold">
<i class="bi bi-check-circle me-2 text-success"></i>Résultat de l'analyse
</h2>
<p class="text-muted mb-0">Analyse du {{ detection.created_at|date:"d/m/Y à H:i" }}</p>
</div>
<div class="col-auto">
{% if detection.detection_count > 0 %}
<span class="badge bg-danger fs-5 px-3 py-2">
<i class="bi bi-exclamation-triangle me-1"></i>
{{ detection.detection_count }} nid{{ detection.detection_count|pluralize }}
de poule détecté{{ detection.detection_count|pluralize }}
</span>
{% else %}
<span class="badge bg-success fs-5 px-3 py-2">
<i class="bi bi-check-lg me-1"></i>
Aucun nid de poule détecté
</span>
{% endif %}
</div>
</div>
<!-- Messages -->
{% for message in messages %}
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Fermer"></button>
</div>
{% endfor %}
<div class="row g-4">
<!-- Image annotée -->
<div class="col-lg-8">
<div class="card result-card">
<div class="card-header bg-primary text-white">
<h5 class="mb-0"><i class="bi bi-image me-2"></i>Image annotée</h5>
</div>
<div class="card-body text-center result-image">
{% if detection.result_image %}
<img src="{{ detection.result_image.url }}"
alt="Image annotée avec bounding boxes"
class="img-fluid">
{% else %}
<div class="text-muted py-5">
<i class="bi bi-x-circle fs-1 d-block mb-2"></i>
Image résultat non disponible.
</div>
{% endif %}
</div>
{% if detection.result_image %}
<div class="card-footer bg-transparent d-flex gap-2 justify-content-end">
<a href="{{ detection.result_image.url }}" download
class="btn btn-outline-primary">
<i class="bi bi-download me-1"></i>Télécharger l'image annotée
</a>
</div>
{% endif %}
</div>
</div>
<!-- Panneau latéral -->
<div class="col-lg-4 d-flex flex-column gap-4">
<!-- Image originale (comparaison) -->
<div class="card result-card">
<div class="card-header bg-secondary text-white">
<h6 class="mb-0"><i class="bi bi-file-image me-2"></i>Image originale</h6>
</div>
<div class="card-body image-compare text-center">
<img src="{{ detection.uploaded_image.url }}"
alt="Image originale uploadée">
</div>
</div>
<!-- Informations de l'analyse -->
<div class="card result-card">
<div class="card-header bg-light">
<h6 class="mb-0"><i class="bi bi-info-circle me-2"></i>Détails</h6>
</div>
<div class="card-body">
<dl class="row mb-0 small">
<dt class="col-7 text-muted">Modèle</dt>
<dd class="col-5">YOLO11</dd>
<dt class="col-7 text-muted">Seuil de confiance</dt>
<dd class="col-5">{{ detection.confidence_threshold|floatformat:2 }}</dd>
<dt class="col-7 text-muted">Détections</dt>
<dd class="col-5">{{ detection.detection_count }}</dd>
<dt class="col-7 text-muted">Date</dt>
<dd class="col-5">{{ detection.created_at|date:"d/m/Y H:i" }}</dd>
{% if detection.notes %}
<dt class="col-7 text-muted">Notes</dt>
<dd class="col-5">{{ detection.notes }}</dd>
{% endif %}
</dl>
</div>
</div>
<!-- Localisation GPS de la photo -->
{% if detection.image_lat and detection.image_lon %}
<div class="card result-card">
<div class="card-header bg-light">
<h6 class="mb-0"><i class="bi bi-geo-alt me-2"></i>Localisation de la photo</h6>
</div>
<div class="card-body small">
<dl class="row mb-2">
<dt class="col-5 text-muted">Latitude</dt>
<dd class="col-7 font-monospace">{{ detection.image_lat|unlocalize }}</dd>
<dt class="col-5 text-muted">Longitude</dt>
<dd class="col-7 font-monospace">{{ detection.image_lon|unlocalize }}</dd>
</dl>
<a href="https://www.google.com/maps?q={{ detection.image_lat|stringformat:'.7f' }},{{ detection.image_lon|stringformat:'.7f' }}"
target="_blank" rel="noopener noreferrer"
class="btn btn-sm btn-outline-secondary w-100">
<i class="bi bi-map me-1"></i>Voir sur Google Maps
</a>
</div>
</div>
{% endif %}
<!-- Actions -->
<a href="{% url 'road_detection:upload' %}" class="btn btn-primary">
<i class="bi bi-plus-circle me-2"></i>Nouvelle analyse
</a>
</div>
</div>
<!-- Tableau des détections -->
{% if detection.detection_count > 0 %}
<div class="row mt-4">
<div class="col">
<div class="card result-card">
<div class="card-header bg-danger text-white">
<h5 class="mb-0">
<i class="bi bi-table me-2"></i>
Détail des {{ detection.detection_count }} détection{{ detection.detection_count|pluralize }}
</h5>
</div>
<div class="card-body p-0">
{% if detection.detections_data %}
<div class="table-responsive">
<table class="table table-hover table-sm mb-0 small">
<thead class="table-light">
<tr>
<th class="ps-3">#</th>
<th>Classe</th>
<th class="text-center">Confiance</th>
<th>Bounding Box (px)</th>
<th>Coordonnées GPS estimées</th>
</tr>
</thead>
<tbody>
{% for det in detection.detections_data %}
<tr>
<td class="ps-3 text-muted">{{ forloop.counter }}</td>
<td>{{ det.label }}</td>
<td class="text-center">
<span class="badge {% if det.confidence >= 0.7 %}bg-success{% elif det.confidence >= 0.4 %}bg-warning text-dark{% else %}bg-danger{% endif %}">
{{ det.confidence|floatformat:2 }}
</span>
</td>
<td class="font-monospace text-muted" style="font-size:.8em">
({{ det.bbox.x1 }}, {{ det.bbox.y1 }}) → ({{ det.bbox.x2 }}, {{ det.bbox.y2 }})
</td>
<td>
{% if det.gps %}
<a href="https://www.google.com/maps?q={{ det.gps.lat|stringformat:'.7f' }},{{ det.gps.lon|stringformat:'.7f' }}"
target="_blank" rel="noopener noreferrer"
class="font-monospace text-decoration-none"
title="Ouvrir sur Google Maps (estimation)">
{{ det.gps.lat|unlocalize }}, {{ det.gps.lon|unlocalize }}
<i class="bi bi-box-arrow-up-right ms-1 small"></i>
</a>
<br><span class="text-muted" style="font-size:.8em"><i class="bi bi-exclamation-circle me-1"></i>Estimation géométrique</span>
{% else %}
<span class="text-muted">—</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if not detection.image_lat %}
<div class="alert alert-warning m-3 mb-0 d-flex align-items-center gap-2" role="alert">
<i class="bi bi-exclamation-triangle-fill flex-shrink-0"></i>
<small>
Aucune donnée GPS trouvée dans l'EXIF de la photo. Ajoutez des coordonnées
à votre image (smartphone avec géolocalisation activée) pour obtenir des
positions GPS estimées.
</small>
</div>
{% else %}
<div class="alert alert-info m-3 mb-0 d-flex align-items-center gap-2" role="alert">
<i class="bi bi-info-circle-fill flex-shrink-0"></i>
<small>
Les coordonnées GPS sont des <strong>estimations</strong> basées sur la
position de la photo et un modèle géométrique simplifié (caméra orientée
vers l'avant, sol plat). La précision dépend du cap de la caméra et de la
distance réelle aux défauts.
</small>
</div>
{% endif %}
{% else %}
<div class="alert alert-warning m-3 mb-0 d-flex align-items-center gap-2" role="alert">
<i class="bi bi-info-circle-fill flex-shrink-0"></i>
<small>
Le détail des détections individuelles n'est pas disponible pour cette analyse.
Référez-vous à l'image annotée ci-dessus pour visualiser les bounding boxes.
</small>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% else %}
<div class="row mt-4">
<div class="col">
<div class="alert alert-success d-flex align-items-center gap-2" role="alert">
<i class="bi bi-check-circle-fill fs-5 flex-shrink-0"></i>
<div>
<strong>Aucun nid de poule détecté</strong> sur cette image avec un seuil de confiance
de {{ detection.confidence_threshold|floatformat:2 }}.
Si vous pensez que l'image contient des défauts, essayez de diminuer le seuil de confiance.
</div>
</div>
</div>
</div>
{% endif %}
</div>
{% endblock content %}