|
<!DOCTYPE html> |
|
<html lang="fr"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Labélisation d'Images avec SAM</title> |
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}"> |
|
<style> |
|
|
|
body { |
|
font-family: Arial, sans-serif; |
|
margin: 0; |
|
padding: 0; |
|
background-color: #f4f4f4; |
|
} |
|
|
|
header { |
|
background-color: #4CAF50; |
|
padding: 15px 0; |
|
text-align: center; |
|
color: white; |
|
font-size: 24px; |
|
font-weight: bold; |
|
} |
|
|
|
section { |
|
margin: 20px auto; |
|
max-width: 1200px; |
|
padding: 20px; |
|
background: white; |
|
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); |
|
border-radius: 8px; |
|
} |
|
|
|
.upload-section { |
|
text-align: center; |
|
} |
|
|
|
.upload-section input[type="file"] { |
|
margin: 10px 0; |
|
} |
|
|
|
.image-container { |
|
display: flex; |
|
flex-wrap: wrap; |
|
gap: 20px; |
|
justify-content: center; |
|
} |
|
|
|
.image-item { |
|
width: 150px; |
|
height: 150px; |
|
overflow: hidden; |
|
border: 2px solid #ddd; |
|
border-radius: 8px; |
|
cursor: pointer; |
|
transition: transform 0.3s ease, border-color 0.3s ease; |
|
display: flex; |
|
justify-content: center; |
|
align-items: center; |
|
background-color: #fff; |
|
} |
|
|
|
.image-item:hover { |
|
border-color: #4CAF50; |
|
transform: scale(1.05); |
|
} |
|
|
|
.image-item img { |
|
max-width: 100%; |
|
max-height: 100%; |
|
object-fit: cover; |
|
} |
|
|
|
canvas { |
|
border: 2px solid #ddd; |
|
border-radius: 8px; |
|
margin: 20px auto; |
|
display: block; |
|
} |
|
|
|
.class-management { |
|
text-align: center; |
|
margin-bottom: 20px; |
|
} |
|
|
|
.class-management input[type="text"] { |
|
padding: 8px; |
|
font-size: 16px; |
|
width: 300px; |
|
margin-right: 10px; |
|
} |
|
|
|
.class-list { |
|
display: flex; |
|
justify-content: center; |
|
flex-wrap: wrap; |
|
gap: 10px; |
|
list-style: none; |
|
padding: 0; |
|
} |
|
|
|
.class-item { |
|
padding: 5px 15px; |
|
border-radius: 20px; |
|
background-color: #f4f4f4; |
|
border: 1px solid #ccc; |
|
cursor: pointer; |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.class-item:hover { |
|
background-color: #ddd; |
|
} |
|
|
|
.class-item.active { |
|
background-color: #4CAF50; |
|
color: white; |
|
border-color: #45a049; |
|
} |
|
|
|
.controls { |
|
text-align: center; |
|
margin-top: 20px; |
|
} |
|
|
|
button { |
|
background-color: #4CAF50; |
|
color: white; |
|
border: none; |
|
padding: 10px 20px; |
|
font-size: 16px; |
|
cursor: pointer; |
|
border-radius: 5px; |
|
transition: background-color 0.3s ease; |
|
margin: 0 10px; |
|
} |
|
|
|
button:hover { |
|
background-color: #45a049; |
|
} |
|
|
|
button:disabled { |
|
background-color: #ccc; |
|
cursor: not-allowed; |
|
} |
|
|
|
.result-section img { |
|
max-width: 100%; |
|
margin: 20px auto; |
|
display: block; |
|
border: 2px solid #4CAF50; |
|
border-radius: 8px; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<header>Labélisation d'Images avec SAM</header> |
|
|
|
|
|
<section class="upload-section"> |
|
<h2>Télécharger vos images</h2> |
|
<form method="post" enctype="multipart/form-data"> |
|
<input type="file" id="image" name="images" accept="image/*" multiple required> |
|
<br> |
|
<button type="submit">Télécharger</button> |
|
</form> |
|
</section> |
|
|
|
{% if uploaded_images %} |
|
|
|
<section> |
|
<h2>Images téléchargées</h2> |
|
<div class="image-container"> |
|
{% for image in uploaded_images %} |
|
<div class="image-item" onclick="loadImage('{{ image }}')"> |
|
<img src="{{ url_for('static', filename='uploads/' + image) }}" alt="{{ image }}"> |
|
</div> |
|
{% endfor %} |
|
</div> |
|
</section> |
|
|
|
|
|
<section> |
|
<canvas id="image-canvas"></canvas> |
|
</section> |
|
|
|
|
|
<section class="class-management"> |
|
<h3>Ajouter une classe</h3> |
|
<input type="text" id="class-name" placeholder="Nom de la classe"> |
|
<button id="add-class">Ajouter</button> |
|
<ul id="class-list" class="class-list"></ul> |
|
</section> |
|
|
|
|
|
<section class="controls"> |
|
<button id="finish-button" disabled>Terminer l'annotation</button> |
|
<button id="segment-button" disabled>Lancer la segmentation</button> |
|
</section> |
|
{% endif %} |
|
|
|
<script> |
|
let selectedImage = null; |
|
let annotations = {}; |
|
let currentClass = null; |
|
const finishButton = document.getElementById('finish-button'); |
|
const segmentButton = document.getElementById('segment-button'); |
|
|
|
function loadImage(imageName) { |
|
if (!imageName) { |
|
alert("Veuillez sélectionner une image !"); |
|
return; |
|
} |
|
|
|
selectedImage = imageName; |
|
console.log("Image sélectionnée :", selectedImage); |
|
|
|
|
|
if (!annotations[selectedImage]) { |
|
annotations[selectedImage] = []; |
|
} |
|
|
|
const img = new Image(); |
|
img.src = `/static/uploads/${imageName}`; |
|
img.onload = () => { |
|
const canvas = document.getElementById('image-canvas'); |
|
const ctx = canvas.getContext('2d'); |
|
canvas.width = img.width; |
|
canvas.height = img.height; |
|
ctx.clearRect(0, 0, canvas.width, canvas.height); |
|
ctx.drawImage(img, 0, 0); |
|
|
|
|
|
annotations[selectedImage].forEach(point => { |
|
drawPoint(ctx, point.x, point.y, point.class); |
|
}); |
|
}; |
|
|
|
finishButton.disabled = false; |
|
} |
|
|
|
function drawPoint(ctx, x, y, pointClass) { |
|
ctx.fillStyle = pointClass === 'arbre' ? 'green' : 'red'; |
|
ctx.beginPath(); |
|
ctx.arc(x, y, 5, 0, 2 * Math.PI); |
|
ctx.fill(); |
|
} |
|
|
|
document.getElementById('add-class').addEventListener('click', () => { |
|
const className = document.getElementById('class-name').value.trim(); |
|
if (!className) { |
|
alert("Veuillez entrer un nom de classe !"); |
|
return; |
|
} |
|
const li = document.createElement('li'); |
|
li.textContent = className; |
|
li.classList.add('class-item'); |
|
li.onclick = () => { |
|
document.querySelectorAll('.class-item').forEach(item => item.classList.remove('active')); |
|
li.classList.add('active'); |
|
currentClass = className; |
|
console.log("Classe sélectionnée :", currentClass); |
|
}; |
|
document.getElementById('class-list').appendChild(li); |
|
document.getElementById('class-name').value = ''; |
|
}); |
|
|
|
const canvas = document.getElementById('image-canvas'); |
|
const ctx = canvas.getContext('2d'); |
|
|
|
canvas.addEventListener('click', (event) => { |
|
if (!currentClass) { |
|
alert("Veuillez sélectionner une classe avant d'ajouter des points !"); |
|
return; |
|
} |
|
|
|
if (!selectedImage) { |
|
alert("Veuillez sélectionner une image avant d'ajouter des points !"); |
|
return; |
|
} |
|
|
|
const rect = canvas.getBoundingClientRect(); |
|
const x = event.clientX - rect.left; |
|
const y = event.clientY - rect.top; |
|
|
|
const newPoint = { x, y, class: currentClass }; |
|
annotations[selectedImage].push(newPoint); |
|
console.log(`Point ajouté pour ${selectedImage}:`, newPoint); |
|
|
|
drawPoint(ctx, x, y, currentClass); |
|
}); |
|
|
|
finishButton.addEventListener('click', () => { |
|
if (!selectedImage) { |
|
alert("Veuillez sélectionner une image !"); |
|
return; |
|
} |
|
|
|
console.log(`Annotation terminée pour ${selectedImage}.`); |
|
alert(`Annotation pour ${selectedImage} terminée !`); |
|
|
|
finishButton.disabled = true; |
|
|
|
|
|
if (Object.keys(annotations).length > 0) { |
|
segmentButton.disabled = false; |
|
} |
|
}); |
|
|
|
segmentButton.addEventListener('click', () => { |
|
const dataToSend = Object.keys(annotations).map(imageName => ({ |
|
image_name: imageName, |
|
points: annotations[imageName] |
|
})); |
|
|
|
console.log("Données envoyées :", dataToSend); |
|
|
|
fetch('/segment', { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify(dataToSend) |
|
}) |
|
.then(response => response.json()) |
|
.then(data => { |
|
console.log("Réponse du backend :", data); |
|
if (data.success) { |
|
alert("Segmentation réussie !"); |
|
} else { |
|
alert("Erreur : " + data.error); |
|
} |
|
}) |
|
.catch(err => console.error('Erreur lors de la segmentation :', err)); |
|
}); |
|
</script> |
|
</body> |
|
</html> |
|
|