Version avec détection des visages

This commit is contained in:
jac 2021-06-01 16:48:41 +02:00
parent c99e855c56
commit 0dc644da75
4 changed files with 45641 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

48
opencv.js Normal file

File diff suppressed because one or more lines are too long

544
photo_mem_cv.html Normal file
View File

@ -0,0 +1,544 @@
<!DOCTYPE HTML>
<!-- Photo_mem
Version 2.0 avec détection de visages
Copyright © 2017-2021 J. PLISSON
Licence AGPL v3.0+
-->
<html>
<head>
<meta charset="utf-8"/>
<style>
circle {
fill: transparent;
stroke: black;
stroke-width: 2;
}
#bouton_image {background-color:green;color:white;height: 30px;}
#bouton_faces {background-color:blue;color:white;height: 30px;}
#menu_modif {
display: block;
color: black;
background-color: gainsboro;
cursor: pointer;
border: 2px solid;
border-radius: 6px;
text-align: center;
position: absolute;
width: 80px;
z-index: 10;
}
#ajout {
border:2px solid red;
border-radius: 10px;
top: 100px;
left: 200px;
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-left: 1em;
background-color: Azure;
width: 230px;
}
#ajout input:focus {border: solid 2px green;}
.cotecote {display: inline;}
.visible { visibility:visible; }
.invisible { visibility:hidden; }
.etiq {
background-color:oldlace;
border:1px solid blue;
border-radius: 10px;
position:absolute;
font-family: Arial;
font-size: 13px;
left:-200px;
top: 100px;
}
.tit {
background-color:LightYellow;
border: 2px solid Yellow;
border-radius: 5px;
position:absolute;
left:-200px;
top: 100px;
}
</style>
</head>
<body>
<input id="file_image" multiple type="file" class=cotecote style="display:none"/>
<button id="bouton_image" onclick="file_image.click()" title="Charger une image et le XML associé" >Choix de la photo</button>
<input id="file" type="button" class=cotecote value="Enregistrer xml" onclick="enregistrer_fichier(enreg_xml)"/>
<input id="file" type="button" class=cotecote value="Enregistrer image " onclick="image_finale()"/>
<button id="bouton_faces" onclick="file_image.click()" title="Charger une image et le XML haarcascade">Détection des visages</button>
<p id="status" class=cotecote >OpenCV.js chargement en cours...</p>
<div style="position: relative; ">
<img src="" id="ima_fond" style="position: absolute; left: 0; top: 0; z-index: 0;">
</div>
<svg class="invisible" style="position: absolute" ;>
<circle id="cirsvg" cx="30" cy="30" r="28" />
</svg>
<div id="ajout" class="invisible" style="position: relative; z-index: 1;">
<form name="ajout_personne">
<center><font color="green">NOUVELLE PERSONNE</font></center>
Nom : <INPUT type="text" name="nom" id="nom" autofocus><BR>
Née : <INPUT type="text" name="nom_jf" id="nom_jeune_fille"><BR>
Prénom : <INPUT type="text" name="prénom" id="prenom"><BR>
Année : <INPUT type="text" name="année" id="annee"><BR>
Note : <INPUT type="text" name="note" id="note"><BR>
<INPUT type="reset" id="enreg" value="Ajouter" onClick=ajouter_personne_xml();>
<INPUT type="reset" value="Annuler" onClick=document.getElementById("ajout").className="invisible";>
</form>
</div>
<div id="menu_modif" class="invisible">
<div id="modifier" onClick="window.print();menu.style.visibility='hidden';">modifier </div>
<div id="supprimer" onClick="supprimer_personne();menu.style.visibility='hidden';">supprimer</div>
<div id="annuler" onClick="menu.style.visibility='hidden';">annuler</div>
</div>
<script>
var personnes=[],nom=[],nomjf=[],prenom=[],posx=[],posy=[],etx=[],ety=[], can_etiq=[];
var ibac=0, tit={}, titre="";
var image = document.getElementById('ima_fond');
var cercle = document.getElementById("cirsvg");
var menu = document.getElementById("menu_modif");
var cant = document.createElement("canvas");
document.body.appendChild(cant);
let inputElement = document.getElementById('file_image');
inputElement.addEventListener('change', (e) => {
lecfic(e.target.files)
}, false);
function lecfic(fichier) {
i_xml=0;
if (fichier.length==2) {
for (var i = 0; i < fichier.length; i++) {
var ext=fichier[i].name.split('.').pop();
if (ext=="xml") {i_xml=i};
} ;
}
else {
alert("Choisissez deux fichiers : un .xml et un fichier image");
return;
}
i_img=((i_xml-1)<0 ? 1 : 0);
fichier_xml=fichier[i_xml];
fond=fichier[i_img];
var src=fichier[i_img].name.substring(0,fichier[i_img].name.indexOf("."));
enreg_xml=src+".xml"
enreg_noms=src+"_noms.png"
if (fichier_xml.name.startsWith("haar")) { detection_de_visages()}
else {
var reader = new FileReader();
reader.onload = function(evt) {lecture(evt.target.result);};
reader.readAsText(fichier_xml);
function lecture(text) {
var parser = new DOMParser();
data_xml = parser.parseFromString(text,"text/xml");
affiche_fond();
lecture_xml();
};
};
}
function detection_de_visages() {
affiche_fond();
alert("Ok pour continuer")
src = cv.imread(ima_fond);
// cv.imshow('canvasOutput', src);
gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
// cv.imshow('canvasOutput', gray);
chargement_haarcascade();
}
function chargement_haarcascade() {
var reader_haar = new FileReader();
reader_haar.onload = function(ev) {
function str2ab(text) {
return new TextEncoder().encode(text);
}
faceCascadeFile = 'haarcascade_frontalface_alt2.xml';
let data=str2ab(reader_haar.result)
//console.log("array "+data);
cv.FS_createDataFile('/', faceCascadeFile, data, true, false, false);
creation_data_xml()
};
reader_haar.readAsText(fichier_xml);
}
function creation_data_xml() {
var x, i;
var txt = "";
var text = "<photo>" +
"<titre titx='50px' tity='50px'>Titre "+ fond.name + "</titre>" +
"<date> </date>" +
"<lieu> </lieu>" +
"<commentaire> </commentaire>" +
"</photo>";
var parser_face = new DOMParser();
data_xml = parser_face.parseFromString(text,"text/xml");
// documentElement always represents the root node
x = data_xml.documentElement.childNodes;
for (i = 0; i < x.length ;i++) {
txt += x[i].nodeName + ": " + x[i].childNodes[0].nodeValue + "<br>";
}
let faces = new cv.RectVector();
let faceCascade = new cv.CascadeClassifier();
// load pre-trained classifiers
faceCascade.load(faceCascadeFile);
// detect faces
let msize = new cv.Size(0, 0);
faceCascade.detectMultiScale(gray, faces, 1.1, 3, 0, msize, msize);
console.log("Il y a "+ faces.size()+" visage(s)")
for (let i = 0; i < faces.size(); ++i) {
ajouter_face_xml("nom_"+parseInt(i)+" ",faces.get(i).x,faces.get(i).y,faces.get(i).width,faces.get(i).height)
}
// cv.imshow('ima_fond', src);
src.delete(); gray.delete(); faceCascade.delete();
faces.delete();
lecture_xml();
;}
// detect faces
function ajouter_face_xml(nom_face,fx,fy,fw,fh) {
// création d'un nouvel élément <personne> dans data_xml
var personne_ = data_xml.createElement("personne");
var nom_ = data_xml.createElement("nom");
nom_.appendChild(data_xml.createTextNode(nom_face));
var nom_jf_ = data_xml.createElement("nom_jeune_fille");
nom_jf_.appendChild(data_xml.createTextNode(""));
var prenom_ = data_xml.createElement("prenom");
prenom_.appendChild(data_xml.createTextNode("prenom"));
var surnom_ = data_xml.createElement("surnom");
surnom_.appendChild(data_xml.createTextNode(" "));
var annee_ = data_xml.createElement("annee_naiss");
annee_.appendChild(data_xml.createTextNode(" "));
var note_ = data_xml.createElement("note");
note_.appendChild(data_xml.createTextNode(" "));
var position_ = data_xml.createElement("position");
position_.setAttribute("posx", fx+fw/2);
position_.setAttribute("posy", fy+fh/2);
position_.setAttribute("etx", fx+10);
position_.setAttribute("ety", fy+fh*2);
personne_.appendChild(nom_);
personne_.appendChild(nom_jf_);
personne_.appendChild(prenom_);
personne_.appendChild(surnom_);
personne_.appendChild(annee_);
personne_.appendChild(note_);
personne_.appendChild(position_);
data_xml.getElementsByTagName("photo")[0].appendChild(personne_)
};
function lecture_xml() {
personnes = data_xml.documentElement.getElementsByTagName("personne");
tit = data_xml.documentElement.getElementsByTagName("titre")[0];
titre=tit.textContent
nb_pers=personnes.length
for (var i = 0; i < nb_pers; i++) {
nom[i] = personnes[i].getElementsByTagName( "nom")[0].textContent;
if (personnes[i].getElementsByTagName( "nom_jeune_fille")[0]) {
nomjf[i] = personnes[i].getElementsByTagName( "nom_jeune_fille")[0].textContent};
prenom[i] = personnes[i].getElementsByTagName( "prenom")[0].textContent;
posx[i] = parseFloat(personnes[i].getElementsByTagName( "position")[0].attributes['posx'].value);
posy[i] = parseFloat(personnes[i].getElementsByTagName( "position")[0].attributes['posy'].value);
etx[i] = parseFloat(personnes[i].getElementsByTagName( "position")[0].attributes['etx'].value);
ety[i] = parseFloat(personnes[i].getElementsByTagName( "position")[0].attributes['ety'].value);
}
if (titre!=='') {affiche_titre()}
else {affiche_etiquette()} ;
};
// Chargement et dessin de l'image background
function affiche_fond() {
var read_fond = new FileReader();
read_fond.addEventListener("load", function (evt) {
image.src = evt.target.result;
}, false);
read_fond.readAsDataURL(fond);
}
function affiche_titre() {
cant.className="tit";
cant.height=23;
var taille=titre.length;
cant.width=taille*12;
tx = parseFloat(tit.attributes['titx'].value);
ty = parseFloat(tit.attributes['tity'].value);
cant.style.left = tx + "px";
cant.style.top = ty + "px";
titre_ctx = cant.getContext("2d");
titre_ctx.font = '21px Arial';
titre_ctx.fillStyle = 'Maroon';
titre_ctx.fillText(titre, 20, 18);
affiche_etiquette();
}
function affiche_etiquette() {
// affichage du texte nom/prénom dans des canvas etiquette
rayon=28
for (var i = 0; i < nb_pers; i++) {
var id="can"+i;
if (document.getElementById(id)) continue ;
var canv = document.createElement("canvas");
canv.id=id;
document.body.appendChild(canv);
can_etiq[i] = document.getElementById(canv.id);
can_etiq[i].className="etiq";
can_etiq[i].height=30;
etiq_ctx = can_etiq[i].getContext("2d");
var taille=Math.max(nom[i].length,prenom[i].length,nomjf[i].length+5);
can_etiq[i].width=taille*7+10
//alert("nomjf ="+nomjf[i]+" code :"+nomjf[i].charCodeAt(1))
// if (!nomjf[i].charCodeAt(1)==9) {can_etiq[i].height=45};
if (nomjf[i].replace(/\t/g, '').length>1) {can_etiq[i].height=45};
etiq_ctx.font = '13px Arial';
etiq_ctx.fillStyle = 'chocolate';
can_etiq[i].style.left = etx[i] + "px";
can_etiq[i].style.top = ety[i] + "px";
etiq_ctx.fillText(nom[i], 7, 12);
etiq_ctx.fillText(prenom[i], 7, 25);
if (nomjf[i].length>1) {etiq_ctx.fillText("née : "+nomjf[i], 7, 38)};
};
gestion_souris(); // enregistre la position de l'étiquette
};
function gestion_souris() {
if (titre!=='') { // pour déplacer le titre
cant.addEventListener("mousedown", function(e){this.addEventListener("mousemove", deplace_etiquette);});
cant.addEventListener("mouseup", function(e){this.removeEventListener("mousemove", deplace_etiquette);});
}
for (var i = 0; i < nb_pers; i++) { // pour déplacer les étiquettes nom,prénom ...
can_etiq[i].addEventListener("mousedown", function(e){this.addEventListener("mousemove", deplace_etiquette);});
can_etiq[i].addEventListener("mouseup", function(e){this.removeEventListener("mousemove", deplace_etiquette);});
};
ima_fond.addEventListener('mousedown', afficher_formulaire); // pour afficher le formulaire de saisie personne
ima_fond.addEventListener('mousemove', tracer_cercle); // pour afficher cercle personne
cercle.addEventListener('contextmenu', function (e) { menu_modif(e); e.preventDefault();}, false); // menu modif personne
};
function deplace_etiquette(e){
e.target.style.top = e.pageY-15+"px";
e.target.style.left = e.pageX-30+"px";
};
function menu_modif(){
menu.style.left = parseFloat(cercle.getAttribute("cx"))+10 +"px";
menu.style.top = parseFloat(cercle.getAttribute("cy"))+40 +"px";
menu.style.visibility="visible";
}
function supprimer_personne() {
misajour_xml();
x = data_xml.getElementsByTagName("personne")[ibac];
x.parentNode.removeChild(x);
for (var i = 0; i < nb_pers; i++) {
x = can_etiq[i];
x.parentNode.removeChild(x);
};
cercle.style.visibility="hidden";
lecture_xml();
}
function position_souris(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
};
function tracer_cercle(e) {
document.getElementsByTagName("svg")[0].setAttribute('height', image.naturalHeight);
document.getElementsByTagName("svg")[0].setAttribute('width',image.naturalWidth);
var pos_x=position_souris(ima_fond, e).x;
var pos_y=position_souris(ima_fond, e).y;
for (var i = 0; i < nb_pers; i++) {
var dx = posx[i] - pos_x;
var dy = posy[i] - pos_y;
var dist2 = dx * dx + dy * dy;
var rayon2 = rayon * rayon;
if (dist2 < rayon2) {
ibac=i
// bac=can_etiq[i].style.backgroundColor;
can_etiq[i].style.background = "palegreen"
cercle.setAttribute("cx",posx[i]);
cercle.setAttribute("cy",posy[i]);
cercle.setAttribute("r",rayon);
cercle.style.visibility="visible";
// grossir ou diminuer la taille du cercle
// cercle.addEventListener("wheel", function(e) {
// rayon=rayon + (e.deltaY>0 ? -1 : +1);
// cercle.setAttribute("r",rayon );
// } , false);
return
}
};
cercle.style.visibility="hidden";
can_etiq[ibac].style.backgroundColor = "oldlace";
};
function afficher_formulaire(e) {
souris_x = position_souris(ima_fond, e).x ;
souris_y = position_souris(ima_fond, e).y;
if (souris_y-document.getElementById('ajout').height<0) sourisy=50;
document.getElementById('ajout').style.top=souris_y+40+"px";
document.getElementById('ajout').style.left=souris_x-80+"px";
setTimeout(function () { document.getElementById("nom").focus(); },10);
document.getElementById('ajout').className='visible';
};
function ajouter_personne_xml() {
// création d'un nouvel élément <personne> dans data_xml
var nomform=document.getElementById("nom").value
var nomjfform=document.getElementById("nom_jeune_fille").value
var prenomform=document.getElementById("prenom").value
var surnomform=""
var anneeform=document.getElementById("annee").value
var noteform=document.getElementById("note").value
document.getElementById('ajout').className='invisible';
console.log(nomform+" "+prenomform+" "+anneeform)
var personne_ = data_xml.createElement("personne");
var nom_ = data_xml.createElement("nom");
nom_.appendChild(data_xml.createTextNode(nomform));
var nom_jf_ = data_xml.createElement("nom_jeune_fille");
nom_jf_.appendChild(data_xml.createTextNode(nomjfform));
var prenom_ = data_xml.createElement("prenom");
prenom_.appendChild(data_xml.createTextNode(prenomform));
var surnom_ = data_xml.createElement("surnom");
surnom_.appendChild(data_xml.createTextNode(surnomform));
var annee_ = data_xml.createElement("annee_naiss");
annee_.appendChild(data_xml.createTextNode(anneeform));
var note_ = data_xml.createElement("note");
note_.appendChild(data_xml.createTextNode(noteform));
var position_ = data_xml.createElement("position");
position_.setAttribute("posx", souris_x);
position_.setAttribute("posy", souris_y);
position_.setAttribute("etx", souris_x-30);
position_.setAttribute("ety", souris_y+60);
personne_.appendChild(nom_);
personne_.appendChild(nom_jf_);
personne_.appendChild(prenom_);
personne_.appendChild(surnom_);
personne_.appendChild(annee_);
personne_.appendChild(note_);
personne_.appendChild(position_);
data_xml.getElementsByTagName("photo")[0].appendChild(personne_)
lecture_xml();
};
function misajour_xml(){
tit.setAttribute("titx",cant.style.left);
tit.setAttribute("tity",cant.style.top);
for (var i = 0; i < nb_pers; i++) {
position=data_xml.getElementsByTagName( "position")[i];
position.setAttribute("etx",can_etiq[i].style.left);
position.setAttribute("ety",can_etiq[i].style.top);
};
lecture_xml();
} ;
function enregistrer_fichier(fichier) {
misajour_xml()
var texte_xml=(new XMLSerializer()).serializeToString(data_xml)
texte_xml=formatXml(texte_xml)
var blob = new Blob([texte_xml], {type: "text/plain;charset=utf-8"});
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, fichier);
} else {
var a = document.createElement('a');
if (a.download === '');
a.setAttribute('download', fichier);
a.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(texte_xml));
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
}
function formatXml(xml, tab) { // tab = optional indent value, default is tab (\t)
var formatted = '', indent= '';
tab = tab || '\t';
xml.split(/>\s*</).forEach(function(node) {
if (node.match( /^\/\w/ )) indent = indent.substring(tab.length); // decrease indent by one 'tab'
formatted += indent + '<' + node + '>\r\n';
if (node.match( /^<?\w[^>]*[^\/]$/ )) indent += tab; // increase indent
});
return formatted.substring(1, formatted.length-3);
}
function image_finale() {
misajour_xml()
var decalx=5;
var decaly=29;
var can_imf = document.createElement("canvas");
document.body.appendChild(can_imf);
imf_ctx = can_imf.getContext("2d");
can_imf.width=ima_fond.width;
can_imf.height=ima_fond.height;
imf_ctx.drawImage(ima_fond,0,0)
if (titre!=='') {
var taille=titre.length;
hauteur=25
roundedRect(imf_ctx,tx-decalx,ty-decaly,taille*11,hauteur,5,'lightyellow','yellow');
imf_ctx.drawImage(cant, tx-decalx, ty-decaly)
};
for (var i = 0; i < nb_pers; i++) {
var taille=Math.max(nom[i].length,prenom[i].length,nomjf[i].length+5);
hauteur=30
if (nomjf[i].replace(/\t/g, '').length>1) {hauteur=45};
// if (!nomjf[i].charCodeAt(1)==9) {hauteur=45};
roundedRect(imf_ctx,etx[i]-decalx,ety[i]-decaly,taille*7+10,hauteur,15,'oldlace','blue');
imf_ctx.drawImage(can_etiq[i],etx[i]-decalx,ety[i]-decaly)
}
var a = document.createElement('a');
if (a.download === '');
a.setAttribute('download', enreg_noms);
a.setAttribute('href', can_imf.toDataURL("image/png").replace("image/png", "image/octet-stream"));
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
document.body.removeChild(can_imf);
function roundedRect(ctx, x, y, width, height, radius ,couleur_fond ,couleur_trait) {
ctx.beginPath();
ctx.strokeStyle = couleur_trait;
ctx.moveTo(x, y + radius);
ctx.lineTo(x, y + height - radius);
ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
ctx.lineTo(x + width - radius, y + height);
ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
ctx.lineTo(x + width, y + radius);
ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
ctx.lineTo(x + radius, y);
ctx.quadraticCurveTo(x, y, x, y + radius);
ctx.closePath();
ctx.fillStyle = couleur_fond;
ctx.fill();
ctx.stroke();
}
}
</script>
<script>
function onOpenCvReady() {
document.getElementById('status').innerHTML = 'OpenCV.js est chargé !';
}
</script>
<script src="opencv.js" onload="onOpenCvReady();" type="text/javascript"></script>
</body>
</html>