본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 16. 06:14

브라우저에서 구현한 웹캠 수어 판독기 (클라우드 미사용)

요약

MediaPipe와 WebAssembly를 활용하여 클라우드 연결 없이 브라우저 내에서 온디바이스로 동작하는 웹캠 수어 판독기 구현 방법을 소개합니다. 손의 21개 랜드마크 좌표를 기하학적으로 분석하여 손가락 패턴을 인식하고 수어로 변환하는 과정을 다룹니다.

핵심 포인트

  • MediaPipe를 통한 브라우저 기반 온디바이스 손 추적 구현
  • 21개의 랜드마크 좌표를 활용한 손가락 상태 판별
  • 기하학적 계산을 통한 손가락 펴짐 상태 및 엄지 인식 로직
  • 디바운스 처리를 통한 수어 입력의 안정성 확보

"수어를 읽는 AI"라고 하면 연구실과 GPU 클러스터가 떠오를지도 모릅니다. 하지만 진정으로 유용한 초기 버전은 모델 업로드도, 클라우드도 없이 여러분의 브라우저에서 완전히 실행될 수 있습니다. 즉, 카메라 피드가 기기를 절대 벗어나지 않습니다. 제가 어떻게 웹캠 수어 판독기를 처음부터 구축했는지 소개합니다.

이 프로젝트는 매일 실질적이고 유용한 문제를 해결하는 SolveFromZero의 7일 차 기록입니다.

브라우저는 손을 추적할 수 있습니다

서버나 카메라 SDK가 필요하지 않습니다. Google의 MediaPipe는 WebAssembly를 통해 브라우저 탭 내에서 바로 실행되는 아주 작은 손 추적 (hand-tracking) 모델을 제공합니다. 비디오 프레임을 전달하면 손의 스켈레톤 (skeleton)을 돌려받습니다. 이 모든 과정은 온디바이스 (on-device)에서 이루어집니다.

import { HandLandmarker, FilesetResolver } from
  "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/vision_bundle.mjs";
const hand = await HandLandmarker.createFromOptions(files, { runningMode: "VIDEO" });

손 하나당 21개의 포인트

모델은 매 프레임마다 **21개의 랜드마크 (landmarks)**를 반환합니다. 이는 손목과 각 손가락당 4개의 포인트(너클, 두 개의 관절, 끝부분)로 구성되며, 각각 0에서 1 사이의 (x, y, z) 좌표로 제공됩니다. 이 스켈레톤만 있으면 충분하며, 더 이상 가공되지 않은 픽셀 (raw pixels)을 직접 다룰 필요가 없습니다.

const lm = hand.detectForVideo(video, performance.now()).landmarks[0];  // 21 points

손가락 끝이 너클보다 높으면 "펴진" 상태입니다

기하학 (Geometry)이 인식을 수행합니다. 대략적으로 똑바로 세운 손의 경우, 손가락 끝이 중간 관절보다 화면상에서 더 높이 있으면 (y값이 더 작으면) 손가락이 펴진 상태입니다. 네 손가락에 대해 이 조건을 확인하면 몇 개의 손가락이 올라가 있는지 즉시 알 수 있습니다.

const up = [8, 12, 16, 20].map((tip, i) =>
  lm[tip].y < lm[[6, 10, 14, 18][i]].y);

엄지는 까다로운 존재입니다

엄지는 위가 아니라 옆으로 굽히기 때문에, '끝이 너클보다 높음' 방식의 트릭이 통하지 않습니다. 대신 엄지 끝이 손에서 얼마나 멀리 튀어나와 있는지를 측정해야 합니다. 멀리 있을수록 펴진 상태입니다. 엄지를 별도로 처리하는 것은 제스처 코드 작성 시 발생하는 전형적인 주의 사항 (gotcha)입니다.

const thumb = dist(lm[4], lm[5]) > 0.13;

손가락 패턴을 수어에 매핑하기

이제 들어 올려진 손가락의 패턴을 의미로 변환합니다. 손가락 없음 = 0, 검지만 있음 = 1, 검지+중지 = 2, 다섯 손가락 모두 = 펼친 손바닥 "hi", 엄지만 있음 = 👍:

if (!thumb && count === 0) return "0";
if (!thumb && count === 2) return "2";
if (thumb  && count === 4) return "hi";

이는 하드코딩된 룩업 (lookup) 방식입니다. 단순하고 투명하며, 숫자 세기와 몇 가지 제스처를 처리하기에는 충분합니다.

확정하기 위해 유지하기 (Hold to commit)

손은 흔들리기 때문에, 수어가 약 12 프레임(frames) 동안 안정적으로 유지되었을 때만 해당 수어를 "입력(type)"합니다. 이러한 디바운스 (debounce) 처리는 손이 수어 사이를 이동할 때 전사 (transcript) 내용이 노이즈로 가득 차는 것을 방지합니다.

if (sign === lastSign) stable++; else stable = 0;
if (stable === 12) type(sign);

실제 ASL(미국 수어)로 확장하기

이 데모는 순수 기하학 (geometry)만으로 0~5까지의 숫자와 몇 가지 제스처를 인식합니다. 수십 개의 알파벳, 움직임, 양손, 얼굴 표정 등을 포함하는 완전한 ASL을 구현하려면, 동일한 21개의 랜드마크 (landmarks) 위에 놓일 작은 **학습된 분류기 (trained classifier)**가 필요합니다. 하지만 바로 그 점이 아름다운 부분입니다. 어려운 인지 (perception) 작업(손을 찾는 것)은 이미 완료되어 있으며, 실제 서비스를 위해 구축하게 될 파이프라인 (pipeline)은 바로 여기 구현된 것과 정확히 일치합니다. 랜드마크를 입력받아 수어를 출력하는, 완전히 온디바이스 (on-device) 방식으로 작동합니다.

또한 이는 많은 "AI" 제품들이 모델이 20%이고, 그 출력을 유용한 무언가로 바꾸는 과정이 80%라는 사실을 상기시켜 줍니다.

👉 웹캠으로 직접 시도해보세요 (Chrome/Edge, 카메라 권한 허용 필요): https://dev48v.infy.uk/solve/day7-sign-language.html

🌐 모든 솔루션: https://dev48v.infy.uk/solvefromzero.php

내일 예고: 브라우저에서 구현하는 모든 영상용 실시간 자막 (live captions).

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0