Skip to main content

lemon-manga-translator

일본어 → 한국어 만화(망가) 자동 번역 파이프라인.

한 페이지를 받아 텍스트 영역을 검출하고, Vision LLM으로 SFX 분류 + 번역을 동시에 수행한 뒤, AOT 인페인팅으로 원문을 지우고 그 위에 한국어 텍스트를 렌더한다.

Quick Start

pip install lemon-manga-translator
from lemon_manga_translator import MangaTranslator
from PIL import Image

mt = MangaTranslator(
    openrouter_api_key="sk-or-...",
    openrouter_model="google/gemini-3.1-flash-lite-preview",
)
mt.prepare()  # HuggingFace에서 ONNX 모델 자동 다운로드

image = Image.open("page.jpg")
result = mt.translate(image)
result.save("output.png")

prepare() 호출 시 lemondouble/lemon-manga-translator에서 ONNX 모델(CTD 77 MB + AOT 23 MB)을 다운로드한다. 이후 캐시되어 재다운로드하지 않는다.

로컬 모델 사용

mt = MangaTranslator(
    openrouter_api_key="sk-or-...",
    openrouter_model="google/gemini-3.1-flash-lite-preview",
    model_source="/path/to/local/models",  # HF 대신 로컬 경로
)

파이프라인

원본 이미지 ──▶ 1) CTD 검출 ──▶ 2) 마스크 제한 ──▶ 3) Vision LLM ──▶ 4) SFX 드롭
                                                                         │
                                                                         ▼
   최종 이미지 ◀── 7) 텍스트 렌더 ◀── 6) 말풍선 확장 ◀── 5) AOT 인페인트
단계 설명
1) CTD 검출 YOLOv5 bbox + UNet 마스크로 텍스트 영역을 검출한다. YOLO bbox를 seed로 flood fill해 주변 UNet 텍스트를 회수하고, 텍스트 섬 단위로 bbox를 정리한다.
2) 마스크 제한 최종 텍스트 bbox 밖의 마스크 픽셀을 제거해 페이지 번호·잡글자를 인페인트 대상에서 뺀다.
3) Vision LLM 페이지에 번호 박스를 그려 OpenRouter Vision API에 한 번만 호출. 각 블록에 대해 SFX 여부 + 한국어 번역을 JSON으로 받는다. 호출당 wall-clock 60초 상한 · 최대 5회 재시도.
4) SFX 드롭 SFX(의성어/효과음)로 분류된 블록을 마스크에서 제거. 그림의 일부이므로 지우지 않는다.
5) AOT 인페인트 AOT-GAN으로 마스크된 텍스트를 자연스러운 배경으로 채운다.
6) 말풍선 확장 인페인트 결과에 flood fill을 걸어 말풍선 전체 영역을 찾고, 같은 flood zone 또는 같은 부모 bbox의 렌더 영역이 겹치지 않도록 나눈다.
7) 텍스트 렌더 확장된 영역 안에 한국어 번역을 렌더한다. 같은 flood zone의 블록은 공통 폰트 크기를 사용한다. 폰트: Jua(primary) + PretendardJP(fallback).

GPU 사용

device="cuda"를 지정하면 ONNX 추론(CTD, AOT)이 GPU에서 실행된다.

mt = MangaTranslator(
    openrouter_api_key="sk-or-...",
    openrouter_model="google/gemini-3.1-flash-lite-preview",
    device="cuda",
)

GPU 사용 시 onnxruntime 대신 환경의 CUDA 버전에 맞는 onnxruntime-gpu를 직접 설치해야 한다. 자세한 호환성은 onnxruntime 공식 문서 참고.

튜닝

각 단계의 하이퍼파라미터는 dataclass로 노출되어 있다. MangaTranslator 생성자에 주입하면 단계 동작을 바꿀 수 있고, 미지정 시 라이브러리 기본값을 사용한다.

from lemon_manga_translator import (
    MangaTranslator,
    CtdConfig,
    BubbleConfig,
    PipelineConfig,
    RenderConfig,
)

mt = MangaTranslator(
    openrouter_api_key="sk-or-...",
    openrouter_model="google/gemini-3.1-flash-lite-preview",
    ctd_config=CtdConfig(confidence_threshold=0.4),
    bubble_config=BubbleConfig(max_area_ratio=0.06),
    pipeline_config=PipelineConfig(expand_bubbles=True),
    render_config=RenderConfig(min_font_size=12, max_font_size=64),
    vision_system_prompt="path/to/custom_prompt.txt",  # 파일 경로 또는 문자열
)
Config 다루는 것
CtdConfig YOLO confidence/NMS, UNet 마스크 임계, 모폴로지 반경, 말풍선 flood 톨러런스, 텍스트 클러스터 최소 bbox 등
BubbleConfig 말풍선 flood fill 톨러런스, 최대 영역 비율, 블록 패딩, 최소 seed coverage
PipelineConfig drop_bbox_pad, skip_llm, expand_bubbles
RenderConfig 텍스트 색/스트로크, 패딩 비율, 최소·최대 폰트 크기

