AI IMAGE · IMG2IMG

ComfyUI img2img — 있는 그림으로 다시 그리기와 denoise의 정체

junetapa 약 12분

마음에 드는 구도의 그림이 이미 있는데 분위기만 바꾸고 싶을 때, 손으로 대충 그린 낙서를 그럴듯한 그림으로 바꾸고 싶을 때, 쓰는 방법이 img2img(이미지 투 이미지)다. 빈 바탕에서 시작하는 대신 있는 그림을 출발점으로 삼는다. ComfyUI에서 img2img를 처음 해 보면 워크플로 자체는 금방 잇지만, KSampler의 denoise 칸 하나 때문에 한참을 헤매게 된다. 0.5로 두면 어느 정도 바뀌는지, steps를 늘리면 더 많이 바뀌는지 감이 오지 않기 때문이다. 이 글은 ComfyUI 공식 문서와 예제 페이지, 그리고 ComfyUI 저장소의 소스 파일을 직접 열어 denoise가 실제로 무엇을 하는지 한 줄씩 대조해 정리한다.

이어 읽기

ComfyUI를 아직 깔지 않았다면 ComfyUI 입문 실전 가이드부터 본다. 그림 일부만 고치는 법은 ComfyUI 인페인팅에서, 다 된 그림을 크게 만드는 법은 ComfyUI 업스케일에서 다뤘다. 두 글 모두 «원래 그림을 얼마나 남길지»를 denoise로 정하는 자리가 나왔는데, 이 글은 그 denoise 자체를 맡는다.

img2img는 무엇을 넘겨받나

ComfyUI 공식 문서는 Image to Image를 그림을 입력으로 받아 그것을 바탕으로 새 그림을 만드는 워크플로라고 설명한다. 예제 페이지의 설명은 조금 더 구체적이다. 그림을 불러와 VAE로 잠재 공간에 넣은 다음, 1.0보다 낮은 denoise로 그 위에서 샘플링하는 것이 img2img라는 것이다.

이 방식의 바탕이 되는 생각은 확산 모델 연구에서 먼저 정리됐다. 2021년에 공개된 SDEdit 논문은 입력 그림에 먼저 노이즈를 더한 뒤, 확산 모델로 그 노이즈를 걷어 내며 그림을 더 사실적으로 만드는 방법을 제안했다. 논문은 이 방법이 따로 학습하지 않고도 «사실감»과 «원본에 대한 충실도» 사이의 균형을 잡을 수 있다고 적었다. 노이즈를 많이 더하면 모델이 새로 그릴 여지가 커져 그림은 매끈해지지만 원본에서 멀어지고, 적게 더하면 원본은 지켜지지만 고쳐지는 것이 적다. ComfyUI의 denoise가 바로 이 균형을 정하는 손잡이다.

정리하면 img2img가 넘겨받는 것은 두 가지다. 출발점이 될 그림(잠재 공간으로 바꾼 것)과, 그 그림을 얼마나 흔들지 정하는 값(denoise)이다. 프롬프트와 모델은 txt2img와 똑같이 쓴다.

txt2img에서 바뀌는 두 칸

ComfyUI 예제 페이지는 img2img 워크플로가 기본 txt2img와 같고, 다른 점은 빈 이미지 대신 불러온 그림이 샘플러로 들어간다는 것과 denoise가 0.87로 놓여 있다는 것이라고 적었다. 처음 만드는 사람에게 이 설명이 가장 쓸모 있다. 이미 쓰던 txt2img 워크플로에서 두 칸만 바꾸면 되기 때문이다.

순서노드txt2img와 비교
1Load Checkpoint그대로. MODEL · CLIP · VAE 세 출력
2CLIP Text Encode 두 개그대로. 원하는 결과를 긍정 칸에, 피할 것을 부정 칸에
3Load Image새로 추가. 출발점이 될 그림을 올린다
4VAE EncodeEmpty Latent Image 자리에 들어간다. 3번 IMAGE와 1번 VAE를 잇는다
5KSampler4번 LATENT를 latent_image에 잇고 denoise를 1.0보다 낮춘다
6VAE Decode → Save Image그대로

