FFmpeg로 영상을 GIF로 바꾸는 원리 — 팔레트 생성과 디더링의 역할
영상을 GIF로 변환할 때 원본은 1,680만 가지 이상의 색상(24비트 색 공간)을 담지만, 결과물은 겨우 256색으로 압축됩니다. 이 과정에서 어떤 기술이 색 손실을 최소화하고 화질을 유지할까요? FFmpeg가 GIF 변환에 사용하는 팔레트 생성과 디더링 알고리즘을 깊이 있게 들여다보면, 파일 크기와 시각적 품질 사이의 균형이 어떻게 맞춰지는지 명확히 알 수 있습니다.
GIF 형식이 256색으로 제한된 역사적·기술적 배경
GIF(Graphics Interchange Format)는 1987년 CompuServe에서 개발되었을 때 컴퓨터 메모리와 저장공간이 극도로 제한되었던 시대의 산물입니다. 당시 표준 비디오 메모리는 256KB 수준이었으므로, 이미지를 8비트(2^8 = 256색)로 저장하는 것이 최적의 선택이었습니다. 이 제약은 30년이 지난 지금도 GIF 형식의 핵심 특징으로 남아있습니다.
8비트 팔레트는 인덱스 색상(Indexed Color) 모드로 작동합니다. 이미지에 포함된 모든 색상을 0번부터 255번까지 번호를 매기고, 각 픽셀이 어느 번호의 색상을 사용하는지만 기록하는 방식입니다. 예를 들어 파란 하늘은 23번, 초록 잔디는 157번이라고 정의하면, 실제 픽셀 데이터에는 "23, 23, 23, 157, 157, 157..." 이런 식으로 저장됩니다. 이를 통해 24비트 RGB(각 채널 8비트씩, 총 24비트)에서 8비트로 96% 용량을 줄일 수 있었습니다.
그러나 디지털 사진이나 고화질 영상은 훨씬 더 많은 색상을 포함합니다. 카메라 센서가 캡처하는 이미지는 조명, 물질의 질감, 미세한 톤 변화로 인해 수백만 가지 색상을 담고 있습니다. 이를 256색으로 강제 축소하면 색 밴딩(Color Banding), 포스터화(Posterization), 색감 왜곡이 발생합니다. FFmpeg의 팔레트 생성과 디더링 알고리즘은 이 손실을 지능적으로 보완하기 위해 설계되었습니다.
FFmpeg의 팔레트 생성 알고리즘 — 최적의 256색을 선택하는 원리
FFmpeg에서 GIF로 변환할 때 가장 먼저 해야 할 작업은 팔레트 생성(Palette Generation)입니다. 영상에 포함된 모든 색상 중에서 가장 중요한 256가지를 지능적으로 선별하는 과정입니다.
FFmpeg가 기본적으로 사용하는 팔레트 생성 방식은 중앙값 컷(Median Cut) 알고리즘입니다. 이는 다음과 같이 작동합니다:
- 영상의 모든 프레임을 분석하여 사용된 색상의 범위를 파악합니다. 예를 들어 최소 R값이 10, 최대 R값이 245인 식입니다.
- RGB 색 공간을 하나의 큰 직육면체로 생각합니다. 이 직육면체의 가장 긴 축(예: R축)을 중앙에서 나누어 두 개의 작은 직육면체로 분할합니다.
- 분할된 각 영역에 포함된 픽셀의 개수를 세어 더 많은 픽셀을 포함한 영역을 다시 나눕니다.
- 이 과정을 재귀적으로 반복하여 256개의 구간을 만듭니다.
- 각 구간의 모든 픽셀의 RGB 값을 평균내어 대표 색상 1개를 정합니다.
중앙값 컷 알고리즘의 장점은 인간의 시각 인식과 일치한다는 점입니다. 인간의 눈은 색상의 절대값보다 색상 간의 상대적 차이에 더 민감합니다. 따라서 사용 빈도가 높은 색상(예: 배경색)에는 더 많은 할당 공간을 주고, 드물게 나타나는 색상에는 적게 할당하는 것이 최적입니다. 중앙값 컷은 이를 자동으로 수행합니다.
예시로 720p 해상도 30프레임 영상 1초를 생각해봅시다. 프레임 크기는 1,280 × 720 = 921,600 픽셀이고, 30프레임 × 30 = 27,648,000 픽셀의 색상 데이터가 생깁니다. 이 중에서 파란 하늘이 약 20%, 검은 그림자가 15%, 흰색 텍스트가 8% 등으로 분포한다면, 팔레트는 가장 빈번한 색상 256개를 선정합니다.
FFmpeg 명령어에서 팔레트 생성을 명시적으로 지시하려면:
ffmpeg -i input.mp4 -vf "fps=10,scale=320:-1:flags=lanczos,palettegen" palette.png
위 명령은 fps=10(초당 10프레임 샘플링), scale=320:-1(가로 320픽셀로 축소), flags=lanczos(고품질 보간)를 적용한 후 팔레트를 생성합니다. 이때 palettegen 필터가 자동으로 중앙값 컷을 실행하고, 결과를 8비트 256색 PNG 이미지(palette.png)로 저장합니다.
색상 손실의 문제점 — 팔레트만으로 부족한 이유
팔레트를 생성했다고 해서 작업이 끝나는 것은 아닙니다. 원본 영상의 색상을 이 256가지 팔레트 색상으로 변환하는 과정에서 문제가 발생합니다.
예를 들어 원본 이미지에 RGB(100, 150, 200)이라는 파란색이 있는데, 팔레트에 정확히 일치하는 색상이 없다면 어떻게 할까요? 가장 가까운 색상인 RGB(95, 155, 205)로 변환합니다. 이를 색상 양자화(Color Quantization)라고 부릅니다.
문제는 이 변환이 모든 픽셀에 일괄 적용될 때 발생합니다. 원본에서 부드러운 그라데이션(예: 밝은 파란색에서 어두운 파란색으로 점진적인 전환)이 있었다면, 양자화 후에는 명확한 단계가 나타납니다. 이를 포스터화(Posterization) 또는 색 밴딩(Color Banding)이라고 부르며, 사진이나 영상에서 매우 부자연스러워 보입니다.
| 색상 손실 유형 | 발생 원인 | 시각적 증상 | 심각도 |
|---|---|---|---|
| 포스터화 | 연속 그라데이션이 256색 경계에서 끊김 | 층상 색상, 부자연스러운 경계선 | 높음 |
| 색감 왜곡 | 특정 색상이 전혀 다른 색으로 변환됨 | 피부색이 녹색이 되거나, 빨강이 주황색이 됨 | 높음 |
| 명도 손실 | 밝기 정보가 256색 팔레트에 제한됨 | 이미지가 뭉개져 보임 | 중간 |
| 세부 손실 | 미세한 톤 변화가 같은 팔레트 색상으로 병합 | 질감이 사라지고 평면적으로 보임 | 중간 |
이 문제를 해결하기 위해 FFmpeg과 대부분의 이미지 처리 소프트웨어는 디더링(Dithering)이라는 기법을 도입했습니다.
디더링 알고리즘 — 256색으로 백만 가지 색상을 표현하는 착각 기법
디더링은 인간의 눈을 속이는 시각 심리학 기법입니다. 256가지 색상만 사용하면서도 사람의 눈에는 훨씬 더 많은 색상이 있는 것처럼 보이게 만듭니다.
원리는 간단합니다. 인간의 눈은 작은 크기의 색점들이 모여있을 때 그것들을 혼합한 중간색으로 인식합니다. 이를 가산 혼합(Additive Mixing)이라고 부릅니다. 예를 들어 빨강과 파랑의 점들이 촘촘히 섞여 있으면, 먼 거리에서 봤을 때 자주색으로 보입니다. 팔레트에 자주색이 없어도, 빨강 픽셀과 파랑 픽셀을 적절히 배치하면 자주색 효과를 만들 수 있다는 뜻입니다.
FFmpeg이 지원하는 주요 디더링 방식은 다음과 같습니다:
1. Floyd-Steinberg 디더링 (기본값)
가장 널리 사용되는 방식입니다. 각 픽셀을 팔레트 색상으로 변환할 때, 원래 색상과 변환된 색상의 오차(Error)를 계산하고, 이 오차를 주변 픽셀들에게 분배합니다.
처리 순서는 좌상단에서 우하단으로 진행됩니다:
- 현재 픽셀의 RGB 값을 팔레트의 가장 가까운 색상으로 변환합니다.
- 원래 값과 변환된 값의 차이(오차)를 계산합니다. 예: 원본 (100, 150, 200), 팔레트 (95, 155, 205) → 오차 = (5, -5, -5)
- 이 오차를 우측, 좌하단, 중앙하단, 우하단 4개 픽셀에 가중치를 적용하여 분배합니다.
- 오차 분배 비율: 우측 7/16, 좌하단 3/16, 중앙하단 5/16, 우하단 1/16
Floyd-Steinberg의 이 가중치는 수십 년 간의 실험과 인간 시각 심리학 연구를 통해 경험적으로 결정되었습니다. 우측에 70%, 하단에 30%를 분배하는 것이 인간의 눈에 가장 자연스러운 결과를 만듭니다.
2. Bayer 디더링 (순차 디더링)
오차 분배 대신 디더링 패턴 행렬을 사용합니다. 이 패턴은 2×2, 4×4, 8×8 크기의 행렬로, 각 셀에 0부터 최대값 사이의 숫자가 배열되어 있습니다. 픽셀의 밝기를 이 행렬값과 비교하여 팔레트 색상을 선택합니다.
예를 들어 2×2 Bayer 패턴은:
0 2
3 1
이 패턴을 이미지 전체에 반복 적용하면 규칙적인 디더링 패턴이 생성됩니다. Floyd-Steinberg보다 계산이 빠르지만, 일반적으로 품질은 낮습니다. 반대로 패턴이 명확하게 보이므로 일부 예술적 효과 용도로는 의도적으로 사용하기도 합니다.
3. 무디더링 (None) — 최근접 색상 선택
가장 간단한 방식입니다. 각 픽셀을 팔레트의 가장 가까운 색상으로 변환하기만 합니다. 오차 분배나 패턴 적용을 하지 않습니다. 파일 크기는 작지만, 포스터화가 심해 사진이나 영상에는 부적합합니다.
FFmpeg에서 디더링 방식을 지정하려면:
ffmpeg -i input.mp4 -vf "fps=10,scale=320:-1,palettegen=stats_mode=diff" palette.png
palettegen 필터에서 stats_mode를 diff(기본값, Floyd-Steinberg와 유사)로 설정하면 색상 분포를 더 정교하게 분석합니다.
FFmpeg 팔레트 변환 명령의 실전 구성
팔레트를 생성한 후, 실제로 영상을 GIF로 변환하는 단계에서도 디더링을 적용해야 합니다. 다음은 최적화된 명령어 예시입니다:
ffmpeg -i input.mp4 -i palette.png -filter_complex "[0:v]fps=10,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse=dither=floyd_steinberg" output.gif
이 명령의 각 부분을 분석하면:
- fps=10: 초당 10프레임으로 샘플링 (원본이 30fps면 3프레임 중 1프레임만 추출)
- scale=320:-1: 가로를 320픽셀로 축소하고, 세로는 자동 계산 (-1)
- flags=lanczos: Lanczos 필터로 고품질 축소 (기본 bilinear보다 우수)
- paletteuse=dither=floyd_steinberg: 앞서 생성한 팔레트를 적용하며, Floyd-Steinberg 디더링 사용
이 설정으로 생성된 GIF는 일반적으로 원본 영상 크기의 2~5%에 해당하는 용량을 가집니다. 예를 들어 100MB MP4 영상은 2~5MB GIF가 됩니다.
실전 팁 — 팔레트와 디더링 최적화로 화질 극대화
1. 팔레트 생성 시 통계 모드 선택
FFmpeg의 palettegen 필터는 stats_mode 옵션으로 색상 분석 방식을 조절합니다. 기본값 full은 전체 영상을 분석하고, diff는 색상 차이에 중점을 두고, single은 첫 프레임만 분석합니다. 동영상의 경우 full을 사용하되, 색상이 극도로 다양하면 diff를 시도해봅시다.
2. fps와 scale의 균형
fps를 낮추면 (예: 5fps) 파일 크기는 줄지만 움직임이 끊길 수 있습니다. scale을 크게 설정하면 (예: 640px) 화질은 좋지만 용량이 폭증합니다. 블로그나 메신저 용도는 320~480px, 고화질 필요 시 640px을 권장합니다.
3. 색상 다양성이 높은 영상의 대처
카메라로 촬영한 실사 영상이나 사진은 색상이 극도로 다양합니다. 이 경우 palettegen의 max_colors를 256보다 낮게 설정 (예: 128)하면 오히려 주요 색상에 집중되어 화질이 좋아질 수 있습니다. 정반대로, 만화나 로고처럼 색상이 단순하면 max_colors를 줄여도 무방합니다.
4. 디더링 강도 조절
Floyd-Steinberg는 기본적으로 강한 디더링을 적용합니다. 그래픽이나 텍스트 위주라면 none을 시도해보세요. bayer나 heckbert 같은 다른 디더링도 시도 가치가 있습니다.
5. 여러 번 테스트와 비교
최적의 설정은 영상의 성질에 따라 다릅니다. 동일한 소스로 fps 8/10/12, scale 280/320/400, dither floyd_steinberg/bayer 등 여러 조합을 시도하고, 결과 용량과 시각적 품질을 비교하는 것이 필수적입니다.
editpixel으로 간편하게 GIF 변환하기
FFmpeg 명령줄은 강력하지만 설정이 복잡합니다. 별도의 도구 설치 없이 브라우저에서 바로 GIF를 변환하고 싶다면 editpixel의 MP4→GIF 변환 도구를 활용하는 것이 편리합니다. editpixel은 이 글에서 설명한 팔레트 생성과 디더링 알고리즘을 내부적으로 자동 적용하므로, 복잡한 명령어 없이도 최적화된 GIF를 얻을 수 있습니다. 특히 프레임 선택, 해상도 조정, 색상 최적화를 시각적 인터페이스로 제어할 수 있어 초보자도 전문가 수준의 결과를 만들 수 있습니다.
FFmpeg의 기술적 원리를 이해하면, 어떤 도구를 사용하든 GIF 변환 결과를 예측하고 최적화할 수 있습니다. 팔레트 생성이 색상 선택의 기초이고, 디더링이 손실을 보상하는 핵심이라는 점을 기억하면서 프로젝트에 맞는 설정을 찾아보시기 바랍니다.