기본 Vision 시스템 프롬프트는 lemon_manga_translator/prompts/vision_system.txt에 동봉되어 있다.

배경 마스킹

Vision LLM에 보내는 이미지에서 텍스트 bbox 바깥 영역을 마스킹할 수 있다. 배경 정보를 줄여 LLM이 텍스트에 집중하도록 유도하는 옵션.

from lemon_manga_translator import MangaTranslator

mt = MangaTranslator(
    openrouter_api_key="sk-or-...",
    openrouter_model="google/gemini-3.1-flash-lite-preview",
    bg_mask_mode="blur",  # "none" | "solid" | "blur" | "overlay"
)
모드 설명
none 기본값. 원본 이미지 그대로 전송.
solid bbox 밖을 흰색으로 채움.
blur bbox 밖을 강한 가우시안 블러 처리.
overlay bbox 밖을 반투명 회색 오버레이.

테스트 스크립트에서도 --bg-mask 플래그로 사용 가능:

uv run python scripts/test_pipeline.py image.jpg --bg-mask blur

배치 번역

여러 페이지를 병렬로 번역할 수 있다. 내부적으로 ThreadPoolExecutor를 사용하며, 입력 순서가 보장된다.

images = [Image.open(p) for p in page_paths]
results = mt.translate_batch(images, max_workers=4)

for i, r in enumerate(results):
    r.save(f"output_{i:03d}.png")

내부 컴포넌트가 stateless라 단일 인스턴스를 스레드 간 공유해도 안전하다.

진행 상황 콜백

on_progress를 넘기면 각 단계를 시작할 때 PipelineStage로 호출된다. 텍스트가 없는 페이지는 DETECT 이후 바로 끝난다.

from lemon_manga_translator import PipelineStage

def on_progress(stage: PipelineStage) -> None:
    print(stage)  # detect → translate → inpaint → render

result = mt.translate(image, on_progress=on_progress)
단계 파이프라인
DETECT 1~2
TRANSLATE 3~4
INPAINT 5
RENDER 6~7

on_stage_done을 넘기면 각 단계가 끝날 때 StageResult로 중간 결과를 받는다.

단계 채워지는 필드
DETECT text_blocks (bbox)
TRANSLATE vision_results (블록별 번역, no_translate)
INPAINT image (원문을 지운 이미지)
RENDER image (최종 이미지)

번역 수정 후 다시 렌더

translations에 VisionBlockResult 목록을 넘기면 Vision LLM을 호출하지 않고 그 번역으로 인페인트·렌더만 다시 한다. 같은 이미지는 검출 결과가 같으므로 block_index가 그대로 유지된다. no_translate=True인 블록은 지우지 않고 원문을 남긴다.

from dataclasses import replace

first = []
mt.translate(image, on_stage_done=lambda result: first.extend(result.vision_results or []))

edited = [replace(first[0], ko_translation="수정한 번역")] + first[1:]
result = mt.translate(image, translations=edited)

로깅

라이브러리는 표준 logging 모듈로 단계별 진행 상황을 INFO 레벨로 기록한다. 호출자가 핸들러를 설정하면 실시간 로그가 보인다.

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s: %(message)s",
    datefmt="%H:%M:%S",
)

mt = MangaTranslator(...)
mt.prepare()
mt.translate(image)

샘플 출력:

11:53:10 INFO lemon_manga_translator.pipeline: 페이지 처리 시작 (크기=1200x1800)
11:53:10 INFO lemon_manga_translator.pipeline: [1/7] CTD 검출 완료: 텍스트 12블록
11:53:11 INFO lemon_manga_translator.pipeline: [3/7] Vision LLM 완료 (시도=1회, 대사=11, SFX/제외=3)
11:53:13 INFO lemon_manga_translator.pipeline: [7/7] 텍스트 렌더 완료 (11블록)

Docker

pre_download()로 빌드 시 모델을 미리 캐싱하면 컨테이너 시작 시 다운로드 없이 바로 사용할 수 있다.

FROM python:3.11-slim

RUN pip install lemon-manga-translator

# 빌드 시 ONNX 모델을 캐시에 다운로드 (세션 로드 없음)
RUN python -c "from lemon_manga_translator import MangaTranslator; \
    MangaTranslator.pre_download()"

COPY server.py .
CMD ["python", "server.py"]
# server.py — prepare()는 캐시에서 즉시 로드
mt = MangaTranslator(
    openrouter_api_key=os.environ["OPENROUTER_API_KEY"],
    openrouter_model="google/gemini-3.1-flash-lite-preview",
)
mt.prepare()

Debug

from lemon_manga_translator.api.debug_translator import DebugTranslator

dt = DebugTranslator(
    openrouter_api_key="sk-or-...",
    openrouter_model="google/gemini-3.1-flash-lite-preview",
)
dt.prepare()

