Python과 OpenCV, FER을 사용한 실시간 감정 인식 방법

Python과 OpenCV, FER을 사용한 실시간 감정 인식 방법
TILPosted On Jul 13, 202417 min read

이미지

감정 인식 기술은 심리학, 인공지능 및 컴퓨터 과학의 흥미로운 교차점을 제시합니다. 우리는 영상 처리를 위해 OpenCV의 기능을 이용하고, 얼굴 감정 인식(FER) 라이브러리를 활용하여 비디오 피드에서 실시간 감정 검출을 제공합니다.

이 방법은 얼굴 표정을 캡처하고, 딥러닝 모델을 사용하여 감정 상태를 해석하며, 이러한 감정을 동적으로 시각화하는 것을 포함합니다. 실용적인 응용 프로그램은 소프트웨어에서 사용자 경험을 향상시키는 것부터 감정 인식 AI 시스템에 대한 통찰력을 제공하는 것까지 다양합니다.

이 기사는 실용적인, 처음부터 끝까지의 코드 구현을 제공합니다. 웹캠이나 화면 녹화, 비디오 파일 등을 통해 실시간으로 감정을 캡처하고 분석할 수 있는 플러그 앤 플레이 솔루션을 개발자 및 열성가 모두에게 제공합니다.

1. 기술 스택

1.1 FER (Facial Emotion Recognition)

FER은 얼굴 표정에서 감정을 감지하는 데 중점을 둔 Python 라이브러리입니다. 사전 학습된 딥 러닝 모델을 활용하여 FER은 이미지와 비디오를 분석하여 분노, 혐오, 두려움, 행복, 슬픔, 놀라움, 중립 등 다양한 감정을 식별합니다.

이는 사용 편의를 고려하여 설계되었으며, 감정 감지가 필요한 프로젝트에 간편하게 통합할 수 있습니다. 출처: PyPI — FER.

1.2 OpenCV (오픈 소스 컴퓨터 비전 라이브러리):

OpenCV는 컴퓨터 비전 분야에서 핵심적인 라이브러리입니다. 인텔에서 처음 개발되었으며, 이미지 및 비디오 처리에 널리 사용됩니다. OpenCV는 Python을 포함한 다양한 프로그래밍 언어를 지원하며, 실시간 응용 프로그램에서 높은 효율성으로 알려져 있습니다.

이 라이브러리는 이미지 및 비디오 조작에서 중요한 역할을 하며, 웹캠 피드 캡처, 비디오 처리, 이미지 위에 주석 그리기와 같은 작업에 이상적입니다. 출처: OpenCV 문서.

1.4 MediaPipe (여기에서 사용되지 않음)

저희가 실시간 감정 인식 기술 스택에 대해 논의한 맥락에서, 이 구체적인 구현에는 사용되지는 않지만, MediaPipe를 언급할 가치가 있습니다. 독자들이 정보를 얻는 데 도움이 될 것이라고 생각합니다.

MediaPipe는 Google이 개발한 프레임워크로서 멀티모달(오디오, 비디오, 시계열 등) 적용 기계 학습 파이프라인을 구축하는 데 사용됩니다. 실시간 및 스트리밍 미디어에 대한 사용자 정의 가능한 기계 학습 솔루션을 제공하며, 특히 얼굴 인식, 손 추적, 자세 추정 기능으로 잘 알려져 있습니다.

MediaPipe는 실시간 이미지 및 비디오 처리에 대해 자세히 탐구하는 독자들이 가치 있는 도구로 여길 수 있습니다.

특히 얼굴 감정 인식 이상의 더 복잡하거나 다양한 유형의 시각 데이터 처리 및 인식 작업이 요구되는 시나리오에서 특히 강력한 도구입니다. 출처: MediaPipe Github.

2. 파이썬 구현

구현은 간단하며 주로 네 가지 라이브러리가 필요합니다: FER, OpenCV, matplotlib 및 imageio.

감정 인식 코드를 실행하기 위해 환경을 설정하려면 필요한 라이브러리를 설치해야 합니다. 명령 프롬프트 또는 터미널을 통해 다음 명령을 실행하세요:

pip install fer
pip install opencv-python
pip install matplotlib
pip install imageio

2.1 실시간 감정 감지

파이썬을 사용하여 실시간 감정 감지의 기본 개념을 소개합니다. 지금은 간단하고 액세스하기 쉽도록 유지하기 위해 핵심 기능을 보여주는 기본 스크립트부터 시작합니다.

