E aí galera! Tudo certo?
Hoje vamos continuar aquela nossa aplicação para realizar reconhecimento facial e identificação de pessoas utilizando os serviços cognitivos do Azure. Como é um serviço exposto via HTTP, podemos fazer a aplicação com a linguagem que quisermos; nesse exemplo vamos utilizar Node.js e Angular. Bora lá!
O post vai ser dividido em duas partes:
- Parte 1 (aqui): vamos ver um pouco de como funciona o Azure Cognitive Services, como ele reconhece faces, como utilizar e criar esse serviço no portal do Azure e por fim vamos cadastrar faces em um “banco de faces” para serem reconhecidas posteriormente.
- Parte 2 (esse post): vamos enviar uma face para o serviço de reconhecimento e ver a mágica acontecer.
O que vimos no post anterior?
Na primeira parte desse post, nós aprendemos:
- O que são os serviços cognitivos do Azure;
- Como funciona o reconhecimento facial;
- Como criar um serviço de reconhecimento facial no Azure;
- Como criar listas, enviar imagens e treinar nossa API.
O que veremos hoje?
Como identificar uma face! 😀
Mãos na massa!
Depois de já termos uma “base” de imagens com os nossos supostos clientes, e da nossa API estar treinada e pronta para reconhecer imagens, para fazer o reconhecimento basta fazermos o seguinte:
- Enviar a nossa imagem para um endpoint chamado “detect”, esse endpoint é responsável por identificar faces em imagens; além disso ele também consegue nos trazer alguns atributos sobre as faces encontradas, como por exemplo: gênero, cor, se a pessoa usa maquiagem, óculos ou outro adereço, emoções e afins. Essa imagem que nós vamos enviar pra lá irá receber um identificador e ficará disponível por 24 horas.
- Enviar o identificador da face para um endpoint chamado “findsimilars” que será o responsável por nos trazer imagens semelhantes a imagem que nós enviamos.
O resultado final é esse:
*Me desculpem pela cara de pastel, acabei de sair de uma cirurgia rsrs.
Vejam primeiramente, como ficou a parte do front-end:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="ui-s600"> | |
<form #formReconhecimento="ngForm" class="ui-validate on-dirty on-submit" (submit)="onSubmit(formReconhecimento)"> | |
<ui-card class="elevate-on-toolbar" [class.loading]="loading"> | |
<div class="ui-progress accent" [class.hide]="!loading"> | |
<div class="indeterminate"></div> | |
</div> | |
<ui-toolbar class="flat"> | |
<span class="title">Reconhecimento de clientes</span> | |
</ui-toolbar> | |
<fieldset [disabled]="saving || loading"> | |
<ui-card-content> | |
<div class="ui-flex-container"> | |
<video class="ui-flex-container" id="video-user" [src]="videoSrc" autoplay></video> | |
</div> | |
</ui-card-content> | |
<div [hidden]="true"> | |
<canvas class="ui-flex-container" id="canvas" [width]="videoWidth" [height]="videoHeight"> | |
Seu navegador não suporta Canvas 😦 | |
</canvas> | |
</div> | |
</fieldset> | |
</ui-card> | |
<div class="ui-fab-container"> | |
<button class="ui-button success fab" uiRipple [class.hide]="loading"> | |
<ui-progress-radial class="indeterminate" *ngIf="saving"></ui-progress-radial> | |
<i class="material-icons">check</i> | |
</button> | |
</div> | |
</form> | |
</div> |
Para reconhecer a câmera, foi utilizado o seguinte trecho de código:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
iniciarCamera() { | |
let nav = <any>navigator; | |
nav.getUserMedia = nav.getUserMedia || nav.mozGetUserMedia || nav.webkitGetUserMedia; | |
if (!nav.getUserMedia) { | |
UiSnackbar.show({ | |
text: 'Seu navegador não tem suporte para Webcam' | |
}); | |
return; | |
} | |
let options = { | |
video: true, | |
audio: false | |
}; | |
nav.getUserMedia(options, (stream) => { | |
let webcamUrl = URL.createObjectURL(stream); | |
this.videoSrc = this.sanitizer.bypassSecurityTrustUrl(webcamUrl); | |
let video = this.element.nativeElement.querySelector('#video-user'); | |
video.autoplay = true; | |
let reconhecimento = this; | |
let getVideoSize = function() { | |
reconhecimento.videoWidth = video.videoWidth; | |
reconhecimento.videoHeight = video.videoHeight; | |
video.removeEventListener('playing', getVideoSize, false); | |
}; | |
video.addEventListener('playing', getVideoSize, false); | |
}, (err) => { | |
UiSnackbar.show({ | |
text: 'Ocorreu um erro ao iniciar a Webcam' | |
}); | |
}); | |
} |
E o submit do formulário:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
onSubmit(form) { | |
if (!this.saving) { | |
this.saving = true; | |
let video = this.element.nativeElement.querySelector('#video-user'); | |
let canvas = this.element.nativeElement.querySelector('#canvas'); | |
var ctx = canvas.getContext('2d'); | |
ctx.drawImage(video, 0, 0); | |
this.imagem = canvas.toDataURL("image/jpeg"); | |
this.reconhecimentoService.reconhecer(this.imagem).subscribe(data => { | |
this.saving = false; | |
this.router.navigate(['/reconhecimento', data['content'].idVisita], { replaceUrl: true }); | |
}, e => { | |
this.saving = false; | |
UiSnackbar.show({ | |
text: 'Ocorreu um erro interno, tente novamente mais tarde.' | |
}); | |
}); | |
} | |
} |
A parte da API, que é a mais importante, se comporta dessa maneira:
Faz o upload da imagem, utilizando o endpoint “detect” que foi explicado acima:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
async function uploadFaceParaDeteccao(imageName) { | |
let config = { | |
method: 'POST', | |
uri: `${faceApi}/detect?returnFaceId=true&returnFaceLandmarks=false`, | |
headers: { | |
'Ocp-Apim-Subscription-Key': faceApiKey | |
}, | |
json: true, | |
body: { | |
url: `${blobReconhecimentoUrl}/${imageName}` | |
} | |
}; | |
let response = await request(config); | |
return response; | |
} |
Dentro do objeto response, temos uma lista de faces que foram identificadas na imagem, para cada face identificada, nós faremos a busca por faces similares utilizando o endponit “findsimilar“:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
async function verificarFace(faceId) { | |
let config = { | |
method: 'POST', | |
uri: `${faceApi}/findsimilars`, | |
headers: { | |
'Ocp-Apim-Subscription-Key': faceApiKey | |
}, | |
json: true, | |
body: { | |
faceId: faceId, | |
largeFaceListId: largeFaceListName, | |
maxNumOfCandidatesReturned: 2, | |
mode: "matchPerson" | |
} | |
}; | |
let response = await request(config); | |
return response; | |
}; |
E por fim, o reconhecimento é efetuado:
É isso pessoal! Finalizamos o nosso reconhecimento de clientes 😀
Se tiverem qualquer dúvida sobre essa parte, se algo ficou muito vago ou confuso, me enviem feedbacks que irei dar um jeito 😉
Os códigos utilizados estão disponíveis no GitHub:
Por hoje é só isso, qualquer dúvida ou sugestão, estou à disposição! Até mais 😀
One thought on “Reconhecimento facial com Azure Cognitive Services, Angular e Node.js – Parte 2”