카테고리 없음

3D 배치 → 실사 인테리어 이미지, 왜 이렇게 어려울까

ideas9710 2025. 8. 11. 11:08
반응형

three.js 배치·JSON·스크린샷을 활용해 스타일별 이미지를 뽑아내려는 사람을 위한 솔직한 가이드

실제로 해보면 금방 막힙니다. three.js로 방과 가구를 배치하는 건 잘 되는데, 그걸 근거로 “레이아웃은 그대로 유지하면서” 스타일만 달리한 실사 이미지를 얻는 건 생각보다 난이도가 높습니다. 아래는 제가 겪은 핵심 난관과, 그걸 줄이기 위한 현실적인 설계 방법을 단계별로 정리한 글입니다. 임베딩, 학습, 파인튜닝까지 고려했을 때 어디서 어렵고 무엇을 선택해야 하는지도 함께 짚습니다.


왜 어려운가 — 본질적인 난관 7가지

  1. 레이아웃 보존 vs. 스타일 자유도의 충돌
    텍스트 프롬프트는 “느낌”을 잘 바꿔주지만, 가구 위치·크기·벽체 같은 구조 보존은 못합니다. 반대로 구조 제어(Depth, Edge, Segmentation 등)를 강하게 걸면 스타일 변화가 빈약해지기 쉽습니다. 둘 사이의 최적점을 찾는 게 핵심 난이도입니다.
  2. 입력 소스가 이질적
    우리는 JSON(정확한 수치), 캡처 이미지(시각적 단서), 텍스트 프롬프트(의도)라는 세 가지 다른 표현을 한 장의 사진으로 합성해야 합니다. 모델은 숫자를 직접 이해하지 못하니, JSON은 결국 마스크/가이드 맵 같은 “이미지형 조건”으로 변환해야 합니다.
  3. 카메라·광원·재질의 불안정성
    three.js 캡처는 대부분 게임 같고 플랫합니다. FOV, 화각, 노출, 그림자가 실사와 다르면, 생성 모델이 “실사로 보정”하려다 레이아웃을 망가뜨리기도 합니다.
  4. 스케일 기준의 부재
    침대가 실제보다 작거나 크게 나오면 전체 감이 무너집니다. JSON에 치수가 있어도, 모델이 그걸 직접 쓰지 못하니 깊이 지도(Depth) 같은 간접 표식으로 스케일을 암시해야 합니다.
  5. 참조 일관성 문제
    같은 배치라도 스타일만 바꾼 이미지들을 연속으로 뽑으면, 침대 모양·문짝 위치가 바뀌는 일이 흔합니다. 시드 고정, 컨트롤 신호 고정, 임베딩/LoRA를 섞어 일관성을 유지해야 합니다.
  6. 데이터·비용·시간의 삼각 딜레마
    파인튜닝을 하면 좋아질 때가 있지만, 그 전에 데이터 수집·정제·라벨링이라는 큰 산이 있습니다. 비용과 시간의 한계 때문에 “프롬프트+ControlNet” 선에서 최대치 성능을 끌어내는 전략이 자주 필요합니다.
  7. 파이프라인의 “끈기” 요구
    실험이 한두 번에 끝나지 않습니다. 프롬프트/강도/컨트롤 채널/업스케일러를 바꿔가며 수십 번 조정해야 합니다. 자동화 스크립트와 캐시가 없으면 금방 지칩니다.

전체 설계도 — 가장 많이 쓰는 현실적 파이프라인

입력

  • scene.json : 방 크기, 가구 위치/치수, 카메라 파라미터
  • capture.png : three.js에서 동일 카메라로 캡처한 저품질 스냅샷
  • style : “북유럽 미니멀”, “모던 럭셔리” 같은 스타일 토큰

전처리

  • 캡처 → Depth/Edge/Segmentation 맵 추출 (ControlNet용)
  • JSON → 2D 평면도/마스크 렌더 또는 레이블된 레이아웃 맵 생성
    예: 벽(1), 바닥(2), 침대(10), 데스크(11) 등 클래스 인덱스 이미지

