{"id":646,"date":"2026-09-16T15:55:03","date_gmt":"2026-09-16T12:55:03","guid":{"rendered":"https:\/\/sandrobenigno.com.br\/blog\/?p=646"},"modified":"2026-09-16T16:47:15","modified_gmt":"2026-09-16T13:47:15","slug":"neurais-e-expressao-facial-web-mediapipe-p5-js","status":"publish","type":"post","link":"https:\/\/sandrobenigno.com.br\/blog\/2026\/09\/16\/neurais-e-expressao-facial-web-mediapipe-p5-js\/","title":{"rendered":"Redes Neurais e Express\u00e3o Facial &#8211; Web (MediaPipe + p5.js)"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\"><\/h2>\n\n\n\n<p>Meu projeto original no LAC-EBA-UFMG dependia de um pipeline cl\u00e1ssico em desktop: Python, OpenCV, ONNX (RFB-320 + PFLD) e envio de UDP direto para um sketch Java no Processing. Funcionava redondo, mas exigia instalar runtime, configurar drivers de webcam e lidar com depend\u00eancias locais.<\/p>\n\n\n\n<p>Decidi levar esse experimento 100% para o browser, mantendo o car\u00e1ter explorat\u00f3rio e a precis\u00e3o do c\u00e1lculo facial, mas com zero instala\u00e7\u00e3o. Funciona inclusive em celulares, com uma formata\u00e7\u00e3o din\u00e2mica otimizada.<\/p>\n\n\n\n<p><a href=\"https:\/\/sandrobenigno.github.io\/Interfaces_com_Redes_Neurais_e_Expressao_Facial_WEB\" target=\"_blank\" rel=\"noreferrer noopener\">Experimente online!<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">A mec\u00e2nica no navegador<\/h3>\n\n\n\n<p>Tudo roda client-side via <strong>MediaPipe Face Mesh<\/strong> acelerado por WebAssembly e WebGL, mapeando os 468 landmarks faciais em tempo real.<\/p>\n\n\n\n<p>Para a detec\u00e7\u00e3o do piscar, implementei o c\u00e1lculo cl\u00e1ssico de <strong>EAR (Eye Aspect Ratio)<\/strong> de Soukupov\u00e1 &amp; Cech em JavaScript puro, acoplado a uma m\u00e1quina de estados com histerese configur\u00e1vel (<code>setP_fechar<\/code> e <code>setP_abrir<\/code>) via sliders na tela. Isso evita falsos positivos por microoscila\u00e7\u00f5es.<\/p>\n\n\n\n<p>O cl\u00e1ssico sketch das bolinhas coloridas (<code>Bolinhas_OSC_PISCADAS<\/code>) virou um m\u00f3dulo em <strong>p5.js<\/strong>. A grande sacada arquitetural aqui foi desacoplar a vis\u00e3o computacional da interface visual:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Em vez de fundir tudo num mon\u00f3lito, a comunica\u00e7\u00e3o interna usa <strong><code>BroadcastChannel<\/code><\/strong> (com fallback para <code>postMessage<\/code>).<\/li>\n\n\n\n<li>D\u00e1 para rodar a c\u00e2mera e o sketch divididos na mesma aba ou abrir as bolinhas em uma janela\/monitor pop-up separado \u2014 a sincronia continua instant\u00e2nea.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">A Bridge: saindo do DOM para o mundo real<\/h3>\n\n\n\n<p>O diferencial mais divertido desse experimento \u00e9 n\u00e3o deixar os dados presos no ecossistema web. Para plugar o navegador com DAWs, sintetizadores ou ambientes visuais, criei uma <strong>bridge leve em Python<\/strong> (<code>websockets<\/code> + <code>python-osc<\/code>):<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>O browser envia o stream via WebSocket local.<\/li>\n\n\n\n<li>A bridge converte os pacotes e dispara via <strong>OSC sobre UDP<\/strong>.<\/li>\n\n\n\n<li>Softwares como <strong>PureData, Processing, SuperCollider ou Reaper<\/strong> recebem tudo em tempo real na porta configurada (default <code>12345<\/code>).<\/li>\n<\/ol>\n\n\n\n<p>Al\u00e9m do evento discreto <code>\/piscou<\/code>, a aplica\u00e7\u00e3o joga um fluxo cont\u00ednuo a ~30 Hz mapeando:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>\/head\/angles<\/code>: pitch, roll e yaw da cabe\u00e7a em graus<\/li>\n\n\n\n<li><code>\/eye\/open<\/code>: abertura ocular normalizada<\/li>\n\n\n\n<li><code>\/mouth\/mar<\/code>: Mouth Aspect Ratio (abertura vertical da boca)<\/li>\n\n\n\n<li><code>\/brow\/raise<\/code>: eleva\u00e7\u00e3o das sobrancelhas<\/li>\n<\/ul>\n\n\n\n<p>Com isso, um simples piscar de olhos ou a inclina\u00e7\u00e3o da cabe\u00e7a vira gatilho de sampler, modula\u00e7\u00e3o de filtro de \u00e1udio ou controle de c\u00e2mera 3D \u2014 rodando direto do GitHub Pages, com uma pontezinha UDP discreta fazendo o trabalho pesado de integra\u00e7\u00e3o.<\/p>\n\n\n\n<p>Para obter o c\u00f3digo e informa\u00e7\u00f5es mais detalhadas, acesse o link do projeto no GitHub:<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/sandrobenigno\/Interfaces_com_Redes_Neurais_e_Expressao_Facial_WEB\" target=\"_blank\" rel=\"noreferrer noopener\">Interfaces_com_Redes_Neurais_e_Expressao_Facial_WEB<\/a><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Meu projeto original no LAC-EBA-UFMG dependia de um pipeline cl\u00e1ssico em desktop: Python, OpenCV, ONNX (RFB-320 + PFLD) e envio [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":652,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-646","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-nao-especificada"],"_links":{"self":[{"href":"https:\/\/sandrobenigno.com.br\/blog\/wp-json\/wp\/v2\/posts\/646","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sandrobenigno.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sandrobenigno.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sandrobenigno.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sandrobenigno.com.br\/blog\/wp-json\/wp\/v2\/comments?post=646"}],"version-history":[{"count":9,"href":"https:\/\/sandrobenigno.com.br\/blog\/wp-json\/wp\/v2\/posts\/646\/revisions"}],"predecessor-version":[{"id":662,"href":"https:\/\/sandrobenigno.com.br\/blog\/wp-json\/wp\/v2\/posts\/646\/revisions\/662"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sandrobenigno.com.br\/blog\/wp-json\/wp\/v2\/media\/652"}],"wp:attachment":[{"href":"https:\/\/sandrobenigno.com.br\/blog\/wp-json\/wp\/v2\/media?parent=646"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sandrobenigno.com.br\/blog\/wp-json\/wp\/v2\/categories?post=646"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sandrobenigno.com.br\/blog\/wp-json\/wp\/v2\/tags?post=646"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}