image = Image.open("page.jpg")
result = dt.translate(image, debug_dir="./debug/")

result.detection       # CTD 결과 (mask + text_blocks)
result.inpainted       # AOT 인페인트 결과
result.vision_results  # LLM 응답 (block_index, is_sfx, ko_translation)
result.save_all("./debug/")

debug_dir를 지정하면 각 단계의 중간 산출물이 파일명 prefix로 정렬되어 저장된다.

디버그 산출물 목록
파일 의미
00_input.png 원본 입력 이미지
00_params.json 실행 하이퍼파라미터 스냅샷
01_mask_raw.png UNet 원본 float 마스크
01_mask_refined.png 임계화 + 모폴로지 후처리 후 마스크
01b_mask_bbox_restricted.png 최종 텍스트 bbox 밖 마스크 제거 후
02_bboxes.png 원본 위에 최종 텍스트 박스 + 박스별 YOLO/UNet 신뢰도 라벨
02_text_blocks.json 검출된 텍스트 블록 메타(bbox, yolo_confidence 등) JSON
02a_balloon_flood_scope.png YOLO seed 기반 CTD flood fill 영역
02a_balloon_flood_overlay.png CTD flood fill 영역을 원본 위에 하늘색 반투명 오버레이
03_mask_overlay.png 마스크를 원본 위에 핑크색 반투명 오버레이
03b_mask_filtered.png SFX 드롭 후 마스크 (해당 시만)
03c_mask_filtered_overlay.png SFX 드롭 마스크 오버레이 (해당 시만)
04_inpainted.png AOT 인페인트 결과
05a_annotated.png LLM에 전송된 번호 박스 이미지
05_vision.json LLM 응답 JSON
05_cost.json 토큰/비용 정보
05b_render_bboxes.png 원본 bbox(빨강) + 확장된 render_bbox(초록) + 말풍선 확장 status/expansion ratio 라벨
06_final.png 최종 결과

Dev Playground

파라미터를 바꿔가며 단계별로 결과를 확인하는 로컬 디버깅 GUI(dev-tools/playground)가 별도로 들어 있다 — 라이브러리 PyPI 패키지에는 포함되지 않는다. 사용법은 dev-tools/README.md 참고.

모델·코드·폰트 출처

모델 가중치는 lemondouble/lemon-manga-translator에서 PyTorch(safetensors) + ONNX 형태로 제공된다.

구성 요소 출처 라이선스
Comic Text Detector 원 저자 dmMaze/comic-text-detector · 배포 manga-image-translator beta-0.3 GPL-3.0
AOT Inpainting 아키텍처 AOT-GAN (Zeng et al., 2021) · 파인튜닝 manga-image-translator beta-0.3 · 리팩 mayocream/aot-inpainting GPL-3.0
detection/ctd_utils/ zyddnys/manga-image-translator manga_translator/detection/ctd_utils (벤더) GPL-3.0
assets/fonts/Jua-Regular.ttf The Jua Project Authors / Woowahan Brothers · Google Fonts: Jua SIL OFL 1.1
assets/fonts/PretendardJP-Regular.otf orioncactus/pretendard (Kil Hyung-jin) SIL OFL 1.1
Vision LLM (런타임 API) OpenRouter 경유 호출 번들되지 않음. 사용 모델 제공자 ToS

License

GPL-3.0

Metadata

Release files for lemon-manga-translator 0.0.19

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lemon-manga-translator 0.0.19
File Size Uploaded
lemon_manga_translator-0.0.19.tar.gz 3.5 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for lemon-manga-translator 0.0.19
File Interpreter ABI Platform
lemon_manga_translator-0.0.19-py3-none-any.whl Python 3 none any Details

Total release size: 7.1 MB

Release files / lemon_manga_translator-0.0.19.tar.gz

Download URL lemon_manga_translator-0.0.19.tar.gz
Size 3.5 MB
Tags Source
SHA-256 checksum
How to use checksums
933e301473dd03a9398cd7b13734b0714d3cdb4712d67e2f45d879fc3bdaecf2
BLAKE2b-256 checksum
How to use checksums
d0b791caf134836f683ea053bd6bc4f3a7e595b4d5cc95525058d7a30ab8380a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Release files / lemon_manga_translator-0.0.19-py3-none-any.whl

Download URL lemon_manga_translator-0.0.19-py3-none-any.whl
Size 3.5 MB
Tags Python 3
SHA-256 checksum
How to use checksums
3b0b48e6eab88c503460dde4cc05d9b416da1065b3abe9bf29c82df7168c12e5
BLAKE2b-256 checksum
How to use checksums
ab690d41879ad715edd31e92fed96c3ce05cb00897f062daa93087ed8a6bed83
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.0

2 release files

0.0.20

2 release files

This release

0.0.19 This release

2 release files

0.0.18

2 release files

0.0.16

2 release files

0.0.15

2 release files

0.0.14

2 release files

0.0.13

2 release files

0.0.12

2 release files

0.0.11

2 release files

0.0.10

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page