푸리에 이미지 변환은 사진을 픽셀 격자가 아니라 2차원 사인파를 얼마나 섞었는지의 장부로 바꿔 읽는 방법이다. 이 장부를 진폭과 위상으로 갈라보면, 이미지의 구조 정보는 거의 전부 위상 쪽에 들어 있다.
사진에도 이퀄라이저가 있다면

음악 앱의 이퀄라이저에서 베이스 슬라이더를 끝까지 밀어 올린 적이 있을 것이다. 저음이 묵직하게 부풀고, 트레블을 내리면 쨍한 고음이 사그라든다. 슬라이더 하나가 소리 전체를 새로 녹음한 게 아니다. 소리를 시간의 흐름이 아니라 "어떤 높이의 음을 얼마나 담았는가"라는 주파수 성분으로 갈라, 그중 한 칸만 조절한 것이다.
사진에도 똑같은 이퀄라이저가 있다면 어떨까. 놀랍게도 있고, 그게 이 글이 다루는 푸리에 이미지 변환이다. 소리를 주파수로 다루듯, 이미지도 주파수로 다룰 수 있다. 다만 여기서 말하는 주파수는 시간당 진동이 아니라 공간 주파수(spatial frequency) 다 — 화면을 가로지르며 밝기가 얼마나 촘촘하게 오르내리는가를 뜻한다.
넓은 하늘이나 매끈한 벽처럼 밝기가 천천히 변하는 부분은 낮은 공간 주파수다. 머리카락 한 올, 벽돌의 경계선처럼 밝기가 급하게 튀는 부분은 높은 공간 주파수다. 이미지를 이 주파수들의 목록으로 펼쳐 놓으면, 사진의 이퀄라이저 슬라이더를 하나씩 손에 쥐게 된다.
이미지는 사인파의 합이다 — 스펙트럼 읽는 법
시작은 단순한 그림 한 장이다. 화면 전체를 가로지르는 줄무늬 하나. 밝기가 사인파를 그리며 오르내리는, 세로로 선 줄무늬다. 이런 줄무늬는 방향(가로냐 세로냐)과 조밀함(줄 간격)만으로 완전히 정해진다. 바로 2차원 사인파다.
푸리에가 밝힌 사실은 이렇다. 아무리 복잡한 이미지라도, 방향과 조밀함이 서로 다른 이런 줄무늬들을 알맞은 세기로 겹쳐 쌓으면 원래 그림이 그대로 나온다. 사진은 픽셀의 격자이기 이전에 줄무늬들의 합인 셈이다. 그러니 사진 한 장을 "어떤 줄무늬를 얼마나 섞었는가"의 장부로 적을 수 있다. 이 장부가 바로 스펙트럼이다.
그림 1는 그 장부를 눈으로 보여준다. 왼쪽은 원본 이미지, 오른쪽은 로그로 밝기를 눌러 그린 진폭 스펙트럼이다. 스펙트럼을 읽는 규칙은 세 줄이면 충분하다.
- 중심은 저주파. 한가운데는 밝기가 천천히 변하는 성분, 즉 이미지의 큰 형태와 전체 밝기를 담는다. 자연스러운 사진은 언제나 중심이 가장 밝다.
- 가장자리는 고주파. 중심에서 멀어질수록 촘촘한 줄무늬, 즉 디테일과 경계선을 담는다.
- 방향은 수직으로 꺾인다. 이미지의 줄무늬가 세로로 서 있으면, 스펙트럼의 밝은 점은 가로 방향으로 뻗는다. 무늬가 결을 이루는 방향과 스펙트럼이 뻗는 방향은 항상 직각이다.
세 규칙만 손에 쥐면 스펙트럼은 더 이상 알 수 없는 얼룩이 아니라, 무늬의 결이 어디로 얼마나 촘촘하게 흐르는지 짚어주는 지도가 된다.
2D 푸리에 변환의 정의와 대칭, 그리고 1/f² 감쇠
이제 그 장부를 적는 식을 보자. 이미지 크기를 $M \times N$이라 하자. 이 이미지 $f(x,y)$에 대한 2차원 이산 푸리에 변환(DFT)은 이렇게 정의된다.
겁먹을 식이 아니다. 식 1는 "모든 픽셀을 하나씩 훑으면서, $(u,v)$번째 줄무늬와 얼마나 닮았는지 점수를 매겨 합산하라"는 지시일 뿐이다. 그 점수의 묶음 $F(u,v)$가 스펙트럼이고, 코드로는 딱 한 줄이다. 작은 합성 패턴으로 계산해 스펙트럼이 정말 몇 개의 점으로 뭉치는지 확인해 보자.
import numpy as np
# 8x8 합성 이미지: 가로 방향 주파수 2 줄무늬 + 세로 방향 주파수 1 줄무늬
x = np.arange(8)
f = np.sin(2*np.pi*2*x/8)[None, :] + 0.5*np.cos(2*np.pi*1*x/8)[:, None]
F = np.fft.fft2(f) # 2D DFT — 딱 한 줄
amp = np.abs(F)
print("amplitude[:3, :3] =")
print(np.round(amp[:3, :3], 1))
# 켤레 대칭 확인: F(-u,-v) == conj(F(u,v))
idx = (-np.arange(8)) % 8
F_flip = np.conj(F[np.ix_(idx, idx)])
print("conjugate symmetric:", np.allclose(F, F_flip))amplitude[:3, :3] =
[[ 0. 0. 32.]
[16. 0. 0.]
[ 0. 0. 0.]]
conjugate symmetric: True두 줄무늬만 섞은 이미지라 스펙트럼도 딱 몇 칸에만 값이 뭉친다. 가로 주파수 2 성분은 [0,2]에, 세로 주파수 1 성분은 [1,0]에 나타난다. 나머지는 0이다. 이미지를 줄무늬의 목록으로 적는다는 말이 무슨 뜻인지, 배열 하나로 눈에 잡힌다.
마지막 줄의 True는 그저 지나칠 값이 아니다. 실수 값 이미지(색이 아니라 밝기만 있는 흑백)의 스펙트럼은 언제나 원점을 기준으로 켤레 대칭을 이룬다.
식 2에서 별표는 켤레 복소수를 뜻한다. 한쪽 점을 알면 원점 반대편 점은 자동으로 정해진다는 말이다. 그래서 스펙트럼 그림은 늘 중심을 축으로 점대칭으로 보인다. 정보의 절반은 처음부터 거울상이라, 실제로 담긴 것은 그 절반뿐이다.
그런데 자연 이미지의 스펙트럼에는 규칙이 하나 더 숨어 있다. 중심(저주파)에 에너지가 압도적으로 쏠려 있고, 바깥(고주파)으로 갈수록 급격히 옅어진다 . 얼마나 급하게 옅어지는지 방사 방향으로 평균 내어 로그-로그 축에 그리면 기울기가 드러난다.
import numpy as np
from skimage import data
img = data.camera().astype(float) # 512x512 표준 이미지 (scikit-image 내장)
F = np.fft.fftshift(np.fft.fft2(img))
power = np.abs(F)**2
cy, cx = np.array(power.shape) // 2
y, x = np.indices(power.shape)
r = np.hypot(y - cy, x - cx).astype(int)
radial = np.bincount(r.ravel(), power.ravel()) / np.bincount(r.ravel())
freqs = np.arange(len(radial))
mask = (freqs >= 3) & (freqs <= 200) # DC와 나이퀴스트 꼬리 제외
slope = np.polyfit(np.log(freqs[mask]), np.log(radial[mask]), 1)[0]
print(f"radial power-spectrum slope = {slope:.2f}")radial power-spectrum slope = -2.61이 사진의 실측 기울기는 약 $-2.6$이다. 사진마다 조금씩 다르지만, 자연 이미지 전반이 대략 $1/f^2$(기울기 $-2$) 계열로 감쇠한다는 것이 Field(1987)의 관찰이고, 이 사진도 그 계열에 든다. 그림 2가 그 곡선이다. 이 한 줄이 뒤에 나올 모든 이야기의 뿌리다. 에너지가 저주파에 쏠려 있다는 것은, 고주파를 웬만큼 버려도 그림이 크게 상하지 않는다는 뜻이다. JPEG가 사진을 10분의 1로 줄이고도 멀쩡한 이유가 바로 이 기울기에 적혀 있다.
진폭과 위상을 갈라보다 — 스왑 실험
여기서 이 글의 심장으로 들어간다. 스펙트럼의 각 점 $F(u,v)$는 복소수다. 복소수는 크기와 각도로 갈라 적을 수 있다.
식 3에서 $|F(u,v)|$는 진폭 — 그 줄무늬를 얼마나 세게 섞었는가다. $\phi(u,v)$는 위상 — 그 줄무늬를 어디서부터 시작할지, 즉 어느 위치에 밝은 마루가 오게 정렬할지를 정한다. 진폭이 "얼마나"라면 위상은 "어디에"다.
둘 중 어느 쪽이 이미지의 정체를 쥐고 있을까. 답을 보는 가장 잔인한 실험은 두 이미지의 위상을 서로 맞바꾸는 것이다. 한 이미지의 진폭에 다른 이미지의 위상을 붙여 역변환한 결과가 누구를 닮는지, 그것이 곧 답이다 .
import numpy as np
from skimage import data, color
A = data.camera().astype(float) # 512x512
B = color.rgb2gray(data.astronaut()).astype(float) * 255
FA, FB = np.fft.fft2(A), np.fft.fft2(B)
ampA, phB = np.abs(FA), np.angle(FB)
# A의 진폭 + B의 위상 → 역변환
recon = np.real(np.fft.ifft2(ampA * np.exp(1j * phB)))
def corr(p, q):
return np.corrcoef(p.ravel(), q.ravel())[0, 1]
print(f"위상 준 쪽(B)과의 상관: {corr(recon, B):.2f}")
print(f"진폭 준 쪽(A)과의 상관: {corr(recon, A):.2f}")위상 준 쪽(B)과의 상관: 0.73
진폭 준 쪽(A)과의 상관: 0.11숫자가 편을 확실히 갈랐다. A의 진폭을 썼는데도 재구성 이미지는 A가 아니라 위상을 준 B를 훨씬 더 닮았다. 그림 3의 네 패널이 이 배신을 눈으로 확인시킨다. 세 번째, 네 번째 패널을 보면 진폭이 어디서 왔는지는 거의 티가 안 나고, 알아볼 수 있는 형체는 전부 위상을 준 쪽에서 왔다.
이미지의 구조 정보는 진폭이 아니라 위상에 산다. 무엇을 얼마나 섞었느냐보다, 그것들을 어디에 정렬했느냐가 그림을 그린다.
이 결과는 직관을 뒤집는다. 스펙트럼 그림에서 눈에 보이는 밝은 점은 전부 진폭이다. 정작 이미지의 정체를 쥔 위상은 그림으로는 잘 드러나지도 않는다. 우리가 스펙트럼을 볼 때 화려한 진폭에 눈을 뺏기지만, 형체를 붙들고 있는 손은 조용한 위상 쪽이다.
스펙트럼 문해력이 닿는 곳: JPEG부터 MRI까지
스펙트럼을 읽고 쓸 줄 알면, 이미지를 손보는 일이 곧 스펙트럼의 특정 자리를 지우거나 남기는 일이 된다. 중심의 원형만 남기고 바깥을 지우면(저역 통과) 디테일이 사라지고 큰 형태만 남아 흐릿해진다. 반대로 중심을 지우고 바깥만 남기면(고역 통과) 매끈한 면은 사라지고 경계선만 뼈대처럼 튀어나온다.
그림 4가 그 두 필터다. 흐림 필터와 엣지 검출은 사실 스펙트럼의 다른 쪽을 지우는 같은 동작이었다. 포토샵의 블러 슬라이더는 이 저역 통과 원의 반지름을 조절하는 이퀄라이저 손잡이인 셈이다.
같은 문해력이 훨씬 멀리까지 닿는다. JPEG는 이미지를 8×8 조각으로 나눠 이산 코사인 변환(DCT)으로 스펙트럼을 구한 뒤, 앞서 본 $1/f^2$ 기울기를 믿고 고주파 계수를 과감히 버린다. 모아레 무늬나 규칙적인 노이즈는 스펙트럼에서 몇 개의 튀는 점으로 뭉치므로, 그 점만 눌러 지우면 원본을 거의 건드리지 않고 잡음만 걷어낼 수 있다.
JPEG가 고주파를 과감히 버려도 사진이 멀쩡해 보이는 건 두 가지가 겹친 덕이다. 하나는 방금 본 $1/f^2$ — 애초에 고주파엔 에너지가 적다. 다른 하나는 사람 눈이 밝기의 미세한 고주파 변화에 둔감하다는 시각 특성이다. 버려도 티가 안 나는 것부터 버리는 게 압축의 핵심이다.
가장 놀라운 착지는 촬영 그 자체에 있다. 자기공명영상(MRI)은 이미지를 먼저 찍고 스펙트럼을 구하는 게 아니라, 처음부터 주파수 공간(k-space)에서 데이터를 한 점씩 측정한다. 스펙트럼을 직접 채운 다음, 역변환을 돌려 비로소 우리가 보는 단면 영상을 만든다. 천문 간섭계도 여러 망원경이 받은 신호로 하늘의 스펙트럼을 채우고 역변환해 영상을 얻는다.
주파수 공간에서 먼저 찍고 나중에 되돌리는 기계가, 병원 복도에 실재한다. 이쯤 오면 스펙트럼을 픽셀 격자의 그림자쯤으로 여기던 감각이 뒤집힌다. 스펙트럼은 단순한 분석 도구가 아니라 이미지가 놓일 수 있는 또 하나의 좌표계였던 것이다.
더 읽기
- A. V. Oppenheim, J. S. Lim, "The Importance of Phase in Signals," Proceedings of the IEEE, 69(5), 1981. — 위상이 이미지 구조를 지배한다는 스왑 실험의 원전.
- D. J. Field, "Relations between the statistics of natural images and the response properties of cortical cells," Journal of the Optical Society of America A, 4(12), 1987. — 자연 이미지의 $1/f^2$ 통계.
- R. C. Gonzalez, R. E. Woods, Digital Image Processing (4th ed.), 2018. — 2D DFT·주파수 영역 필터링의 표준 교과서.