📁 File2. 이미지05 · JPEG 심층

05 · JPEG 심층

이 문서가 답하는 질문: JPEG은 어떻게 동작하며, DCT·양자화 테이블·점진적(progressive) 모드는 무엇이고, 주관적 품질은 어떻게 결정되는가?


한 줄 답 (Pyramid Top)

JPEG의 압축은 공간 도메인 → 주파수 도메인(DCT) → 양자화(저주파 보존, 고주파 버림) → 엔트로피 코딩의 4단 파이프라인이고, 양자화 테이블이 어느 주파수를 얼마나 버릴지를 정의한다. 이 양자화 테이블 = JPEG 품질의 본체다.


Why — 왜 JPEG이 30년이 지나도 살아남나

JPEG(1992 ISO/IEC 10918-1)이 30년이 지난 2026년에도 web image traffic의 절반 이상을 차지하는 이유:

  1. 무료: ISO 표준 + 무료 reference 구현(libjpeg, 1991)
  2. 모든 OS / 브라우저 / 카메라 / 프린터에 디코더 내장
  3. 자연사진에 적합한 압축 모델: 사람 눈의 고주파 둔감성 활용
  4. 점진적 개선 가능: mozjpeg(2014), Guetzli(2017), JPEG XL의 무손실 변환(2021)

JPEG의 핵심 통찰:

  • 사람 눈은 밝기(luminance) 변화에 민감하고 색(chrominance) 변화에 둔감 → YCbCr + 4:2:0
  • 사람 눈은 저주파(부드러운 영역) 에 민감하고 고주파(미세 질감) 에 둔감 → DCT + 양자화

How — JPEG 인코딩 파이프라인

1) 전체 흐름

2) Step 1 — RGB → YCbCr

Y  =  0.299 R + 0.587 G + 0.114 B
Cb = -0.169 R - 0.331 G + 0.500 B + 128
Cr =  0.500 R - 0.419 G - 0.081 B + 128

Y는 휘도(밝기), Cb/Cr은 색차(청색/적색 방향).

3) Step 2 — 크로마 서브샘플링

표기의미압축률용도
4:4:4풀 색해상도1.00×무손실 / 그래픽
4:2:2가로만 1/20.67×방송 / 마스터링
4:2:0가로 세로 1/20.50×웹 JPEG / 비디오 표준

왜 4:2:0이 표준인가: 사람 눈의 색해상도가 휘도 해상도의 절반 수준 → 색 정보를 1/4로 줄여도 거의 못 알아챔.

예외: 빨간 글씨를 4:2:0으로 압축하면 가장자리에 색번짐이 생김. 그래서 디자이너용 JPEG은 4:4:4로.

4) Step 3 — DCT (Discrete Cosine Transform)

8×8 픽셀 블록을 8×8 주파수 계수로 변환.

F(u,v) = (1/4) C(u) C(v) Σ_x Σ_y f(x,y) cos(...) cos(...)

좌상단(0,0) = DC = 블록의 평균값. 오른쪽/아래로 갈수록 고주파.

DC  →→→ 고주파 가로



고주파 세로

이 변환은 손실 없음. 정보를 다시 정렬할 뿐.

5) Step 4 — 양자화 (이게 손실의 본질)

DCT 계수를 양자화 테이블(Q-table)로 나눈 뒤 정수로 반올림.

표준 luminance Q-table (품질 50):

16  11  10  16  24  40  51  61
12  12  14  19  26  58  60  55
14  13  16  24  40  57  69  56
14  17  22  29  51  87  80  62
18  22  37  56  68 109 103  77
24  35  55  64  81 104 113  92
49  64  78  87 103 121 120 101
72  92  95  98 112 100 103  99

좌상단(저주파) 작은 수 = 거의 보존, 우하단(고주파) 큰 수 = 거의 0으로.

품질 N → 표준 테이블에 factor를 곱함:

factor = (N < 50) ? (5000 / N) / 100
                  : (200 - 2N) / 100

품질 95: 테이블 거의 그대로 → 손실 적음 품질 50: 표준 테이블 → 균형 품질 10: 테이블 × 5 → 거의 다 0이 됨 → 블록 노이즈

6) Step 5 — Zigzag → Run-length → Huffman

양자화 후 8×8의 우하단은 거의 0. 지그재그 스캔으로 0이 연속되도록 펼친 뒤:

DC | (run-length, value) (run-length, value) ... EOB

Huffman 또는 Arithmetic 코딩으로 엔트로피 압축.

7) Baseline vs Progressive

모드디코딩 순서용도
Baseline (sequential)위에서 아래로 한 줄씩빠른 디코딩
Progressive저주파 → 고주파 점진적느린 네트워크에서 흐릿한 이미지 먼저

Progressive JPEG는 같은 파일이 ~5% 더 작은 경우가 많음 (mozjpeg는 progressive를 기본).


What — 구체 사양

JPEG 파일 구조 (마커)

SOI (FFD8)        — Start of Image
APP0 (FFE0)       — JFIF 헤더 ("JFIF\0")
APP1 (FFE1)       — EXIF (선택)
APP2 (FFE2)       — ICC 프로파일 (선택)
DQT (FFDB)        — Define Quantization Table
SOF0 (FFC0)       — Start of Frame (baseline)
                    또는 SOF2 (FFC2) — progressive
