한양과학기술고등학교

에듀테크 프로젝트 대시보드

이산 코사인 변환과 JPEG

이산 코사인 변환과 JPEG

사진 파일이 원본의 1/10 크기로 줄어드는데도 눈에는 거의 똑같아 보이는 이유는? JPEG은 사진을 8×8 조각으로 자른 뒤, 각 조각을 여러 줄무늬(코사인 파동)의 합으로 바꾼다(DCT). 그리고 사람 눈이 둔감한 잔잔한 무늬 성분을 뭉뚝하게 버린다(양자화). 아래에서 직접 조각 하나를 그려 넣고 화질을 조절해 보자.

핵심 아이디어: 자연스러운 사진의 8×8 조각은 대부분 천천히 변한다. 그래서 DCT로 바꾸면 에너지가 왼쪽 위(저주파) 몇 칸에 몰린다. 나머지 고주파 칸은 0에 가까우니, 거칠게 반올림해서 대부분 0으로 만들면 압축이 된다. 0이 잔뜩 이어진 데이터는 아주 잘 접힌다.

1. JPEG이 이미지를 접는 5단계

① 색 변환RGB → YCbCr. 밝기(Y)와 색(Cb·Cr) 분리, 색은 절반 해상도로 다운샘플.
② 8×8 블록이미지를 8×8 픽셀 타일로 자른다. 각 타일을 따로 처리.
③ DCT타일을 64개 코사인 무늬의 계수로 변환. 저주파가 왼쪽 위.
④ 양자화계수를 양자화 표로 나눠 반올림. 여기서 정보가 버려진다(손실).
⑤ 부호화지그재그로 훑어 0의 연속을 RLE + 허프만으로 무손실 압축.

손실이 일어나는 단계는 딱 하나, ④ 양자화다. 나머지는 전부 되돌릴 수 있다. 화질(quality) 슬라이더가 바로 이 양자화 표의 세기를 조절한다.

2. 64개의 코사인 무늬 (DCT 기저)

모든 8×8 블록은 아래 64개 흑백 무늬를 적당한 밝기로 섞어 더한 것으로 정확히 표현된다. 왼쪽 위는 평평한 무늬(평균 밝기 = DC), 오른쪽·아래로 갈수록 촘촘한 줄무늬(고주파)다.

가로축 u = 좌우 줄무늬 촘촘함 · 세로축 v = 상하 줄무늬 촘촘함

3. 직접 해보기 — 블록 하나 압축

왼쪽 캔버스를 클릭·드래그하면 픽셀 밝기가 바뀐다(프리셋 버튼으로 시작해도 된다). 화질 슬라이더를 내리면 살아남는 계수 개수와 오차가 어떻게 변하는지 보라.

원본 8×8

128 값

양자화된 DCT 계수

0 / 64 유지

복원 결과

RMSE 0.0
가운데: 밝은 칸일수록 계수 절댓값이 큼, 검은 칸 = 0(버려짐). 지그재그 경로를 함께 표시.
유지 계수 0 / 64 0이 된 계수 64 평균 오차(RMSE) 0.0 근사 압축률 1.0×

RMSE는 픽셀당 평균 밝기 오차(0~255 척도). 사람 눈은 대략 RMSE 3 이하면 차이를 거의 못 느낀다. 압축률은 "0이 아닌 계수 비율"로 매우 거칠게 추정한 값이다.

4. 양자화 표 — 무엇을 얼마나 버릴까

JPEG 표준이 정한 밝기용 양자화 표다. 각 DCT 계수를 대응하는 값으로 나눠 반올림한다. 오른쪽 아래(고주파)로 갈수록 나누는 수가 커서 거의 다 0이 된다 — 사람 눈이 고주파에 둔감하다는 실험 결과를 표에 새겨 넣은 것이다.

현재 화질에서 실제로 적용되는 양자화 표 (숫자가 클수록 = 더 많이 버림)

5. 코드로 보는 한 블록

# 1D DCT-II 기저 (N=8) — 2D는 행에 한 번, 열에 한 번
def dct2(block):                 # block: 8x8, 값은 -128 시프트됨
    F = zeros(8, 8)
    for u in range(8):
      for v in range(8):
        s = 0
        for x in range(8):
          for y in range(8):
            s += block[x][y] * cos((2*x+1)*u*pi/16) * cos((2*y+1)*v*pi/16)
        F[u][v] = 0.25 * C(u) * C(v) * s   # C(0)=1/√2, 그 외 1
    return F

quant = np.round(F / (Q_TABLE * scale))     # ← 유일한 손실 지점
# 복원: quant * (Q_TABLE*scale) 후 idct2, +128

6. 자주 나오는 흔적

현상원인
격자무늬 블록 경계 (blocking)8×8 블록마다 DC가 조금씩 달라 계단처럼 보임 — 화질 낮을 때 심함
글자·경계 주변 잔물결 (ringing)급격한 모서리 = 고주파인데 고주파 계수를 버려서 생기는 깁스 현상
색 번짐Cb·Cr을 절반 해상도로 다운샘플(4:2:0)했기 때문
여러 번 저장할수록 열화저장할 때마다 재양자화 — 손실이 누적됨
한 줄 요약 — JPEG은 8×8 블록을 DCT로 주파수 성분으로 바꾸고, 눈에 덜 중요한 고주파를 양자화로 거칠게 버린 뒤, 남은 0투성이 데이터를 무손실 압축한다. 관련: 푸리에 변환(같은 아이디어의 복소수 버전), 허프만 코딩(⑤ 단계), 색 공간(YCbCr), 합성곱(이미지 필터), 부동소수점(계수 계산 정밀도).