공식 튜토리얼은 Load Checkpoint에 v1-5-pruned-emaonly-fp16.safetensors를 고르고, 이 파일을 ComfyUI/models/checkpoints 폴더에 넣으라고 안내한다. 그다음 Load Image 노드에 그림을 올리고 Ctrl(맥은 Cmd) + Enter로 실행하는 순서다. 예제 페이지는 입력 그림을 ComfyUI의 input 폴더에 넣는다고 적었다. 소스 코드의 Load Image도 이 input 폴더에서 그림 목록을 읽는다.

txt2img와 img2img 워크플로 비교 — 위쪽 txt2img는 Empty Latent Image에서 KSampler(denoise 1.0)로 가고, 아래쪽 img2img는 Load Image와 VAE Encode를 거쳐 KSampler(denoise 1.0 미만)로 간다. 바뀌는 칸은 출발점 노드와 denoise 두 곳
출발점과 denoise, 두 칸만 바뀐다.
공식 튜토리얼이 쓰는 노드 이름

소스 코드에서 그림을 잠재 공간으로 바꾸는 노드의 화면 이름은 «VAE Encode», 그림을 올리는 노드는 «Load Image»다. 인페인팅 글에서 본 «VAE Encode (for Inpainting)»과는 다른 노드다. 이 노드는 가린 칸을 회색으로 채우는 동작이 있어서 img2img에는 맞지 않는다.

denoise의 정체 — 노이즈 일정의 어디서부터 그릴까

denoise를 «원본을 몇 퍼센트 지울지»로 이해하는 경우가 많다. 방향은 맞지만, ComfyUI 소스 코드가 실제로 하는 일은 조금 다르다.

먼저 칸의 정의부터 보자. nodes.py의 KSampler에서 denoise는 기본 1.0, 0.0부터 1.0까지, 0.01 단위로 고르는 값이다. 칸에 붙은 설명 문구는 «적용할 잡음 제거의 양이며, 값이 낮을수록 처음 이미지의 구조를 유지해 이미지에서 이미지로 샘플링할 수 있게 한다»는 뜻이다.

이 값이 쓰이는 곳은 comfy/samplers.py의 set_steps다. 샘플러는 그림을 그리기 전에 «노이즈 일정», 곧 큰 노이즈에서 작은 노이즈로 내려가는 계단 목록(시그마 값들)을 만든다. 코드는 denoise가 0.9999보다 크면 steps 개수 그대로 일정을 만든다. denoise가 그보다 작으면 steps를 denoise로 나눈 값(소수점 아래는 버림)만큼 더 긴 일정을 만든 뒤, 그 일정의 맨 뒤쪽 steps + 1개만 남긴다. denoise가 0 이하이면 일정이 비어 버린다.

공식 문서도 같은 내용을 적었다. ComfyUI는 steps ÷ denoise(버림) 길이의 일정을 만들고 마지막 steps + 1개 시그마만 남기므로, steps 20에 denoise 0.5는 40단계 일정의 노이즈가 낮은 쪽 절반 위에서 20번 샘플링한다는 설명이다.

이 코드를 그림으로 바꿔 말하면 이렇다. 긴 계단의 위쪽(노이즈가 큰 구간)은 건너뛰고, 아래쪽(노이즈가 작은 구간)만 걷는다. 노이즈가 큰 구간은 구도와 큰 형태가 정해지는 자리이고, 노이즈가 작은 구간은 세부와 질감이 다듬어지는 자리다. 위쪽을 많이 건너뛸수록(denoise가 낮을수록) 원본의 구도가 그대로 남고 표면만 바뀐다. 공식 문서가 denoise가 작을수록 원본과 차이가 작고, denoise 1이면 잠재 공간이 완전한 노이즈가 되어 원본의 특징이 사라진다고 설명한 것과 같은 이야기다.

denoise에 따라 노이즈 일정이 잘리는 모습 — steps 20 고정일 때 denoise 1.0은 20단계 일정 전체, denoise 0.87은 22단계 일정의 뒤쪽 20단계, denoise 0.5는 40단계 일정의 뒤쪽 20단계만 걷는다. 왼쪽이 노이즈가 큰 쪽, 오른쪽이 작은 쪽
steps는 실제로 걷는 계단 수, denoise는 긴 계단의 어디서부터 걸을지를 정한다.

숫자로 따라가 보는 steps와 denoise

set_steps의 계산을 그대로 따라가면 몇 가지 헷갈리던 점이 풀린다. 아래 표는 코드의 «steps ÷ denoise, 소수점 버림, 뒤쪽 steps + 1개» 규칙을 그대로 적용한 것이다.

