반응형
멀티 모달(Multi Modal)은 텍스트, 이미지, 음성, 비디오 등 다양한 유형의 데이터를 함께 활용하는 기술을 뜻한다.
이번 포스트에서는 DeepFace 라이브러리로 프로필 이미지를 분석하고 특징들을 추출한 뒤에 추출된 이미지를 다시 지브리 스튜디오 스타일로 변환하는 멀티 모달 애플리케이션을 제작해 보겠다.
UI를 띄우기 위해 Gradio를 사용했다.
그전에 각각이 무엇인지 용어 설명을 하겠다
DeepFace
- 얼굴 검출 및 인식, 그리고 나이/성별/감정 등 얼굴 분석 기능을 제공하는 Python 얼굴인식 프레임워크이다.
Gradio
- Model을 웹으로 손쉽게 사용할 수 있게 해주는 라이브러리이자 플랫폼입니다
LangChain
- LLM을 사용하여 애플리케이션 생성을 단순화하도록 설계된 프레임워크
간단하게 아래와 같은 동작원리를 가지고 있다
- DeepFace 를 이용한 사진 분석 -> 'age', 'gender', 'emotion', 'race' 를
추출한다 - 추출된 특성들로 자세하게 묘사하는 Prompt 를 영어로 생성한다
- 생성된 프롬프트를 기반으로 Dalle-3 를 사용해 이미지
기본적으로 LLM은 영어로 프롬프트를 넣을 때 더 높은 성능을 보여준다고 한다.
결과물
Gradio를 이용하여 UI를 구성했다.


