MacBook의 내장 웹캠만 사용해 얼굴 움직임과 표정으로 마우스를 제어하는 Python 프로그램입니다. iPhone 연속성 카메라는 카메라 후보에서 제외합니다. 얼굴 랜드마크는 macOS 내장 Vision 프레임워크로 분석하므로 얼굴 추적에는 MediaPipe나 별도 모델이 필요하지 않습니다. 손쉬운 사용 정보로 찾지 못한 화면 요소를 직접 분석하는 선택 기능에는 로컬 Ollama 비전 모델을 사용합니다.
cd /Users/igyeongmin/Desktop/eyetracker
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtOpenCV 5.x와의 호환 문제를 피하려면 아래 명령으로 4.x 버전을 설치하세요.
python3 -m pip install --upgrade --force-reinstall "opencv-python>=4.9,<5"이미 일부 패키지를 개별 설치했다면, dispatch 모듈까지 포함되도록 다음 명령을 한 번 실행하세요.
python3 -m pip install -U pyobjc-framework-AVFoundation pyobjc-framework-libdispatch pyobjc-framework-Quartz pyobjc-framework-Vision웹페이지처럼 손쉬운 사용 정보가 부족한 화면도 시각적으로 분석하려면 Ollama와 로컬 비전 모델을 설치합니다.
brew install ollama
brew services start ollama
ollama pull qwen2.5vl:3b
ollama listqwen2.5vl:3b 다운로드 크기는 약 3.2GB입니다. Ollama를 설치하지 않아도 얼굴 마우스, 음성 받아쓰기, 기존 접근성 기반 AI 액션은 계속 사용할 수 있습니다.
프로그램은 시작할 때 로컬 비전 모델을 백그라운드에서 예열합니다. 첫 실행의 모델 로딩은 수십 초 걸릴 수 있지만 그동안 얼굴 마우스와 접근성 기반 액션은 그대로 사용할 수 있으며, 예열이 끝나면 터미널에 완료 메시지가 표시됩니다. 사용 중인 모델은 첫 시각 분석 이후 30분 동안 메모리에 유지됩니다.
python head_mouse.py처음 실행하면 macOS가 다음 권한을 요청합니다.
- 카메라: Terminal 또는 사용하는 IDE에 허용
- 손쉬운 사용(Accessibility): 커서 이동을 위해 Terminal 또는 사용하는 IDE에 허용
- 마이크: 음성 입력을 위해
Head Mouse Voice에 허용 - 음성 인식: 음성을 텍스트로 변환하기 위해
Head Mouse Voice에 허용 - 화면 및 시스템 오디오 기록: 로컬 AI가 화면을 분석할 수 있도록 Terminal 또는 사용하는 IDE에 허용한 뒤 해당 앱 재시작
권한 위치: 시스템 설정 → 개인정보 보호 및 보안 → 카메라 / 손쉬운 사용 / 마이크 / 음성 인식 / 화면 및 시스템 오디오 기록
- 얼굴을 화면 중앙에 둔 상태에서
C: 현재 얼굴 위치를 기준점으로 보정 - 양쪽 눈을 빠르게 세 번 깜빡이기: 좌클릭
- 자연스럽게 입을 벌리고 0.7초 유지: 스크롤 모드 켜기/끄기
- 스크롤 모드에서 고개를 위·아래로 이동: 위·아래 스크롤
- 양쪽 눈썹을 0.5초 올리기: 좌클릭 누르기/놓기 토글
- 넓게 미소 짓기를 2초 유지: 한국어 음성 입력 또는 주변 요소 AI 액션 시작
H: 우측 하단 모션 안내 켜기/끄기Q또는Esc: 종료- 카메라 미리보기 창을 클릭한 뒤 키를 누르세요.
시작하거나 C를 누른 직후에는 약 24프레임 동안 정면을 보고 눈을 뜬 채 입을 자연스럽게 다문 표정을 유지하세요. 눈 뜬 정도, 평상시 입 모양, 눈썹 위치를 사용자 얼굴에 맞게 자동 보정합니다.
드래그 중에는 미리보기 테두리가 빨간색으로 표시됩니다. 얼굴을 1초 이상 인식하지 못하거나 프로그램을 종료하면 안전을 위해 좌클릭 누르기 상태가 자동 해제됩니다.
스크롤 모드가 켜져 있는 동안에는 화면 좌측 상단에 스크롤 모드 활성화 상태가 표시됩니다. 음성 인식을 듣는 동안에는 음성 인식 모드 활성화, 로컬 AI가 화면을 보는 동안에는 로컬 AI 화면 분석 중이 같은 위치에 표시됩니다. 상태 표시는 일반 창이 아닌 테두리 없는 반투명 오버레이이며, 마우스 클릭은 아래 앱으로 통과합니다.
프로그램을 실행하면 각 기능과 얼굴 모션을 정리한 테두리 없는 반투명 안내가 화면 우측 하단에 오버레이됩니다. 안내는 항상 위에 표시되지만 마우스 클릭은 아래 앱으로 통과하므로 작업을 방해하지 않습니다. 카메라 미리보기 창을 클릭한 뒤 H 키를 누르면 언제든 숨기거나 다시 표시할 수 있습니다. 안내가 필요 없는 사용자는 다음과 같이 처음부터 숨긴 상태로 실행할 수 있습니다.
python head_mouse.py --hide-guide- 얼굴 마우스로 웹사이트 검색창을 좌클릭합니다.
- 넓게 미소 짓기를 2초 유지합니다.
- 미리보기에
LISTENING...이 표시되면 검색어를 말합니다. - 약 1.5초 동안 말이 없으면 인식을 종료하고 현재 포커스된 검색창에 텍스트를 입력합니다.
음성 입력을 듣는 동안에는 입 벌리기를 포함한 클릭·드래그·스크롤 제스처가 모두 일시 중지되며, 스크롤 모드는 켜지지 않습니다.
음성 입력을 시작하면 현재 마우스 커서에서 약 280px 안에 있는 Dock 및 현재 앱의 실행 가능한 요소를 macOS 손쉬운 사용 정보로 먼저 분석합니다. 인식된 문장이 켜줘, 열어줘, 실행해, 눌러줘, 클릭해, 선택해줘 같은 명령으로 끝나면 검색창에 입력하지 않고 가장 잘 일치하는 주변 요소의 액션을 실행합니다.
예를 들어 Dock의 메모 아이콘 근처에 커서를 둔 다음 넓게 미소 지어 음성 모드를 켜고 다음과 같이 말할 수 있습니다.
메모장 켜줘
애플 뮤직 열어줘
크롬 실행해
이 버튼 눌러줘
오늘 1 달러는 몇 원입니까 텍스트를 클릭해줘
웹페이지에서는 커서 바로 아래의 텍스트뿐 아니라 그 텍스트를 포함하는 상위 링크·버튼도 함께 확인합니다. Chrome에서는 음성 모드를 시작할 때 AXEnhancedUserInterface를 요청해 웹페이지 접근성 트리를 활성화하고, 음성 인식이 끝난 시점에 요소를 다시 분석합니다.
접근성 정보만으로 명령 대상을 찾지 못하면 명령 시점의 커서 중심 1000×760 화면을 캡처합니다. 화면에 목표 문구가 있으면 macOS Vision의 로컬 OCR이 먼저 문구와 정확한 글자 위치를 찾고, OCR로 해결할 수 없는 아이콘·이미지·시각적 컨트롤은 이 Mac에서 실행되는 qwen2.5vl:3b가 분석합니다. 모델이 찾은 텍스트 좌표도 OCR 결과가 있으면 글자 중앙으로 다시 보정합니다.
분석 중에는 얼굴 제스처와 커서 이동이 일시 중지됩니다. 클릭 직전에는 마우스가 원래 위치에서 크게 움직이지 않았는지, 대상 주변 화면이 캡처 시점과 달라지지 않았는지를 다시 확인합니다. 화면이 바뀌었으면 오래된 절대 좌표를 클릭하지 않고 취소하며, 정상 클릭 후에는 실제 위치와 내부 커서 좌표를 동기화합니다.
화면 이미지는 외부 AI API로 전송되지 않고 코드에서 허용한 이 Mac의 루프백 주소(127.0.0.1, localhost, ::1)에 있는 Ollama로만 전달됩니다. 일반적인 검색어나 문장은 기존처럼 현재 포커스된 입력창에 입력됩니다.
로컬 화면 AI가 모든 콘텐츠를 항상 정확히 처리할 수 있는 것은 아닙니다. 화면에 보이는 정적 이미지 기준이므로 DRM·보안 화면, 가려진 요소, 아주 작은 글씨, 비슷한 후보가 여러 개인 화면에서는 실패할 수 있습니다. 기본적으로 확신도 0.70 미만, 커서에서 460px보다 먼 대상, 삭제·결제·전송·권한 허용·다운로드·설치 같은 위험 액션은 접근성 경로와 시각 경로 모두에서 자동 실행하지 않습니다.
다른 로컬 모델이나 Ollama 포트를 사용하려면 다음 옵션을 지정할 수 있습니다. 보안을 위해 원격 Ollama 주소는 허용하지 않습니다.
python head_mouse.py --visual-model qwen2.5vl:3b --ollama-url http://127.0.0.1:11434로컬 화면 AI 폴백을 끄려면 다음과 같이 실행합니다.
python head_mouse.py --no-visual-agent기본 언어는 한국어입니다. 다른 언어를 사용하려면 실행 옵션으로 언어 코드를 지정하세요.
python head_mouse.py --language en-US인식 결과는 클립보드를 거치지 않고 macOS 유니코드 키보드 이벤트로 입력됩니다. 언어 및 시스템 설정에 따라 Apple 음성 인식 서비스가 인터넷 연결을 사용할 수 있습니다.
음성 도우미의 Swift 소스를 수정했거나 실행 파일이 없다면 다음 명령으로 다시 빌드할 수 있습니다. Xcode Command Line Tools가 필요합니다.
./build_voice_helper.sh카메라 미리보기는 화면 좌측 하단에 작게 표시되며, 커서는 전체 화면 영역으로 이동합니다.
커서는 상대 이동 방식입니다. 얼굴을 중앙에서 약간 벗어난 위치로 유지하면 해당 방향으로 계속 이동하며, 중앙 근처의 작은 흔들림은 무시합니다. 처음 0.25초는 목표 위치를 정밀하게 맞출 수 있도록 저속으로 움직이고, 같은 방향을 계속 유지하면 이후 0.75초 동안 부드럽게 가속합니다. 얼굴을 중앙으로 되돌리거나 방향을 반대로 바꾸면 가속 상태가 즉시 초기화됩니다. 따라서 짧게 움직이면 미세 조정이 되고, 작은 각도로 고개를 유지하면 화면 끝까지 빠르게 이동할 수 있습니다.
최고 이동 속도는 --sensitivity로 조절합니다. 기본값 1.8부터 사용하고, 장거리 이동만 과하게 빠르면 값을 조금 낮추세요. --smoothing은 속도 변화의 반응성을 조절하며 높을수록 현재 목표 속도에 빠르게 도달합니다.
python head_mouse.py --sensitivity 1.8 --smoothing 0.75일반적인 OpenCV의 VideoCapture(0) 방식은 macOS가 우선순위를 바꾸면 iPhone 연속성 카메라를 열 수 있습니다. 이 프로그램은 OpenCV로 카메라를 열지 않고, macOS AVFoundation에서 AVCaptureDeviceTypeBuiltInWideAngleCamera인 장치만 명시적으로 선택합니다. 즉 iPhone/연속성 카메라는 선택 후보가 아닙니다. 내장 카메라를 찾지 못하면 다른 카메라로 대체하지 않고 오류를 표시합니다.
그래도 시스템 전체에서 연속성 카메라를 끄고 싶다면 iPhone의 설정 → 일반 → AirPlay 및 연속성 → 연속성 카메라도 끌 수 있습니다.