stepsdenoise만드는 일정 길이실제로 걷는 단계건너뛰는 앞쪽 단계
201.020200
200.8722202
200.5402020
200.3662046
100.5201010

표에서 세 가지가 보인다.

첫째, denoise를 바꿔도 걷는 단계 수는 steps 그대로다. steps 20이면 denoise가 1.0이든 0.3이든 샘플러는 20번 움직인다. 공식 문서가 steps 20, denoise 0.5를 «20번 샘플링»이라고 적은 것도 이 때문이다. denoise를 낮춘다고 그리는 시간이 줄지 않는다는 뜻이다. 시간을 줄이고 싶다면 steps를 줄여야 한다.

둘째, 예제 페이지의 0.87은 생각보다 많이 바꾸는 값이다. steps 20에서 0.87은 22단계 일정 가운데 앞쪽 두 단계만 건너뛴다. 노이즈가 가장 큰 구간 대부분을 그대로 걸으므로 원본의 색 배치 정도는 남아도 형태는 크게 바뀔 수 있다. 예제가 이 값을 쓴 것은 원본을 크게 바꾸는 쪽의 예시로 읽는 것이 맞다.

셋째, denoise가 낮을수록 같은 steps를 더 촘촘한 계단에 쓴다. denoise 0.3에서는 66단계 일정의 뒤쪽 20단계만 걷는다. 노이즈가 작은 구간을 잘게 나눠 걷는 셈이라, 원본을 거의 유지하면서 질감을 고르게 다듬는 쪽에 가깝다.

결과를 비교할 때 고정할 것

denoise만의 효과를 보고 싶다면 시드와 steps를 고정하고 denoise만 바꾼다. steps까지 함께 바꾸면 일정 길이와 걷는 단계가 동시에 달라져서 무엇 때문에 결과가 바뀌었는지 가려지지 않는다.

KSampler (Advanced)로 같은 구간 고르기

ComfyUI에는 denoise 대신 «몇 번째 단계부터 걸을지»를 직접 적는 노드도 있다. 화면 이름은 «KSampler (Advanced)»다. 이 노드에는 denoise 칸이 없고, 대신 다음 칸이 있다.

  • add_noise — enable 또는 disable. 소스 코드는 disable이면 빈 노이즈를 쓰도록 바꾼다. img2img처럼 원본에 노이즈를 섞어야 하는 경우에는 enable로 둔다.
  • start_at_step — 기본 0, 0부터 10000까지. 노이즈 일정에서 몇 번째 단계부터 걸을지 정한다.
  • end_at_step — 기본 10000, 0부터 10000까지. 어디서 멈출지 정한다.
  • return_with_leftover_noise — disable이 기본이며, 이때 소스 코드는 마지막까지 노이즈를 모두 걷어 내도록 처리한다.

samplers.py를 보면 start_at_step은 노이즈 일정의 앞쪽을 그 번호만큼 잘라 낸다. 시작 번호가 일정 길이보다 크거나 같으면 샘플링 없이 입력 잠재 이미지를 그대로 돌려준다.

그래서 두 노드는 같은 일을 다른 방식으로 적을 수 있다. 일반 KSampler에서 steps 10, denoise 0.5로 두면 20단계 일정의 뒤쪽 11개 시그마, 곧 마지막 10단계를 걷는다. KSampler (Advanced)에서 steps 20, start_at_step 10으로 두면 같은 20단계 일정에서 앞쪽 10단계를 잘라 내고 남은 10단계를 걷는다. 두 설정은 같은 구간을 걷는다. 다만 샘플러 종류에 따라 일정을 만드는 세부 처리가 조금 다를 수 있으므로, 같은 결과가 필요하면 같은 샘플러 · 스케줄러로 맞춰 확인한다.

Advanced 노드가 편한 경우는 단계 번호로 생각하는 쪽이 익숙할 때, 그리고 한 그림을 두 샘플러에 나눠 그릴 때다. 앞 샘플러는 end_at_step에서 멈추고 노이즈를 남긴 채 넘기고, 뒤 샘플러는 add_noise를 끈 채 그 번호부터 이어 받는 식이다. 처음 img2img를 할 때는 일반 KSampler의 denoise로 충분하다.

입력 그림의 크기는 그대로 따라간다