import os
import numpy as np
import requests
from io import BytesIO
from PIL import Image
# LangChain 관련 모듈 임포트
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# Gradio 임포트
import gradio as gr
# DeepFace 임포트
from deepface import DeepFace
import traceback
# OPENAI API KEY 설정
os.environ['OPENAI_API_KEY']="YOUR-API-KEY"
llm = ChatOpenAI(model="gpt-4o", max_tokens=1024)
def extract_facial_features(image):
try:
# PIL 이미지를 numpy 배열로 변환
img_array = np.array(image)
# DeepFace를 사용한 얼굴 분석
analysis = DeepFace.analyze(img_array,
actions=['age', 'gender', 'emotion', 'race'],
detector_backend='retinaface')
# 얼굴 랜드마크 정보 추출
demography = analysis[0]
# 주요 특징 추출
age = demography['age']
gender = demography['gender']
emotion = demography['dominant_emotion']
race = demography['race']
# 감정에 따른 얼굴 표정 특징 추정
emotion_features = {
'angry': '뾰족한 눈썹, 긴장된 눈, 약간 다문 입',
'disgust': '구겨진 코, 좁은 눈, 약간 올라간 입',
'fear': '올라간 눈썹, 커진 눈, 약간 벌어진 입',
'happy': '약간 올라간 눈썹, 눈가 주름, 미소 짓는 입',
'sad': '처진 눈썹, 슬픈 눈, 처진 입',
'surprise': '높이 올라간 눈썹, 크게 뜬 눈, O자형 입',
'neutral': '평온한 눈썹, 편안한 눈, 자연스러운 입'
}
# 인종에 따른 얼굴형 특징 추정
dominant_race = max(race.items(), key=lambda x: x[1])[0]
race_features = {
'asian': '둥근 얼굴형, 낮은 코 다리, 약간 납작한 안면구조',
'indian': '난형 얼굴형, 뚜렷한 코, 도드라진 광대',
'black': '둥근 얼굴형, 넓은 코, 도드라진 광대',
'white': '타원형 얼굴형, 좁은 코, 높은 눈썹',
'middle eastern': '타원형 얼굴형, 뚜렷한 코, 강한 턱선',
'latino hispanic': '둥근 얼굴형, 중간 크기의 코, 둥근 뺨'
}
# 특징 데이터 구성
features = {
'age': age,
'gender': gender,
'emotion': emotion,
'emotion_features': emotion_features.get(emotion, '일반적인 표정'),
'dominant_race': dominant_race,
'race_features': race_features.get(dominant_race, '일반적인 얼굴형')
#'emotion_confidence': demography['emotion'][emotion], 이렇게 하면 demography['emotion']['angry'] 확률 반환한다
#'race_confidence': demography['race'][dominant_race]
}
return features, None
except Exception as e:
error_msg = f"얼굴 분석 중 오류 발생: {str(e)}"
return None, error_msg
# LangChain을 사용해 얼굴 특징을 영어로 설명
def interpret_features(features):
# 특징 해석 프롬프트
interpret_prompt = ChatPromptTemplate.from_messages([
('system', """You are an expert facial feature analyst who provides detailed and accurate descriptions.
Describe the facial features based on the analysis data in elegant English.
Focus on eyes, nose, mouth, face shape, and other distinctive features.
Be specific, detailed, and objective. Avoid subjective judgments."""),
('user', """Please provide a detailed description of facial features based on this analysis data:
Age: {age}
Gender: {gender}
Dominant Emotion: {emotion}
Facial Expression: {emotion_features}
Dominant Race: {dominant_race}
Face Shape Features: {race_features}
Create a detailed paragraph describing the age, eyes, nose, mouth, face shape, and other notable features.
This will be used to generate a Studio Ghibli style portrait. And also as a ID photo for a passport.""")
])
# 특징 해석 체인
interpret_chain = interpret_prompt | llm | StrOutputParser()
# 체인 실행
return interpret_chain.invoke(features)
# 지브리 스타일 이미지 생성 함수
# OpenAI 모듈 임포트
import openai
client = openai.OpenAI()
def generate_ghibli_portrait(face_description):
response = client.images.generate(
model="dall-e-3",
prompt=f"""Create a Studio Ghibli style portrait based on these facial features:
{face_description}
Important guidelines:
- Use Studio Ghibli's distinctive art style (like characters from Spirited Away, Howl's Moving Castle, or My Neighbor Totoro)
- Use soft, warm colors and gentle lines characteristic of Ghibli animations
- The character should have a friendly expression with Ghibli's signature large expressive eyes
- Include shoulders and a simple background reminiscent of Ghibli films
- The portrait should look hand-drawn with clean lines and warm colors
- Maintain the unique facial features described while adapting to Ghibli style
This MUST look like it was drawn by Studio Ghibli animators while preserving the described facial characteristics.
""",
size="1024x1024",
quality="hd",
n=1,
)
image_url = response.data[0].url
return image_url
# 이미지 처리 메인 함수
def process_image(image):
if image is None:
return "이미지를 업로드해주세요.", None, None, None
# 1단계: DeepFace로 얼굴 특징 추출
features, error = extract_facial_features(image)
if error:
return error, None, None, None
# 2단계: LangChain으로 얼굴 특징 해석
face_description = interpret_features(features)
# 중간 결과 반환 (UI 업데이트용)
yield "분석 중...", face_description, None, None
# 3단계: 지브리 스타일 이미지 생성
try:
ghibli_image_url = generate_ghibli_portrait(face_description)
response = requests.get(ghibli_image_url)
ghibli_image = Image.open(BytesIO(response.content))
# 최종 결과 반환
yield "분석 완료!", face_description, ghibli_image, ghibli_image_url
except Exception as e:
yield f"이미지 생성 중 오류 발생: {str(e)}", face_description, None, None
with gr.Blocks() as demo:
gr.Markdown("# 🎨 증명사진 → 지브리 스타일 변환기")
gr.Markdown("DeepFace로 얼굴을 분석하고 지브리 스타일의 캐릭터로 변환합니다.")
with gr.Row():
with gr.Column(scale=1):
image_input = gr.Image(type="pil", label="증명사진 업로드")
submit_button = gr.Button("지브리 스타일로 변환하기", variant="primary")
status_output = gr.Textbox(label="상태", value="대기 중...")
with gr.Column(scale=2):
features_output = gr.Textbox(label="얼굴 특징 분석 결과 (영어)", lines=10)
with gr.Row():
with gr.Column():
ghibli_output = gr.Image(label="지브리 스타일 결과")
with gr.Column():
image_url_output = gr.Textbox(label="이미지 URL (저장용)")
# 이벤트 연결
submit_button.click(
process_image,
inputs=image_input,
outputs=[status_output, features_output, ghibli_output, image_url_output]
)
# 예시 설명
gr.Markdown("""
## 📝 사용 방법
1. 증명사진을 업로드하세요
2. '지브리 스타일로 변환하기' 버튼을 클릭하세요
3. DeepFace가 얼굴을 분석하고 특징을 추출합니다
4. LangChain이 이를 영어로 상세히 해석합니다
5. DALL-E가 지브리 스타일의 캐릭터를 생성합니다
## ⚠️ 주의사항
- 얼굴이 명확히 보이는 정면 사진을 사용하세요
- 첫 실행 시 DeepFace 모델 다운로드로 시간이 걸릴 수 있습니다
- 변환 과정은 총 15-30초 정도 소요됩니다
""")
demo.launch()
결론 : Dalle-3의 한계점을 느낄 수 있었다.
왜 지브리 스타일로 해달라니깐 못 알아먹는거지...?
반응형