Stable Diffusion로 txt2img 파인튜닝해보기(1)

목록으로 돌아가기

본 글은 keras 공식 홈페이지의 스테이블 디퓨전 파인튜닝 예시 코드를 기반으로 작성됐습니다.
함께 학습한 안효주님의 블로그 바로가기


데이터 구조

실제 사람 사진 1장과 유사한 얼굴을 띈 메이플스토리 캐릭터 사진 1장 한 묶음으로 준비가 돼 있습니다.

파일명은 다음과 같습니다.

data/man_1.jpg # 메이플 캐릭터 사진
data/man_real_1.png # 실제 사람 사진



전처리

아래 코드로 실제 사람의 이미지 데이터의 주소를 result_data에 담았습니다.

import cv2
import mediapipe as mp
import numpy as np
import os
import pandas as pd

# CSV 파일에 저장할 결과 데이터프레임을 초기화합니다.
result_data = []


# data 폴더에서 real을 포함한 이미지 파일 경로를 가져오는 함수
def get_image_paths(directory):
    image_paths = []
    for root, dirs, files in os.walk(directory):
        for file in files:
            if (
                file.lower().endswith((".jpg", ".jpeg", ".png", ".bmp", ".gif"))
                and "real" in file.lower()
            ):
                image_paths.append(os.path.join(root, file))
    return image_paths


image_paths = get_image_paths("./data")


그 후 각 이미지를 순회하며 mediapipe를 사용하여 사람의 얼굴 특성을 하드코딩으로 추출했습니다.
관련 글은 daily study에 mediapipe글을 참고해 주세요

for image_path in image_paths:
    image = cv2.imread(image_path)

    # Mediapipe 초기화
    mp_face_mesh = mp.solutions.face_mesh
    face_mesh = mp_face_mesh.FaceMesh()

    # .... 특성추출 및 이미지 경로 저장

    new_data = {
        "image_path": new_image_path,
        "Eye Ratio": eye_ratio,
        "Face Ratio": face_ratio,
        "Eyebrow Ratio": eyebrow_ratio,
        "Lip Width": lip_width,
        "Nose Width": nose_width,
    }

    result_data.append(new_data)



저장

저장을 위해 데이터 프레임으로 변환 후 각 수치의 33, 67퍼센트에 해당하는 값을 기점으로 각 얼굴의 특성을 분류하였습니다.

# 데이터프레임으로 변환
result_df = pd.DataFrame(result_data)

# Sort the DataFrame by 'Eye Ratio' column
result_df = result_df.sort_values(by="Eye Ratio")

# # 처리할 수치 열의 목록과 해당 별칭 정의
column_aliases = {
    "Eye Ratio": "눈",
    "Face Ratio": "얼굴",
    "Eyebrow Ratio": "눈썹",
    "Lip Width": "입",
    "Nose Width": "코",
}
# 각 수치 열에 대한 사분위수 기반으로 라벨 생성
for col, alias in column_aliases.items():
    bottom_quantile = result_df[col].quantile(0.33)
    top_quantile = result_df[col].quantile(0.67)

    # 경계선 값 출력
    print(f"Bottom Quantile ({col}): {bottom_quantile}")
    print(f"Top Quantile ({col}): {top_quantile}")

    result_df[alias + "_label"] = "중" + alias  # 기본값으로 중간 라벨 설정
    result_df.loc[result_df[col] <= bottom_quantile, alias + "_label"] = "소" + alias
    result_df.loc[result_df[col] > top_quantile, alias + "_label"] = "대" + alias

# 'caption' 열 생성: 라벨 열을 이용하여 생성
label_columns = [alias + "_label" for alias in column_aliases.values()]
result_df["caption"] = "메이플캐릭터," + result_df[label_columns].apply(
    lambda row: ",".join(row), axis=1
)

selected_columns = ["image_path", "caption"]
new_df = result_df[selected_columns]


# 수정 함수 정의
def modify_caption(row):
    if "woman" in row["image_path"]:
        return row["caption"] + ",woman"
    else:
        return row["caption"] + ",man"


# apply 함수를 사용하여 caption 열 수정
new_df["caption"] = new_df.apply(modify_caption, axis=1)


# 새로운 DataFrame을 CSV 파일로 저장
new_df.to_csv("dataset.csv", index=False)



출력된 dataset.csv 파일

최종적인 dataset.csv는 총 두개의 컬럼으로 캐릭터 이미지 경로인 image_path, 얼굴의 특성이 담긴 txt인 caption열로 구성이 됩니다.

image_path,caption
./data/man_15.jpg,"메이플캐릭터,소눈,대얼굴,소눈썹,대입,대코,man"
./data/woman_25.jpg,"메이플캐릭터,소눈,소얼굴,소눈썹,중입,소코,woman"
./data/man_23.jpg,"메이플캐릭터,소눈,대얼굴,소눈썹,대입,대코,man"



Etc

author-profile
Written by 유찬영

댓글