img2img에는 Empty Latent Image가 없으므로, 결과 그림의 크기는 입력 그림의 크기를 그대로 따라간다. VAE Encode는 그림을 받아 잠재 공간으로 바꿀 뿐 크기를 정하는 칸이 없다. 큰 사진을 그대로 넣으면 모델이 배운 해상도보다 훨씬 큰 캔버스에서 그리게 되어 구도가 흐트러지거나 메모리가 모자랄 수 있다.

이럴 때는 Load Image와 VAE Encode 사이에 «Upscale Image» 노드를 끼워 크기를 맞춘다. 화면 이름은 Upscale Image지만 가로 · 세로를 적어 줄이는 데도 쓰는 노드다. 모델이 배운 해상도는 체크포인트 계열마다 다르므로, 쓰는 모델의 기준 해상도를 먼저 확인하고 입력을 그 근처로 맞춘다. 반대로 작은 그림을 키우면서 다시 그리고 싶다면 그것은 업스케일 글에서 다룬 «키운 뒤 다시 그리기» 갈래와 같은 구조다.

denoise 값을 고르는 순서

공식 문서와 소스 코드는 denoise의 «정답 값»을 정해 두지 않는다. 문서가 말하는 것은 값이 작을수록 원본과 가깝고 클수록 멀다는 방향뿐이다. 그래서 값은 실험으로 정하되, 실험의 순서를 정해 두면 빨리 끝난다.

  1. 원본에서 무엇을 남길지 먼저 적는다. 구도인지, 색 배치인지, 인물의 자세인지. 남길 것이 많을수록 낮은 쪽에서 시작한다.
  2. 시드 · steps · 프롬프트를 고정한다. 위 tip처럼 denoise만 움직여야 비교가 된다.
  3. 간격을 넓게 잡고 몇 장을 뽑는다. 처음에는 낮은 값, 중간 값, 높은 값처럼 넓게 나눠 결과를 나란히 놓는다.
  4. 원하는 결과가 사이에 있으면 그 사이를 좁힌다. 0.01 단위까지 고를 수 있지만, 작은 차이는 시드 차이에 묻히기 쉬우므로 너무 잘게 나누지 않는다.
  5. 프롬프트가 원본과 다투지 않는지 본다. 원본에 없는 큰 물체를 프롬프트로 요구하면 낮은 denoise로는 그릴 자리가 없다. 그럴 때는 값을 올리거나, 그 자리만 인페인팅으로 고친다.

비교한 결과를 나중에 다시 찾는 방법도 정해 두면 좋다. 공식 문서는 워크플로 정보가 메타데이터로 들어 있는 그림을 ComfyUI 화면에 끌어다 놓거나 Workflows 메뉴의 Open으로 열면 워크플로를 그대로 불러올 수 있다고 안내한다. ComfyUI로 저장한 결과 그림 가운데 마음에 든 한 장을 다시 끌어다 놓으면 그때의 denoise · 시드 · steps가 노드에 그대로 돌아오므로, 값을 따로 적어 두지 않아도 같은 자리에서 이어 갈 수 있다.

입력 그림의 권리

img2img의 출발점이 되는 그림은 결과에 형태가 그대로 남는다. 남이 찍은 사진이나 그린 그림을 입력으로 쓸 때는 그 그림의 이용 조건을 먼저 확인한다. 쓰는 체크포인트의 라이선스도 함께 본다.

인페인팅 · 업스케일과 이어지는 자리

이 시리즈의 앞 두 글을 다시 보면, 둘 다 img2img의 변형이었다는 것이 보인다.

  • 인페인팅의 «원래 그림 살리기» 갈래는 VAE Encode 뒤에 Set Latent Noise Mask를 끼운 img2img다. 마스크 안쪽에만 이 글의 denoise 규칙이 적용된다.
  • 업스케일의 «키운 뒤 다시 그리기» 갈래는 늘린 잠재 이미지를 출발점으로 삼은 img2img다. 두 번째 KSampler의 denoise를 1.0보다 낮게 두는 이유가 이 글의 노이즈 일정 설명과 같다.

세 글에 공통인 손잡이는 결국 하나다. 노이즈 일정의 어디서부터 다시 그릴지. 이 손잡이의 동작을 소스 코드 수준에서 알고 나면, 새 워크플로를 받아 왔을 때 denoise 칸에 적힌 숫자가 무엇을 뜻하는지 바로 읽을 수 있다.