이 초기 예제는 웹캠에서 비디오를 캡처하고 FER 라이브러리를 사용하여 실시간으로 감정을 감지하는 데 초점을 맞출 것입니다.

우리의 예제에서는 라이브 웹캠 피드를 사용하지만, 이 스크립트를 다른 소스와 함께 사용할 수 있습니다. 예를 들어, 웹캠 피드를 비디오 파일이나 라이브 화면 녹화로 대체할 수도 있습니다.

  • 웹캠 피드 시작: 먼저 웹캠에서 비디오를 캡쳐하기 위해 OpenCV를 사용합니다. OpenCV의 VideoCapture 함수는 웹캠 피드를 초기화합니다. 대부분의 경우, VideoCapture에 0을 전달하면 기본 웹캠이 선택됩니다.
  • 감정 감지: 그 다음으로는 비디오 프레임에서 감정을 감지하는 간단한 인터페이스를 제공하는 FER 라이브러리를 활용합니다. 웹캠에서 프레임이 캡쳐되면 FER는 프레임을 처리하여 얼굴과 해당 감정을 감지합니다.
  • 감지된 감정 강조: 감정이 감지되면 OpenCV 함수를 사용하여 비디오 프레임에서 감지된 얼굴에 경계 상자와 텍스트 주석을 그립니다. 텍스트 레이블은 감지된 감정과 해당 신뢰 수준을 표시합니다.
from fer import FER
import cv2

# 감정 감지기 초기화
detector = FER(mtcnn=True)

# 웹캠 시작
cap = cv2.VideoCapture(0)

try:
    while True:
        ret, frame = cap.read()
        if not ret:
            break

        # 프레임에서 감정 감지
        result = detector.detect_emotions(frame)
        for face in result:
            # 값을 추출
            box = face["box"]
            emotions = face["emotions"]

            x, y, w, h = box
            cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
            
            # 가장 높은 점수의 감정 찾기
            emotion_type = max(emotions, key=emotions.get)
            emotion_score = emotions[emotion_type]

            # 감정 유형과 신뢰 수준 표시
            emotion_text = f"{emotion_type}: {emotion_score:.2f}"
            cv2.putText(frame, emotion_text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)

        # 결과 프레임 표시
        cv2.imshow('Emotion Detection', frame)

        # 루프 종료
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
except KeyboardInterrupt:
    print("사용자에 의해 중지됨")
finally:
    # 모든 작업이 완료되면 캡처 해제
    cap.release()
    cv2.destroyAllWindows()

2.2 실시간 감정 시각화

기본적인 실시간 감정 감지 스크립트를 기반으로, 실시간 감정 시각화 기능을 추가한 것입니다.

이 업데이트는 감정 감지 응용 프로그램에 더 다이내믹하고 상호작용 가능한 측면을 추가하여 데이터를 더 매력적이고 통찰력 있게 만듭니다.

실시간 감정 막대 차트 생성: 각 프레임에서 감지된 감정을 시각화하기 위해, 우리는 파이썬의 강력한 플로팅 라이브러리인 matplotlib을 사용합니다. 다음은 설정하는 방법입니다:

  • 우리는 matplotlib 피겨를 초기화하고 각 감정에 대한 자리 표시자를 가진 막대 차트를 만듭니다.
  • 차트의 각 막대는 감정을 나타내며, FER에 의해 감지된 신뢰 수준을 실시간으로 업데이트하여 높이가 조정됩니다.
import matplotlib.pyplot as plt

plt.ion()  # 대화형 모드를 활성화
fig, ax = plt.subplots()
emotion_labels = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral']
bars = ax.bar(emotion_labels, [0]*7, color='lightblue')

Matplotlib의 대화형 모드: 대화형 모드를 활성화하면 (plt.ion()), matplotlib의 플롯이 실시간으로 업데이트됩니다. 이를 통해 바 차트가 감정 감지 알고리즘에 의해 처리된 각 새 프레임마다 동적으로 새로 고쳐질 수 있습니다.

차트 업데이트: 감지된 감정을 가져와 각 막대의 높이를 업데이트하는 update_chart 함수를 만듭니다. 이 함수는 처리된 각 프레임에서 호출되어 차트가 현재 감지된 감정을 정확히 반영하도록 합니다.

