| <!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> |
|
|