생성(1차)

  • ControlNet-Depth + ControlNet-Canny/MLSD(직선) 두 채널 병용
  • 프롬프트는 “레이아웃 보존”을 1문장으로 강하게 명시, 나머지는 스타일 설명
  • Guidance(또는 CFG)와 Control strength를 0.6~0.9 구간에서 스윕

정제(2차)

  • 업스케일/리라이트 모델로 디테일 강화
  • 필요 시 소규모 인페인팅으로 어색한 부분만 보정

일관성 유지

  • 시드 고정, 동일 컨트롤맵 재사용
  • 특정 스타일의 텍스트 임베딩 / LoRA를 고정적으로 적용

임베딩·학습·파인튜닝, 언제 쓰고 무엇이 달라지나

  • 텍스트 임베딩(Style/Concept Embedding)
    • 목적: “북유럽 미니멀” 같은 스타일을 문장 대신 고정된 벡터로 재현성 있게 호출
    • 데이터: 스타일별 참고 이미지 20~100장 수준으로도 시도 가능
    • 장점: 가볍고 빠름, 프롬프트 글자 수에 덜 민감
    • 한계: 구조 보존 문제는 여전히 ControlNet/깊이맵에 의존
  • LoRA(경량 파인튜닝)
    • 목적: 특정 재질·마감·조명 톤을 가볍게 학습해 일관적 스타일 확보
    • 데이터: 수십~수백 장, 클래스 다양성보다 톤·재질의 일관성이 중요
    • 장점: 스타일 일관성 향상, 프롬프트 간소화
    • 한계: 데이터 편향이 생기면 가구가 바뀌거나 과적합
  • 풀 파인튜닝(모델 자체 재학습)
    • 목적: 레이아웃+스타일을 모두 우리 도메인에 최적화
    • 데이터: 수천 장 이상, 어ノテ이션(레이아웃/세그멘테이션)까지 있으면 좋음
    • 장점: 최고의 일관성과 재현성
    • 한계: 비용·시간·인프라가 큼. 유지보수 부담도 큼

현실적인 권장 순서
프롬프트+ControlNet → 텍스트 임베딩 → LoRA → (정말 필요하면) 풀 파인튜닝


선택 가이드 표

접근 무엇을 해결 한계 이런 경우에 
프롬프트만 빠른 스타일 실험 레이아웃 붕괴 구조 중요치 않을 때
ControlNet(Depth/Edge) 레이아웃 보존, 스케일감 스타일 자유도 감소 가구 위치·크기 유지 필수
+ Segmentation 카테고리별 재질 유지 세그맵 생성 비용 벽/바닥/가구를 구분해야 할 때
텍스트 임베딩 스타일 재현성 구조는 못 잡음 “브랜드 톤” 고정
LoRA 스타일·재질 일관성 데이터 편향 특정 재질·톤 고정
풀 파인튜닝 전반적 성능 상향 비용/시간 큼 제품 상용화, 대규모 트래픽

웹 구현 구조 예시(파일 트리 포함)

/interior-gen/
├─ frontend/
│  ├─ src/
│  │  ├─ App.jsx
│  │  ├─ components/
│  │  │  ├─ ThreeRoomCanvas.jsx
│  │  │  ├─ StylePicker.jsx
│  │  │  └─ ResultGallery.jsx
│  │  ├─ libs/
│  │  │  └─ api.js
│  │  └─ styles.css
│  └─ public/
│     └─ index.html
└─ backend/
   ├─ main.py
   ├─ routers/
   │  ├─ generate.py
   │  ├─ preprocess.py
   │  └─ health.py
   ├─ services/
   │  ├─ controlnet_pipeline.py
   │  ├─ embedding.py
   │  └─ upscaler.py
   ├─ utils/
   │  ├─ json_to_layoutmap.py
   │  ├─ depth_estimator.py
   │  └─ seed_tools.py
   └─ models/
      └─ lora/
         └─ nordic_minimal_v1.safetensors