def update_chart(detected_emotions, bars, ax, fig):
    ax.clear()
    ax.bar(emotion_labels, [detected_emotions.get(emotion, 0) for emotion in emotion_labels], color='lightblue')
    ### [차트 서식의 나머지 부분]
    fig.canvas.flush_events()

주요 루프에서 차트 업데이트 통합: 스크립트의 주요 루프에서 각 프레임에서 감정을 감지한 후, 최신 감정 데이터로 update_chart를 호출합니다. 이렇게 함으로써 시각화가 비디오 피드와 동기화되도록 유지됩니다.

# 감정 감지 및 시각화를 위한 주요 루프
while True:
    # [웹캠 캡처 및 감정 감지 코드]

    if largest_face:
        # [얼굴 처리 및 감정 점수 매기기]
        
        # 최신 감정 데이터로 실시간 막대 차트 업데이트
        update_chart(current_emotions, bars, ax, fig)

모두 합쳐서 다음과 같은 포괄적인 Python 스크립트를 얻습니다.

from fer import FER
import cv2
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import imageio
import matplotlib
import time

"""
실시간 감정 감지 및 시각화

이 스크립트는 웹캠에서 비디오를 캡처하고 실시간으로 얼굴의 감정을 감지하여 결과를 실시간으로 시각화하는 기능을 제공합니다. 
또한 감지된 감정과 함께 비디오 자체에도 표시된 상자와 감정 레이블을 저장합니다. 또한 실시간 감정 막대 차트를 GIF로, 
누적 감정 통계도 정적 차트로 저장합니다. 이 스크립트는 비디오 처리를 위해 OpenCV, 감정 감지를 위해 FER, 라이브 차트 시각화를 
위해 matplotlib, GIF 제작을 위해 imageio를 사용합니다.

주요 기능:
- 웹캠에서 실시간 감정 감지.
- 막대 차트에서 감정 확신 수준을 실시간으로 업데이트.
- 얼굴 주위의 경계 상자 및 감정 레이블이 있는 비디오 캡처 저장.
- 라이브 감정 막대 차트의 GIF 생성.
- 시간에 따른 감정 통계의 누적 차트 저장.
"""

# matplotlib의 백엔드를 다양한 환경과 호환되도록 'TkAgg'로 설정
matplotlib.use('TkAgg')

# MTCNN을 사용하는 FER (Face Emotion Recognition) 탐지기를 초기화
detector = FER(mtcnn=True)

# 웹캠에서 비디오 캡처 시작 (장치 0)
cap = cv2.VideoCapture(0)

# 비디오 녹화용 프레임 속도 설정 (웹캠의 성능에 따라 조정)
frame_rate = 4.3

# 지정된 프레임 속도로 비디오를 저장하는 OpenCVVideoWriter 초기화
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('emotion_video.avi', fourcc, frame_rate, (640, 480))

# 라이브 감정 감지 결과를 표시할 matplotlib 피겨 설정
plt.ion()  # 라이브 업데이트를 위한 대화형 모드 활성화
fig, ax = plt.subplots()
emotion_labels = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral']
bars = ax.bar(emotion_labels, [0]*7, color='lightblue')  # 각 감정을 위한 막대 초기화
plt.ylim(0, 1)
plt.ylabel('신뢰도')
plt.title('실시간 감정 감지')
ax.set_xticklabels(emotion_labels, rotation=45)

# 라이브 차트 업데이트를 GIF로 저장하기 위해 imageio 라이터 초기화
gif_writer = imageio.get_writer('emotion_chart.gif', mode='I', duration=0.1)

# 각 프레임에 대한 누적 감정 통계를 저장할 리스트
emotion_statistics = []

# 라이브 차트 업데이트 함수
def update_chart(detected_emotions, bars, ax, fig):
    ax.clear()  # 현재 축 지우고 다시 막대 차트 설정
    ax.bar(emotion_labels, [detected_emotions.get(emotion, 0) for emotion in emotion_labels], color='lightblue')
    plt.ylim(0, 1)
    plt.ylabel('신뢰도')
    plt.title('실시간 감정 감지')
    ax.set_xticklabels(emotion_labels, rotation=45)
    fig.canvas.draw()
    fig.canvas.flush_events()

# 웹캠 작동 시간을 측정하기 위해 타이머 시작
webcam_start_time = time.time()