자주 묻는 것

img2img에서 denoise는 얼마로 두나요?

정해진 값은 없습니다. 공식 문서는 denoise가 작을수록 원본과 차이가 작고 클수록 차이가 크다고 설명하고, 예제 페이지는 0.87을 씁니다. 시드와 steps를 고정한 채 몇 가지 값을 넓게 뽑아 비교한 뒤 그 사이를 좁히는 방법이 빠릅니다.

denoise를 낮추면 그리는 시간이 줄어드나요?

줄지 않습니다. 소스 코드는 steps ÷ denoise 길이의 일정을 만든 뒤 뒤쪽 steps + 1개 시그마만 쓰므로, 샘플러가 움직이는 횟수는 steps 그대로입니다. 시간을 줄이려면 steps를 줄입니다.

denoise를 1.0으로 두면 어떻게 되나요?

일정을 자르지 않고 처음부터 끝까지 걷습니다. 공식 문서는 이때 잠재 공간이 완전한 노이즈가 되어 원본의 특징이 사라진다고 설명합니다. 사실상 입력 그림을 쓰지 않는 txt2img와 같아집니다.

KSampler와 KSampler (Advanced)는 무엇이 다른가요?

KSampler는 denoise 비율로 일정의 뒤쪽 구간을 고르고, KSampler (Advanced)는 start_at_step · end_at_step으로 단계 번호를 직접 고릅니다. steps 10 · denoise 0.5와 steps 20 · start_at_step 10은 같은 20단계 일정의 뒤쪽 10단계를 걷습니다.

결과 그림 크기가 입력 그림과 같아요. 바꿀 수 있나요?

img2img에는 Empty Latent Image가 없어서 입력 크기를 따라갑니다. Load Image와 VAE Encode 사이에 Upscale Image 노드를 넣어 원하는 가로 · 세로로 맞춘 뒤 인코딩합니다.

참고 자료

  1. ComfyUI 공식 문서. Image to Image 튜토리얼 — 쓰는 모델 파일과 폴더, Load Image에 그림 올리기, denoise가 작을수록 원본과 차이가 작다는 설명, steps 20 · denoise 0.5 예시, denoise 1이면 완전한 노이즈. docs.comfy.org
  2. ComfyUI Examples. Img2Img examples — VAE로 잠재 공간에 넣고 1.0보다 낮은 denoise로 샘플링한다는 설명, 예제 denoise 0.87, 입력 그림은 input 폴더. comfyanonymous.github.io
  3. ComfyUI 소스 코드 nodes.py — KSampler denoise 기본 · 범위 · 단위와 설명 문구, KSampler (Advanced)의 add_noise · start_at_step · end_at_step · return_with_leftover_noise, 노드 표시 이름. github.com
  4. ComfyUI 소스 코드 comfy/samplers.py — set_steps에서 denoise로 노이즈 일정을 자르는 코드, start_step으로 일정을 자르는 코드. github.com
  5. Meng C, et al. SDEdit: Guided Image Synthesis and Editing with Stochastic Differential Equations(arXiv 2108.01073) 프로젝트 페이지 — 입력 그림에 노이즈를 더한 뒤 걷어 내는 방식, 사실감과 원본 충실도 사이의 균형. sde-image-editing.github.io
이 글의 노드 이름 · 기본값 · 범위 · 동작은 2026년 10월 5일에 연 ComfyUI 공식 문서(Image to Image 튜토리얼), ComfyUI 예제 페이지(Img2Img), ComfyUI 저장소의 nodes.py와 comfy/samplers.py 소스 코드, SDEdit 논문 프로젝트 페이지를 따랐다. 표의 일정 길이와 단계 수는 소스 코드의 계산 규칙을 그대로 적용한 값이며, 일부 샘플러는 일정을 만드는 세부 처리가 다를 수 있다. ComfyUI는 자주 갱신되므로 노드 이름과 기본값은 쓰는 판에서 다시 확인한다. img2img 결과의 품질은 모델 · 입력 그림 · 프롬프트 · 시드에 따라 달라지며, 이 글은 특정 결과를 보장하지 않는다.
ComfyUIimg2imgdenoiseKSampler스테이블디퓨전AI이미지
junetapa
junetapa
AI 도구를 직접 굴려 보고 남은 기록을 정리한다.
Twitter Facebook URL 복사