Docfile's picture
Create templates/index.html
deddb46 verified
raw
history blame
10.4 kB
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Application de Reconnaissance Faciale</title>
<!-- Tailwind CSS -->
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<!-- Font Awesome (pour les icônes) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css">
<style>
/* Styles personnalisés (si nécessaire) */
.preview-image {
background-size: cover;
background-position: center;
min-height: 150px;
}
.github-link {
position: fixed;
bottom: 20px;
right: 20px;
padding: 10px;
background-color: #333;
color: white;
border-radius: 5px;
text-decoration: none;
display: flex;
align-items: center;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
.github-link i {
margin-right: 8px;
font-size: 20px;
}
.github-link:hover {
background-color: #555;
}
</style>
</head>
<body class="bg-gray-100 font-sans">
<div class="container mx-auto p-4">
<h1 class="text-4xl font-bold text-center text-blue-700 mb-8">
<i class="fas fa-user-check text-5xl mr-3"></i>
Reconnaissance et Comparaison Faciale
</h1>
<div class="grid md:grid-cols-2 gap-8">
<!-- Section de sélection d'images -->
<div class="bg-white p-6 rounded-lg shadow-lg">
<h2 class="text-2xl font-semibold mb-4 text-gray-700">
<i class="fas fa-images text-blue-500 mr-2"></i>
Sélectionner des images
</h2>
<input type="file" id="imageUpload" accept="image/*" class="mb-4 hidden">
<label for="imageUpload" class="cursor-pointer bg-blue-500 hover:bg-blue-600 text-white font-bold py-3 px-6 rounded-lg inline-flex items-center transition duration-200 ease-in-out">
<i class="fas fa-upload mr-2"></i>
Choisir un fichier
</label>
<button id="cameraButton" class="bg-green-500 hover:bg-green-600 text-white font-bold py-3 px-6 rounded-lg ml-4 inline-flex items-center transition duration-200 ease-in-out">
<i class="fas fa-camera mr-2"></i>
Utiliser la caméra
</button>
<video id="videoFeed" width="320" height="240" autoplay class="hidden mt-4 rounded-lg"></video>
<canvas id="canvas" width="320" height="240" class="hidden"></canvas>
<!-- Prévisualisation des images -->
<div class="grid grid-cols-2 gap-4 mt-6">
<div id="imagePreview1" class="w-full aspect-w-1 aspect-h-1 rounded-lg overflow-hidden preview-image"></div>
<div id="imagePreview2" class="w-full aspect-w-1 aspect-h-1 rounded-lg overflow-hidden preview-image"></div>
</div>
</div>
<!-- Section des résultats -->
<div class="bg-white p-6 rounded-lg shadow-lg">
<h2 class="text-2xl font-semibold mb-4 text-gray-700">
<i class="fas fa-poll-h text-blue-500 mr-2"></i>
Résultats de la comparaison
</h2>
<div id="results" class="text-center">
<p class="text-gray-600">Veuillez sélectionner des images ou utiliser la caméra pour commencer.</p>
</div>
<button id="compareButton" class="hidden bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded mt-4">
Comparer les visages
</button>
</div>
</div>
</div>
<!-- Lien GitHub -->
<a href="https://github.com/Yusufibin" target="_blank" class="github-link">
<i class="fab fa-github"></i>
<span>Yusufibin</span>
</a>
<script>
const imageUpload = document.getElementById('imageUpload');
const cameraButton = document.getElementById('cameraButton');
const videoFeed = document.getElementById('videoFeed');
const canvas = document.getElementById('canvas');
const imagePreview1 = document.getElementById('imagePreview1');
const imagePreview2 = document.getElementById('imagePreview2');
const resultsDiv = document.getElementById('results');
const compareButton = document.getElementById('compareButton');
const API_BASE_URL = 'http://127.0.0.1:5000'; // URL de base de ton API Flask
let usingCamera = false;
let currentImage = 1; // 1 or 2 pour suivre quelle image prévisualiser
// Gestionnaire pour le téléchargement de fichiers
imageUpload.addEventListener('change', async (event) => {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
if (currentImage === 1) {
imagePreview1.style.backgroundImage = `url(${e.target.result})`;
currentImage = 2;
} else {
imagePreview2.style.backgroundImage = `url(${e.target.result})`;
currentImage = 1;
}
compareButton.classList.remove('hidden'); // Affiche le bouton de comparaison
};
reader.readAsDataURL(file);
}
});
// Gestionnaire pour le bouton de la caméra
cameraButton.addEventListener('click', async () => {
usingCamera = !usingCamera;
if (usingCamera) {
cameraButton.textContent = 'Arrêter la caméra';
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
videoFeed.srcObject = stream;
videoFeed.classList.remove('hidden');
} catch (err) {
console.error("Erreur lors de l'accès à la caméra :", err);
}
} else {
cameraButton.textContent = 'Utiliser la caméra';
const tracks = videoFeed.srcObject.getTracks();
tracks.forEach(track => track.stop());
videoFeed.classList.add('hidden');
}
});
// Capture d'image à partir de la caméra
function captureImageFromCamera() {
const context = canvas.getContext('2d');
context.drawImage(videoFeed, 0, 0, canvas.width, canvas.height);
const imageDataURL = canvas.toDataURL('image/png');
if (currentImage === 1) {
imagePreview1.style.backgroundImage = `url(${imageDataURL})`;
currentImage = 2;
} else {
imagePreview2.style.backgroundImage = `url(${imageDataURL})`;
currentImage = 1;
}
compareButton.classList.remove('hidden'); // Affiche le bouton de comparaison
}
// Gestionnaire pour le bouton de comparaison
compareButton.addEventListener('click', () => {
if (imagePreview1.style.backgroundImage && imagePreview2.style.backgroundImage) {
const formData = new FormData();
const imageData1 = dataURLtoBlob(imagePreview1.style.backgroundImage.slice(5, -2));
const imageData2 = dataURLtoBlob(imagePreview2.style.backgroundImage.slice(5, -2));
formData.append('image1', imageData1, 'image1.png');
formData.append('image2', imageData2, 'image2.png');
fetch(`${API_BASE_URL}/verify`, {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(data => {
displayResults(data);
})
.catch(error => {
console.error('Erreur lors de la comparaison des visages:', error);
resultsDiv.innerHTML = `<p>Erreur lors de la comparaison.</p>`;
});
} else {
alert('Veuillez télécharger deux images pour la comparaison.');
}
});
// Fonction pour convertir une URL de données en Blob
function dataURLtoBlob(dataURL) {
const parts = dataURL.split(';base64,');
const contentType = parts[0].split(':')[1];
const raw = window.atob(parts[1]);
const rawLength = raw.length;
const uInt8Array = new Uint8Array(rawLength);
for (let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], { type: contentType });
}
// Fonction pour afficher les résultats de la comparaison
function displayResults(data) {
let resultHTML = '';
if (data.error) {
resultHTML = `<p class="text-red-600">${data.error}</p>`;
} else {
const similarity = data.verified ? 'Visages similaires' : 'Visages différents';
resultHTML += `<p class="text-lg ${data.verified ? 'text-green-600' : 'text-red-600'}">${similarity}</p>`;
if (data.distance !== undefined && data.threshold !== undefined) {
resultHTML += `<p class="mt-2">Distance : ${data.distance.toFixed(4)}</p>`;
resultHTML += `<p>Seuil de similarité : ${data.threshold.toFixed(4)}</p>`;
}
if (data.image1_url && data.image2_url) {
resultHTML += `<img src="${API_BASE_URL}/${data.image1_url}" alt="Image 1" class="w-32 h-32 mt-4 rounded-lg">`;
resultHTML += `<img src="${API_BASE_URL}/${data.image2_url}" alt="Image 2" class="w-32 h-32 mt-4 rounded-lg">`;
}
}
resultsDiv.innerHTML = resultHTML;
}
</script>
</body>
</html>