안녕하세요. 영상 통화로 사람의 감정을 이해하는 인공지능을 만드는 스타트업을 시작한 클량 아재입니다.
어제 펨코에서 윤석열 후보의 도리도리 횟수를 직접 1321회나 카운트하신 글을 보고는 뭔가 안타까운(?) 마음이 들어서 팀원과 함께 잠깐 재능 낭비 코딩을 해보았습니다.
인간의 행동을 관찰하는 인공지능을 코딩하는 방법에 관심있으신 분은 따라해보기에 괜찮은 것 같아요. 모든 코드는 깃헙(https://github.com/Whew-AI-Inc/Doridori-Counter)에 공개되어 있으니 마음껏 가져다 쓰시면 됩니다.
결과
유튜브로 결과 영상을 올려보았습니다. 0.1 버전이라 좀 나이브한 면이 있지만 실시간 그래프와 영상을 연결해보니 그럴싸하게 작동합니다 :)
도리도리 카운터 (v0.1) 유튜브 링크
동기
- 사람의 감정을 분석하면 그 사람이 중요시 여기는 사안, 불안한 정도, 긴장한 지점 등 다양한 정보를 얻어낼 수 있습니다.
- 대한민국의 방향을 결정하는 자리에 오를 대선 후보가 미처 숨기지 못하는 감정의 최근 상태와 그 변화를 이해하는 것은 유권자 입장에서도 매우 중요한 일이라 생각됩니다.
- 사실 윤후보의 도리도리가 하도 유명하다보니 '도대체 어느 정도길래' 라는 궁금증이 가장 컸습니다.
아이디어
- 아이디어는 단순합니다. '얼굴의 각도의 변화를 계산하여 카운트만 하면 되겠네!' 입니다. 하지만 그것도 나름 아이디어들이 필요했습니다. 특히, 아래와 같이 몇 가지 이슈가 있었습니다.
- 기준점을 어떻게 정의할 것인가?
- 변화량을 어떻게 계산할 것인가?
- 어떤 방법으로 카운팅 할 것인가?
- 아래 개발 과정에서 위 아이디어를 어떻게 풀어나갔는지 적어보겠습니다.
개발 과정
-
기준점을 어떻게 정의할 것인가?
-
얼굴 랜드마크 디텍션
- 사람의 얼굴에서 기준이 되는 표준 포인트들을 얼굴 랜드마크라고 합니다. 랜드마크를 찾는 딥러닝 모델은 다양한 종류가 있습니다. 이번에는 구글 미디어파이프의 페이스 메쉬(https://google.github.io/mediapipe/solutions/face_mesh)를 사용하기로 합니다. 미디어파이프의 페이스 메쉬는 아래와 같이 얼굴에서 468개의 3D 랜드마크를 찾아줍니다. 미디어파이프는 안드로이드, 자바스크립트 등 다양한 플랫폼에서 이용 가능하고 성능도 매우 안정적인 모델입니다.
- 사람의 얼굴에서 기준이 되는 표준 포인트들을 얼굴 랜드마크라고 합니다. 랜드마크를 찾는 딥러닝 모델은 다양한 종류가 있습니다. 이번에는 구글 미디어파이프의 페이스 메쉬(https://google.github.io/mediapipe/solutions/face_mesh)를 사용하기로 합니다. 미디어파이프의 페이스 메쉬는 아래와 같이 얼굴에서 468개의 3D 랜드마크를 찾아줍니다. 미디어파이프는 안드로이드, 자바스크립트 등 다양한 플랫폼에서 이용 가능하고 성능도 매우 안정적인 모델입니다.
-
기준 정의
- 468개의 랜드마크는 아래 그림과 같이 모두 3차원 좌표 벡터로 기록됩니다. 이 중에서 얼굴 각도를 결정하는 핵심적인 랜드마크를 정해야 합니다. 이번 버전에서는 입술위 인중을 의미하는 0번 랜드마크를 임의로 정했습니다.
- 468개의 랜드마크는 아래 그림과 같이 모두 3차원 좌표 벡터로 기록됩니다. 이 중에서 얼굴 각도를 결정하는 핵심적인 랜드마크를 정해야 합니다. 이번 버전에서는 입술위 인중을 의미하는 0번 랜드마크를 임의로 정했습니다.
-
-
변화량을 어떻게 계산할 것인가?
-
변화의 종류
- 처음 생각한 방식은 가로 방향의 위치와 세로 방향의 위치 좌표를 시간축에 따라 심플하게 표시하는 것을 생각했습니다. 하지만 생각보다 윤후보의 얼굴은 사방 팔방으로 움직였기 때문에 이번 버전에서는 일단 방향 구분없이 변화량 자체만을 먼저 계산하기로 합니다.
- 처음 생각한 방식은 가로 방향의 위치와 세로 방향의 위치 좌표를 시간축에 따라 심플하게 표시하는 것을 생각했습니다. 하지만 생각보다 윤후보의 얼굴은 사방 팔방으로 움직였기 때문에 이번 버전에서는 일단 방향 구분없이 변화량 자체만을 먼저 계산하기로 합니다.
-
변화량 계산
- 영상의 각 프레임마다 인중 랜드마크의 3차원 벡터가 계산되므로 변화량이란 직전 프레임의 인중 랜드마크 벡터와 다음 프레임의 인중 랜드마크 벡터간의 거리로 나타낼 수 있습니다. 이는 Scipy의 유클리디안 디스턴스 메트릭(https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.euclidean.html)으로 간단하게 계산됩니다.
- 영상의 각 프레임마다 인중 랜드마크의 3차원 벡터가 계산되므로 변화량이란 직전 프레임의 인중 랜드마크 벡터와 다음 프레임의 인중 랜드마크 벡터간의 거리로 나타낼 수 있습니다. 이는 Scipy의 유클리디안 디스턴스 메트릭(https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.euclidean.html)으로 간단하게 계산됩니다.
-
-
어떤 방법으로 카운팅 할 것인가?
-
표준화
- 인중 랜드마크 벡터간의 거리를 계산했다면 그 변화가 일어나기까지 얼마나 시간이 걸렸는지를 가지고 표준화 해야 합니다. 동일한 유클리디안 디스턴스라도 영상의 fps가 두배 높다면 단위 시간이 절반으로 줄어들어 단위 시간당 이동 거리는 두배가 되기 때문입니다. 이상적인 것은 fps를 나누어 계산하는 것이겠지만 이번 버전에서는 간단하게 만들기 위해 영상은 모두 30 fps라고 가정을 했습니다.
- 인중 랜드마크 벡터간의 거리를 계산했다면 그 변화가 일어나기까지 얼마나 시간이 걸렸는지를 가지고 표준화 해야 합니다. 동일한 유클리디안 디스턴스라도 영상의 fps가 두배 높다면 단위 시간이 절반으로 줄어들어 단위 시간당 이동 거리는 두배가 되기 때문입니다. 이상적인 것은 fps를 나누어 계산하는 것이겠지만 이번 버전에서는 간단하게 만들기 위해 영상은 모두 30 fps라고 가정을 했습니다.
-
피크 디텍션
- 유클리디안 디스턴스가 증가하다가 줄어든다는 것은 움직이다가 멈췄다는 뜻입니다. 증가후 감소하는 지점을 찾기 위해 Scipy의 피크 디텍션 알고리즘 (https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.find_peaks.html)을 사용하였습니다. 피크 디텍션 알고리즘 설정에서 중요한 부분은 distance 파라메타 입니다. 이번에는 distance 파라메타를 12로 결정했는데요, 이는 한번 피크 디텍션을 하면 이후 12 프레임(33.3 * 12 ms) 이후에 다시 나타난 피크만을 피크로 인정한다는 것입니다. 이는 몇개의 30 fps 영상을 실험하며 임의 결정한 파라미터이며, fps와 영상의 상황에 따라서 달리 설정해줘야 할 수 있습니다.
- 유클리디안 디스턴스가 증가하다가 줄어든다는 것은 움직이다가 멈췄다는 뜻입니다. 증가후 감소하는 지점을 찾기 위해 Scipy의 피크 디텍션 알고리즘 (https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.find_peaks.html)을 사용하였습니다. 피크 디텍션 알고리즘 설정에서 중요한 부분은 distance 파라메타 입니다. 이번에는 distance 파라메타를 12로 결정했는데요, 이는 한번 피크 디텍션을 하면 이후 12 프레임(33.3 * 12 ms) 이후에 다시 나타난 피크만을 피크로 인정한다는 것입니다. 이는 몇개의 30 fps 영상을 실험하며 임의 결정한 파라미터이며, fps와 영상의 상황에 따라서 달리 설정해줘야 할 수 있습니다.
-
최소값 설정
- 피크들 중에서도 최소 어떤 경계값 이상의 변화량을 가진 피크만으로 인정하였습니다. 이는 말을 하거나 살짝 흔들리는 변화까지 피크로 디텍션 되는 것을 방지해 줍니다. 가지고 있는 영상들로 테스트해보았을 때는 경계값이 0.004 정도일 때 적절하게 카운팅 되어서 이를 설정하였습니다. 이는 피크 디텍션의 distance 파라메타와 마찬가지로 fps와 영상의 상황에 따라서 달리 설정해줘야 할 수 있습니다.
-
사용 방법
-
설치
- 해당 repo를 clone하시고 tutorial.ipynb 파일에 적힌 대로 이용하시면 됩니다.
- 해당 repo를 clone하시고 tutorial.ipynb 파일에 적힌 대로 이용하시면 됩니다.
-
사용
아래 코드로 간단하게 30 fps 영상에서 도리도리 횟수를 구할 수 있습니다.
from doridori import Doridori
dori = Doridori(filepath)
dori.detect_face()
dori.fit()
아래 코드로 실시간으로 도리도리 변화량 그래프를 보여주는 영상을 filepath 경로에 저장할 수 있습니다.
dori.save_video(filepath)
토의
- 아직은 많은 한계점이 있습니다.
- 모든 fps 영상에 적용될 수 있도록 아직 표준화하지 않았습니다.
- 변화량도 충분히 연구되지는 않았습니다. 영상에서의 얼굴의 크기와 위치에 따라 값이 달라질 수 있으므로 각도와 같이 크기와 위치에 영향을 받지 않는 기준이 더 바람직할 수 있습니다.
- 하지만 쓸만 합니다.
- 일부 파라메터만 살짝 수정해가면서 사용하면 인간의 반복적인 행동을 관찰하기에 좋은 도구가 될 것 같습니다.
- 일부 파라메터만 살짝 수정해가면서 사용하면 인간의 반복적인 행동을 관찰하기에 좋은 도구가 될 것 같습니다.
- 응용 분야가 꽤 있을 듯 합니다.
- 학생들의 틱 장애와 같이 반복적인 행동 장애를 가진 사람의 상태를 정량화하고 치료의 효과를 계산하는데 사용될 수 있을 것 같습니다.
- 심리 상담에서 사용될 수 있을 것 같습니다. 사람의 불안 심리, 거짓말 등을 정량적으로 파악하여 심리 상담가들이 내담자의 심리 상태를 파악하는 보조 지표로 사용될 수 있을 것 같습니다.
- 투자 분야에서 사용될 수 있을 것 같습니다. 중요한 인물의 연설에서 긴장을 한 주제를 찾아서 투자 포인트를 찾는데 사용할 수 있을 것 같습니다. 그러고보니 빌리언즈에서 대형 투자회사가 사회의 중요 인물의 연설문을 분석하여 투자 포인트를 찾는 장면이 있었네요.
- 데이팅 분야에서 사용할 수 있겠습니다. 저희 팀은 화상 통화를 분석하여 상대와의 궁합을 계산해주고 가장 궁합이 잘 맞는 상대를 소개시켜주는 앱도 만들고 있는데, 상대에 대한 나의 태도와 습관을 관찰하고 매력적인 태도를 보이도록 조언하는데 도움이 될 수 있을 것 같습니다.
계획
- 여러 영상들에 대해 관찰하면서 대선 후보의 행동을 관찰하는 리포트를 써볼까 합니다.
- 저희 팀은 영상에서 심장 박동을 추적해내는데 좀 더 전문성이 있습니다. 표정은 숨길 수 있으나 심장 박동은 숨길 수 없거든요. 그래서 심장 박동수와 연동하여 행동 패턴까지 사용하여 후보들의 깊은 심리를 더 잘 파악해볼까 합니다.
이상 긴 글을 읽어주셔서 감사합니다. 너드 감성의 프로젝트는 항상 즐겁습니다. 클량의 잉여력에 뭔가 일조했다는 기부니가 들어서 좋은 아침이네요. 좋은 하루 되세요!
/Vollago
소오름...ㅋㅋ
DPS, DPM, DPH => 도리초, 도리분, 도리시
예제문장) 오늘 기자회견때 DPM 이 얼마였지?
갔다가 오는걸 1도리로 봐야할까요?
저 같은 사람만 있으면 아직도 돌도끼 쓰고 있죠..
ㅎ
고급 인재의 분석도 받아보는군요...ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
/Vollago
아주 좋습니다.
재능낭비 감사합니다.~~!!
윤가한텐 너무 과분한 기술 아닌가요?? 개발자님!! ㅎㅎㅎㅎ
클리앙 다운 글 감사합니다. ^^
뭐? 가 되는거죠?
ㄷㄷㄷ 합니다.
어떻게 하는지 궁금해서 간략하게 검색해보니 혈류량 때문에 피부색이 변하는걸 검출하는 부분은 신기하지만 그렇겠네 하는 생각이 들었는데... 심장이 뛸때마다 얼굴이 (상하로?) 움직이는 걸 검출한다는 부분은 정말 놀랐네요.
심장은 그냥 계속 뛰고 있으니 우리가 못 느끼지만 실제로는 얼굴이 움질일 정도로 큰 일을 하고 있는거구나 하면서요.
https://www.koreascience.or.kr/article/JAKO201913661038174.pdf
암튼 ai가 알아서 해주실거라 믿습니다.. ㄷ ㄷ ㄷ
dori = Doridori(filepath)
dori.detect_face()
dori.fit()
전 여기서 터졌어요 ㅎㅎㅎㅎㅎㅎㅎㅎㅎ
혹시 도리카운터로 카운팅한 도리 회수도 1321회였나요?
..영상에서 심박을 어떻게 카운팅하나요?!?!??!?!?!?!?!?!?!!?
최곱니다! : )
이왕 시작한김에 메트로놈과의 비교도 해보는게 어떨까 싶네요 ㅋㅋㅋ
증가 감소 증가 감소 의 거리값(시간에따른) 변화로 도리도리를 발견하는거네요
재미있는 연구 같습니다. ^^
어차피 3차원 좌표로 입력된다면 안면의 방향도 추적이 되는 것 같은데 위에서 본 회전각도 변화를 측정하면 어떨까 싶네요..^^
일일이 세기 귀찮으니 숫자도 표시해주시기 바랍니다.
저도 올해부터 파이썬배우고 있습니다. 언젠가 저도 잉여력을 발휘할 날이 오기를 기원하며
엄지척 날립니다
이따가 돌려보겠습니다.
뻥카가 없다....yo
포공에서 파티클 쓰던 시절로 다시 회귀하는 느낌입니다.
오히려 감정쪽은 temporal domain으로 고려해보세요.
씬정보에서 감정 추정해도 계속 변하기 때문에, 컨텍스트 리딩 형태로 시간축에서 문제 해결해보려하는게 나을 것 같습니다.
그나저나 감정쪽은 사업화하려면 성공하기 너무 어려우니 돈되는 쪽으로 다시 한번 고려해보세요.. ㅜㅜ
덕분에 버스 장류장 두 개 지나쳤습니다 ㅠㅠ
“필요는 발명의 어머니다”
/Vollago