핵심 흐름

  1. 사용자가 three.js에서 가구 배치 후 scene.json 다운로드 + 동일 뷰로 capture.png 캡처.
  2. 프론트에서 두 파일 업로드(POST /generate).
  3. 백엔드가 전처리(json_to_layoutmap.py, depth_estimator.py)로 컨트롤 맵 생성.
  4. controlnet_pipeline.py가 Depth+Edge(+선택 Seg)로 1차 생성.
  5. upscaler.py가 업스케일 및 디테일 보정.
  6. 결과 URL을 프론트로 반환 → ResultGallery가 스타일별 썸네일 그리드로 표시.

JSON 스키마 예시와 전처리 팁

예시: scene.json

{
  "room": { "width": 402.6, "depth": 429.1, "height": 230 },
  "camera": { "fov": 55, "target": [200, 100, 200], "position": [450, 200, 450] },
  "objects": [
    { "name": "Bed", "type": "bed", "pos": [100, 0, 105], "size": [150, 60, 200], "ry": 0 },
    { "name": "Desk", "type": "desk", "pos": [343, 0, 32], "size": [120, 75, 60], "ry": 0 }
  ]
}

전처리 핵심

  • three.js 카메라 파라미터를 그대로 백엔드 깊이 추정/렌더에 반영.
  • JSON을 평면도/세그맵으로 렌더할 때 픽셀 격자와 카메라 투영을 캡처와 맞추기.
  • 바닥/벽/가구 클래스 인덱스를 고정해 세그멘테이션 맵 일관성 확보.

프롬프트 설계 체크리스트

  • 첫 줄에 “Keep exact layout. Do not move or resize furniture.” 같은 구조 보존 문장.
  • 스타일 문구는 명확한 재질·광원·렌즈로 구체화.
    예: “soft daylight, f/5.6, 24–70mm, oak wood grain, matte wall paint”
  • 금지어도 명확히.
    예: “no built-in wardrobes, no alcoves, no extra furniture”
  • 네거티브 프롬프트에 CG/plastic look, over-smoothing 포함.

하이퍼파라미터 운용 원칙

  • Control strength를 0.6~0.9 구간에서 스윕. 레이아웃이 흔들리면 ↑, 텍스처가 메마르면 ↓.
  • Guidance/CFG는 4~8 사이를 기본. 너무 높으면 과도한 텍스트 종속으로 왜곡.
  • 시드 고정으로 같은 배치, 다른 스타일을 안정적으로 비교.
  • 스타일 세트별로 프리셋 JSON을 만들어 재현성 확보.

일관성 전략

  • 동일한 컨트롤맵시드를 유지한 채 스타일 임베딩/LoRA만 교체.
  • 결과가 흔들리면 ① 업스케일러 단계 고정 ② 인페인팅으로 국소 보정.
  • 가구 재질·색상까지 일관하게 하려면 소형 LoRA로 톤 고정이 효과적.

임베딩/LoRA/파인튜닝을 고려한 데이터 계획

  • 텍스트 임베딩용: 스타일별 대표 이미지 30~50장. 톤·광원 일관성이 중요.
  • LoRA용: 100~300장. 같은 가구 카테고리를 다양한 각도·조명으로.
  • 풀 파인튜닝: 2천 장 이상 권장. 가능하면 레이아웃/세그라벨 포함.
    비용과 일정이 크므로, 제품화 직전 “결정적 병목”일 때만 선택하는 게 현실적입니다.

품질 기준과 자동 평가

  • 구조 정확도: 생성 이미지에서 객체 검출/분할 후, JSON 투영 위치와의 IoU 측정.
  • 스타일 적합도: CLIP 유사도(텍스트 “nordic minimal” vs. 이미지).
  • 재질 충실도: 재질 키워드(“oak”, “linen”)에 대한 이미지 패치 임베딩 유사도.

간단한 메트릭이라도 CI처럼 자동화하면 튜닝 속도가 급격히 올라갑니다.


비용·속도 최적화

  • 전처리(깊이/에지/세그)는 캐시. 같은 캡처엔 다시 계산하지 않기.
  • 스타일 프리셋별로 배치 생성하고, 업스케일은 합격작만.
  • 로컬 실험은 저해상도에서 튜닝 완료 → 클라우드에서 고해상도 한 번에.

 

반응형