7つの画風で描いた同じキャラクター。左から kensaur.us(ドット絵)、glot(16ビットのドット絵)、the wanting mind(木版画)、yen-yen(墨と判子)、help her take photo(ステッカー)、lets-talk(切り絵)、Mushi Mushi(博物誌の挿絵)
kensaurus는 제가 혼자 운영하는 앱 공방입니다. 지난 11월 13일, 제가 만들고 있는 여러 앱과 사이트 중 7곳에 동일한 마스코트를 배치하기로 했습니다. 모델은 저 자신이고 이름은 켄지(Kenji)입니다. 다만 그림체는 통일하지 않았습니다. 타이어 학습 게임에서는 도트풍 선인으로, 철학 책에서는 목판화의 달을 읽는 사람으로, 가계부 앱에서는 도장을 찍는 장부 담당자처럼, 각 앱의 미술적 분위기에 맞춰 다르게 그렸습니다.
이 글은 그 제작 파이프라인 기록입니다. 이미지 생성에는 fal의 google/nano-banana-2.1/edit를 사용했고, 배경 잘라내기(배경 제거)에는 fal-ai/birefnet/v2를 사용했습니다. 총 63회의 생성을 거쳤고, 비용은 fal이 공표한 가격으로 계산하여 $4.68이었습니다. 이 금액은 새로 그린 6가지 화풍에 대한 것이며, glot의 선인은 포함되어 있지 않습니다.
현재 공개된 것들
솔직히 말하자면, 7곳 중 실제 앱에 들어간 곳은 4곳입니다.
| 앱 | 화풍 | 상태 (11월 13일) |
|---|
| lets-talk | 오려 붙이기(切り絵) | 1.3.0으로 공개 완료. 웹 버전(talk.kensaur.us)과 Google Play에 배포됨. iOS는 심사 중 |
| ... | | |
같은 인물로 보이게 하기 위한 약속
화풍을 7가지로 나누다 보니 가장 깨지기 쉬운 부분이 '같은 사람으로 보이는가'입니다. 그래서 어떤 화풍에서도 변하지 않는 특징 3가지만 정했습니다.
- 머리 꼭대기에 모은 쪽진(똥머리)
- 검은 테의 사각형 안경
- 차분한 반쪽 미소
수염은 고정하지 않았습니다. 선인이나 장부 담당자처럼 연장자의 역할일 때는 하얗고 긴 수염을 그리고, 사진 앱과 회화 연습 앱에서는 30세 전후의 수염 없는 모습을 그렸습니다. 이는 '젊고 친근하게'라는 판단 때문이었습니다.
또 다른 약속은 인물 설명 문구를 한 글자도 바꾸지 않고 매번 프롬프트 맨 앞에 넣는 것입니다. 수염이 없는 버전은 다음과 같습니다.
"_identity_young": "CHARACTER (keep identical to the reference style sheet): Kenji, a friendly young man about 28 to 30 years old, CLEAN-SHAVEN (no beard, no moustache, no facial hair at all). Messy black hair gathered into a top-knot bun, rectangular dark-rimmed glasses, warm light-brown skin, a warm half-smile. Slim body, head a little large for the body. Same face, outfit, palette and drawing style as the reference sheet."
문장을 매번 조금씩 수정하면 생성될 때마다 얼굴도 조금씩 달라집니다. 그래서 이 단락은 파일에 한 곳만 두고 어떤 포즈를 생성할 때든 그대로 삽입합니다.
파이프라인
앱 1개당 다음의 4단계를 거칩니다.
스타일 시트(Style Sheet) 제작. 3:2 비율의 이미지 1장에 정면, 사선, 표정 4종을 배치합니다. 참고 이미지는 glot의 선인 시트, 사이트의 도트풍 켄지, 그리고 해당 앱에 원래 있던 미술 자료(책 삽화, 아이콘, 기존 캐릭터 등)입니다. 이 1장을 확인하고 승인한 후에 다음 단계로 넘어갑니다. -
포즈는 1장당 1회 생성. 1:1 비율, 2K 해상도입니다. 참고 자료는 1단계에서 승인된 시트와, 앱에 따라 아이콘이나 동행 캐릭터가 됩니다. -
배경 잘라내기(Background Clipping). birefnet을 이용해 투명하게 만들고, 작은 쓰레기를 지우며, 발의 위치를 맞춥니다. -
파일 출력. 1024px 원본과, 200/400/600px PNG, 600px WebP 파일을 만듭니다.
포즈 1장의 프롬프트
포즈별 차이는 단 한 줄입니다. 인물 단락과 화풍 단락은 앱마다 고정되어 있습니다.
prompt = NL.join([ident, '', cfg['style'], '', f"POSE: {p['desc']}.", ...])
배경은 '무지하고 질감이나 테두리 없음'이라고 매번 명확하게 적습니다. 목판화라면 #F5F0E1의 한지 색깔과 같은 식입니다. 배경이 단순할수록 다음 잘라내기가 깨끗하게 나옵니다.
생성은 ThreadPoolExecutor(4)를 사용했습니다.
4개씩 병렬로 전송하고, 파일이 이미 존재하는 포즈는 건너뜁니다. 중간에 중단되어도 다시 실행하면 이어서 재개할 수 있습니다. 1회 생성은 중앙값으로 약 30초가 소요되었습니다.
자르기 및 발 위치 맞추기 처리
birefnet의 출력물에는 도장 인주가 튀거나 종이 가루 같은 작은 파편이 남아 있을 수 있습니다. 가장 큰 부분의 3% 미만인 파편만 제거합니다. yen-yen의 회계 담당자가 가지고 있는 동전 캐릭터처럼, 큰 무리는 남겨둡니다.
def drop_specks(im):
arr = np.array(im)
mask = arr[:, :, 3] > 24
...
그 후 인물 크기로 잘라내어 정사각형으로 재배치합니다. 이때 발이 모든 포즈에서 같은 높이에 오도록 하단 여백을 고정합니다. 이렇게 하면 앱 화면에서 포즈를 바꿔도 인물이 상하로 튀지 않습니다.
out.paste(im, ((side - w) // 2, side - h - int(side * pad)), im) # feet on a common baseline
소요 비용
생성할 때마다 1줄씩 spend.jsonl에 기록하고 있습니다.
| 내용 | 횟수 | 비용 |
|---|
| 스타일 시트 (4개 앱, 수염 제거 수정 2장, Mushi 2안) | 8 | $0.59 |
| ... | 합계 | $4.68 |
금액은 1회당 $0.0743(2K의 편집. fal의 공표 가격)으로 계산된 것이며, 청구액 실측과는 다릅니다. birefnet의 자르기 작업 48회는 API 페이지에 가격이 명시되어 있지 않아 포함하지 않았습니다.
수염을 지울 때는 처음부터 다시 그리지 않고 “승인된 시트를 편집하는” 방식으로 했습니다. 레이아웃, 옷, 선 굵기는 그대로 두고 나이와 얼굴만 변경하도록 지시합니다. 이렇게 하면 승인된 그림체를 망가뜨릴 염려 없이 앱당 1회 생성으로 끝낼 수 있습니다.
캐릭터를 앱의 목소리로 만들기
그림을 그리는 것이 이 작업의 절반입니다. 나머지 절반은 각 앱에서 켄지에게 무엇을 말하게 할 것인지입니다. 역할명과 말투는 앱마다 다음과 같이 정했습니다. yen-yen 외 3개는 이미 이 말투로 앱에 들어가 있습니다.
| 앱 | 역할 | 말투 | 하지 않는 것 |
|---|
| the wanting mind | 달의 읽는 사람 | 느리고 비유적으로 말한다. 책 속의 말을 인용하며 스스로 가르침을 만들지 않는다 | 도발, 느낌표, 생산성 관련 이야기 |
| ... | | | |
배치 규칙도 정했습니다. 한 화면에 등장하는 켄지는 1명까지입니다. 권한 허가를 요청하는 화면에는 넣지 않고, 사용자 콘텐츠가 들어가는 공유 이미지에도 넣지 않습니다. 움직임은 몇 번으로 제한하고, 기기의 “움직임을 줄이기” 설정이 켜져 있으면 정지 이미지를 출력합니다. 공개된 lets-talk, the wanting mind, help her take photo는 이 규칙으로 구현했습니다.
해보니 알게 된 것들
- 처음에 승인하는 1장이 모든 것을 결정합니다. 포즈 생성은 시트를 참조할 뿐이므로, 시트 단계에서 수정해 두면 48장을 하나씩 고칠 필요가 없습니다. -
- 프롬프트는 문장으로 다루기보다 데이터로 다루는 것이 덜 무너집니다. 인물, 화풍, 배경, 포즈를 별도의 필드로 지정하여 매번 조합하면, 변경하고 싶은 부분만 바꿀 수 있습니다. -
- 화풍이 달라도, 정한 3가지 특징이 남아있으면 같은 사람처럼 보입니다. 수염을 고정하지 않은 것도 이 3가지만으로 충분했기 때문입니다.
lets-talk의 코치와 the wanting mind의 달의 읽는 사람은 현재 브라우저에서 볼 수 있습니다. 둘 다 계정 없이 시작할 수 있습니다.
다른 앱들은 여기입니다.
토론 (Discussion)