try:
    while True:
        ret, frame = cap.read()  # 웹캠에서 프레임 읽기
        if not ret:
            break  # 캡처된 프레임이 없으면 루프 종료

        # 프레임에서 감정 감지
        result = detector.detect_emotions(frame)
        largest_face = None
        max_area = 0

        # 주요 감정 분석을 위해 프레임에서 가장 큰 얼굴 찾기
        for face in result:
            box = face["box"]
            x, y, w, h = box
            area = w * h
            if area > max_area:
                max_area = area
                largest_face = face

        # 얼굴이 감지되면 감정 표시 및 차트 업데이트
        if largest_face:
            box = largest_face["box"]
            current_emotions = largest_face["emotions"]

            # 감정 데이터 저장
            emotion_statistics.append(current_emotions)

            x, y, w, h = box
            cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
            
            emotion_type = max(current_emotions, key=current_emotions.get)
            emotion_score = current_emotions[emotion_type]

            emotion_text = f"{emotion_type}: {emotion_score:.2f}"
            cv2.putText(frame, emotion_text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)

            update_chart(current_emotions, bars, ax, fig)

            out.write(frame)  # 프레임을 비디오 파일에 씀

            # 현재 막대 차트 상태를 GIF의 한 프레임으로 저장
            fig.canvas.draw()
            image = np.frombuffer(fig.canvas.tostring_rgb(), dtype='uint8')
            image = image.reshape(fig.canvas.get_width_height()[::-1] + (3,))
            gif_writer.append_data(image)

        cv2.imshow('감정 감지', frame)  # 프레임 표시

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        
except KeyboardInterrupt:
    print("사용자에 의해 중단됨")

finally:
    webcam_end_time = time.time()  # 웹캠 창이 닫힐 때 타이머 종료
    print(f"웹캠 활동 시간: {webcam_end_time - webcam_start_time:.2f} 초")

    cap.release()
    cv2.destroyAllWindows()
    plt.close(fig)

    out.release()
    gif_writer.close()

    emotion_df = pd.DataFrame(emotion_statistics)

    plt.figure(figsize=(10, 10))
    for emotion in emotion_labels:
        plt.plot(emotion_df[emotion].cumsum(), label=emotion)
    plt.title('시간에 따른 누적 감정 통계')
    plt.xlabel('프레임')
    plt.ylabel('누적 신뢰도')
    plt.legend()
    plt.savefig('cumulative_emotions.jpg')
    plt.close()

2.3 보너스 — 결과 병합하기

감정 감지 기술의 진정한 힘은 데이터를 포괄적이고 매력적인 방식으로 시각화할 때 발휘됩니다. 이를 달성하기 위해 다양한 출력물을 하나의 시각적 프레젠테이션으로 효과적으로 결합하는 스크립트를 개발했습니다. 이 스크립트는 세 가지 요소를 효과적으로 조화시킵니다:

  • 실시간 비디오: 웹캠 피드에서 캡처한 감정 감지 결과가 'emotion_video.avi'로 저장됩니다.
  • 동적 막대 차트 GIF: 감지된 감정을 실시간으로 업데이트하는 차트가 'emotion_chart.gif'로 저장됩니다.
  • 정적 누적 감정 차트: 'cumulative_emotions.jpg'라는 이미지 파일에 시간에 따른 집계된 감정 데이터가 표시됩니다.

스크립트에서 중요한 코드 일부:

  • 입력값 읽기 및 처리:

static_chart = Image.open('cumulative_emotions.jpg')
video = cv2.VideoCapture('emotion_video.avi')
bar_chart_gif = imageio.mimread('emotion_chart.gif')
  • Frames를 조합하는 로직:
combined_frame = Image.new('RGB', (3 * desired_width, desired_height))
combined_frame.paste(video_frame_resized, (0, 0))
combined_frame.paste(gif_resized, (desired_width, 0))
combined_frame.paste(static_chart_resized, (2 * desired_width, 0))

더 자세한 코드와 기술적인 세부 정보를 탐험하고 싶은 분들을 위해, AI, 데이터 과학 및 기술에 대한 다양한 기술 튜토리얼 및 실용적인 가이드가 포함된 리소스인 우리 웹사이트인 Entreprenerdly.com을 방문하시기를 권장합니다.

이 프로젝트와 다른 많은 프로젝트의 완전한 코드를 찾을 수 있습니다. 최신 기술 솔루션을 배우고 구현하는 실전적인 방법을 제공합니다.