DHT (FFC4)        — Define Huffman Table
SOS (FFDA)        — Start of Scan
[compressed data]
EOI (FFD9)        — End of Image

매직 넘버: FF D8 FF (3 bytes)

품질별 파일 크기 (1920×1080 풍경 사진 예)

Quality파일 크기PSNRSSIM시각 평가
95580 KB42 dB0.99거의 원본
85240 KB38 dB0.97일반인 구분 어려움
75150 KB35 dB0.95약간의 모기 노이즈
6090 KB32 dB0.92가장자리 노이즈 보임
3045 KB27 dB0.85블록 노이즈 명확
1022 KB22 dB0.70망가짐

실무 가이드: Q=80~85가 대부분의 웹 이미지에 sweet spot.

mozjpeg vs libjpeg 차이

mozjpeg(Mozilla, 2014)는 호환 가능한 JPEG를 만들면서도 515% 작음:

  • Trellis quantization (계수를 비트 비용 고려해 최적화)
  • DC 예측 개선
  • Progressive 기본 활성화
  • Adaptive quantization
# 일반 libjpeg
cjpeg -quality 80 input.ppm > out.jpg          # 100KB
 
# mozjpeg
mozcjpeg -quality 80 input.ppm > out.jpg       # 88KB (-12%)

Guetzli (Google, 2017)

심리시각 모델(Butteraugli)을 사용해 더 작은 JPEG 생성:

  • 품질 84 mozjpeg와 비슷한 품질에서 ~30% 작음
  • 단점: 인코딩 1MB 이미지에 1분+ — 실시간 불가

What-if — JPEG의 함정

함정 1) JPEG → JPEG 재저장 손실

매번 저장할 때마다 양자화 손실이 누적됨. 100번 저장하면 원본 알아볼 수 없음.

대응: 편집은 PNG/TIFF에서 하고, 마지막에 한 번만 JPEG로 export.

함정 2) 텍스트/UI 스크린샷을 JPEG로 → 글자 가장자리 더러움

증상: UI 스크린샷의 텍스트 가장자리에 색 노이즈.

원인: 8×8 DCT 블록 + 4:2:0 서브샘플링이 sharp edge를 잘 처리 못함.

대응: 스크린샷은 PNG, 사진만 JPEG.

함정 3) Progressive JPEG가 일부 디코더에서 깜빡임

증상: 일부 안드로이드 앱에서 progressive 디코딩 중간 단계가 점멸.

대응: 클라이언트 호환성 우려되면 baseline 사용 (mozjpeg -baseline).

함정 4) 품질 100이 무손실이 아님

JPEG은 양자화 테이블이 1이어도 여전히 손실:

  • DCT의 부동소수점 → 정수 반올림
  • YCbCr 변환의 손실
  • 4:2:0 서브샘플링 (4:4:4로도 여전히 정수 반올림 손실)

진짜 무손실 JPEG은 별도 모드(SOF3 lossless predictive)이지만 거의 미지원.

함정 5) 큰 사진을 progressive baseline 혼합 → 일부 도구에서 망가짐

표준은 둘을 섞을 수 없지만, 일부 라이브러리가 SOF0 + SOS multi-scan으로 만들어버림. exiftool 등으로 검증.


Insight — JPEG의 짧은 역사

“JPEG의 J는 위원회 이름이다”

Joint Photographic Experts Group — 1986년 ISO와 ITU가 합동으로 만든 위원회. Joint는 두 표준화 기구의 공동 작업을 의미. 30년이 지나 위원회는 사라졌지만 이름은 남았다.

“libjpeg의 IJG가 JPEG을 살렸다”

1991년 Independent JPEG Group이 무료 reference 구현 발표. 모든 OS가 같은 코드를 채택 → 디코더 호환성 문제가 사라짐. 그 결과 30년 뒤에도 모든 디바이스가 JPEG을 안다.

“점진적 JPEG의 르네상스 — 2014 mozjpeg”

1990년대 점진적 JPEG는 느린 모뎀을 위해 만들어졌지만, 광케이블 시대에 잊혀짐. 2014년 Mozilla가 mozjpeg에서 progressive를 기본으로 부활시킨 이유:

  1. 같은 화질에서 ~5% 작음
  2. 모바일 환경에서 체감 로딩 속도 빠름 (흐릿한 이미지가 먼저 보임) → 페이스북, 핀터레스트, 인스타그램이 일제히 채택.

“JPEG XL은 JPEG의 영혼을 계승한다”

JPEG XL의 가장 영리한 기능: 기존 JPEG 파일을 무손실로 ~20% 더 압축. 픽셀이 아니라 DCT 계수 자체를 더 좋은 엔트로피 코딩으로 재압축. 즉, 모든 기존 JPEG 자산을 변환 손실 없이 작아진 파일로 바꿀 수 있다. 그러나 Chrome이 채택을 거부하면서 보급이 정체된 비극.


한 단락 요약

JPEG = RGB → YCbCr → 4:2:0 → 8×8 블록 → DCT → 양자화 → Huffman의 7단 파이프라인이고, 손실의 본질은 양자화 테이블이 어느 주파수를 얼마나 버릴지 결정하는 데 있다. 사람 눈의 고주파 둔감성색해상도 둔감성을 활용한 30년 전 설계가 여전히 합리적인 이유다. 다음 문서(06-modern-codecs-webp-avif.md)는 같은 원리를 비디오 코덱으로 확장한 WebP/AVIF를 다룬다.