AI Avatar – 6. Play the Voiceover with the Avatar Animation

이번시간에는 TTS로 생성된 음성파일을 아바타 애니메이션과 통합하는 방법에 대해서 알려드리겠습니다.

지난 시간에 음성파일 재생을 지원하기 위해 Mac에 mpg123 라이브러리를 설치했는데요 안하신 분이 계시면 꼭 설치를 해주시기 바랍니다.

brew install mpg123

그리고 일전에 배웠던 아바타 애니메이션 코드에 아래 함수를 추가해주세요.

def play_voiceover(file_path):
    os.system(f"mpg123 {file_path} &")

def animate_avatar_with_voice(images, voiceover_path):
    play_voiceover(voiceover_path)
    animate_avatar(images)

윈도우 사용자들은 위의 play_voiceover()함수에서 음성파일 실행하는 명령어를 start로 바꿔주세요.

os.system(f'start {file_path}')

그리고 코드 맨 끝에서 animate_avatar_with_voice()함수를 호출해줍니다.

animate_avatar_with_voice(opencv_images, 'avatar_voiceover.mp3')

완성된 코드는 다음과 같습니다.

import os
import cv2
import dlib
import numpy as np
from PIL import Image

def get_files_with_extensions(directory, extensions):
    # get multiple files
    files = os.listdir(directory)
    if len(extensions) > 0:
        return [f for f in files if os.path.splitext(f)[1].lower() in extensions]
    else:
        return files

# dlib 얼굴 검출기 로드
detector = dlib.get_frontal_face_detector()

# 이미지에서 얼굴을 추출하는 함수
def extract_face(image_path):
    image = cv2.imread(image_path)
    faces = detector(image)
    if  len(faces) > 0:
        face = faces[0]   # 발견된 첫 번째 얼굴 추출
        x, y, w, h = face.left(), face.top(), face.width(), face.height()
        face_image = image[y:y+h, x:x+w]
        return cv2.cvtColor(face_image, cv2.COLOR_BGR2RGB)
    else :
        return  None

# 여러 얼굴을 추출하여 반환
def extract_faces_from_arr(image_paths):
    faces = []
    for path in image_paths:
        face = extract_face(path)
        if face is not None :
            faces.append(face)
    return faces

# 얼굴과 비디오 프레임을 합성 아바타로 통합하는 함수
def extract_faces_from_folder(frame_dir):
    # 프레임에서 얼굴 추출하여 배열에 저장
    frame_faces = []
    for frame_file in get_files_with_extensions(frame_dir, ['.jpg', '.png']):
        frame_path = os.path.join(frame_dir, frame_file)
        frame_image = extract_face(frame_path)   # extract_face 함수 재사용
        if frame_image is not None :
            frame_faces.append(frame_image)
    return frame_faces
    
def merge_faces(image_faces, frame_faces):
    return image_faces + frame_faces

def animate_avatar(images):
    cv2.namedWindow('Avatar Animation', cv2.WINDOW_NORMAL)
    for i in range(30):  # Number of animation cycles
        for image in images:
            cv2.imshow('Avatar Animation', image)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
    cv2.destroyAllWindows()

def play_voiceover(file_path):
    os.system(f"mpg123 {file_path} &")

def animate_avatar_with_voice(images, voiceover_path):
    play_voiceover(voiceover_path)
    animate_avatar(images)

# 얼굴을 추출할 이미지 경로
image_paths = ['image1.png', 'image2.png', 'image3.png']
image_faces = extract_faces_from_arr(image_paths)

# 동영상 추출 프레임 이미지 폴더 경로
folder_path = 'frames'
frame_faces = extract_faces_from_folder(folder_path)

all_faces = merge_faces(image_faces, frame_faces)

# Convert the PIL images to OpenCV format for animation
opencv_images = [cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) for img in all_faces]

# Animate the avatar
animate_avatar_with_voice(opencv_images, 'avatar_voiceover.mp3')

실행을 해보기 전에 애니메이션 할때 사용했던 이미지파일들과 만들어 두었던 TTS음성파일을 같은 폴더에 저장합니다. 음성파일 복사해오는 대신 TTS음성파일 만드는 코드를 여기에 갖다 붙여서 사용해도 좋구요.

python voiceover.py

실행해보시면 얼굴들이 미친듯이 돌아가면서 음성파일이 실행됩니다. 전혀 AI 아바타같지는 않은데…이걸로 뭘하라는 건지 잘 모르겠네요..글쓴이는 뭔가 그럴싸한 아이디어를 주었다고 생각하는거 같은데 사실 이건 그 사람이 실제 개발하고 있는 코드는 밥그릇째 내줄수 없다 뭐 그런 느낌이에요. 여기에서 뭔가 스스로 발전시키라는 의도인것 같은데 암튼 좀더 리서치를 해보고 좋은 글을 찾아서 다시 공유하도록 하겠습니다.

References