이미지

5. 실용적인 응용

  • 보안 시스템: 감정 인식은 보안 시스템에 추가적인 보호층을 추가할 수 있습니다. 감정 신호에 기반하여 의심스러운 또는 이례적인 행동을 식별할 수 있습니다.
  • 의료 및 정신 건강: 임상 환경에서 감정 인식은 환자의 정신 건강 상태를 모니터링하는 데 도움을 줄 수 있습니다. 특히 텔레치료 세션에서 유용하며, 환자의 감정 반응에 대한 추가적인 통찰을 제공하여 요법사에게 도움이 될 수 있습니다.
  • 사용자 경험 및 인터페이스 디자인: 웹사이트와 애플리케이션은 감정 인식을 사용하여 사용자 경험을 맞춤화할 수 있습니다. 혼란 또는 불만의 징후를 감지하여 유용한 프롬프트를 트리거하거나 사용자가 더 관련 있는 콘텐츠로 안내할 수 있습니다.
  • 로봇과 인공지능: 로봇 공학에서 감정 인식은 AI 및 로봇과의 상호 작용을 더 자연스럽고 직관적으로 만들 수 있습니다. 특히 요양이나 고객 서비스 로봇에서 유용합니다.
  • 접근성 기술: 언어 또는 청각 장애가 있는 사람들을 위해 감정 인식 기술은 화자의 감정 상태에 대한 추가적인 문맥을 제공하여 의사 소통을 용이하게 할 수 있습니다.

6. 한계와 개선점

6.1 한계

  • 정확도와 데이터 의존성: 감정 감지의 정확도는 FER 모델의 훈련 데이터에 크게 의존합니다. 이 데이터의 편견은 잘못된 또는 일관되지 않은 감정 인식으로 이어질 수 있으며, 특히 다양한 인구 통계군 사이에서 발생할 수 있습니다.
  • 맥락적 이해: 시스템은 감정의 맥락을 이해하기 항해 합니다. 얼굴 표정을 인식하지만 이러한 표정 뒤의 이유를 추론하거나 진짜 감정과 가짜 감정을 구별할 수 없습니다.
  • 조명 및 영상 품질: 웹캠 영상의 품질, 포함하여 조명 조건과 해상도는 감지 정확도에 큰 영향을 미칠 수 있습니다. 낮은 영상 품질은 신뢰할 수 없는 감정 인식으로 이어질 수 있습니다.
  • 개인정보 우려: 감정 인식 기술을 사용함에 있어, 특히 공개적 또는 준공개적 공간에서는 개인정보 문제가 우려됩니다. 이러한 시스템을 구현할 때는 동의와 윤리적 고려가 매우 중요합니다.

6.2 개선 가능한 부분:

  • 향상된 머신러닝 모델: 더 발전된 머신러닝 모델을 통합하거나 기존의 FER 모델을 사용자 정의함으로써 정확성을 향상시키고 편향을 줄일 수 있습니다.
  • 맥락을 인지하는 알고리즘: 상황의 맥락을 고려하는 알고리즘을 개발하면 보다 세밀한 감정 분석을 제공할 수 있습니다.
  • 실시간 처리 최적화: 코드를 효율적으로 최적화하거나 더 강력한 처리 하드웨어를 사용함으로써 실시간 응용 프로그램에서의 대기 시간을 최소화할 수 있습니다.
  • 개인 정보 보호 대책: 엄격한 개인 정보 보호 규정을 시행하고 데이터 사용에 대한 투명성을 보장함으로써 개인 정보 보호 우려를 완화할 수 있습니다.

결론

이러한 강력한 도구들을 결합하여 감정을 실시간으로 감지할 뿐만 아니라 이러한 데이터를 매력적이고 유익한 방식으로 시각화할 수 있다는 것을 확인했습니다. 이 기술의 실용적인 응용은 건강 관리부터 마케팅에 이르기까지 다양하며 다양합니다.

독자들에게는 이 기사가 현재 기술의 능력을 이해하고 그 잠재적인 응용 분야를 상상해 볼 수 있는 시작점으로 제공됩니다. 개발자, 연구자 또는 기술과 감정이 교차하는 부분에 관심이 있는 사람이라면 상상력만큼의 가능성이 넓게 열려 있습니다.

Real-Time Emotion Recognition in Python with OpenCV and FER