이산 코사인 변환
DCT 정의
이산 코사인 변환(DCT)은 영상을 다양한 크기 및 주파수를 갖는 정현파의 합으로 표현합니다. dct2
함수는 영상의 2차원 이산 코사인 변환(DCT)을 계산합니다. 일반적인 영상에 DCT를 적용하는 경우를 보면 시각적으로 의미있는 영상 정보의 대부분이 단 몇 개의 DCT 계수에 집중된다는 특징이 있습니다. 이러한 이유로 영상 압축 응용 분야에서는 DCT를 자주 사용합니다. 예를 들어, JPEG라는 국제 표준 손실 영상 압축 알고리즘의 중심에는 DCT가 있습니다. (JPEG는 이 표준을 개발한 단체인 Joint Photographic Experts Group의 줄임말로 만든 이름입니다.)
M×N 행렬 A
의 2차원 DCT는 다음과 같이 정의됩니다.
값 Bpq는 A
의 DCT 계수입니다. (MATLAB®의 행렬 인덱스는 항상 0이 아닌 1에서 시작하므로 MATLAB 행렬 요소 A(1,1)
과 B(1,1)
은 각각 수학적 수량 A00과 B00에 대응됩니다.)
DCT는 가역 변환이며, 역변환은 다음과 같이 표현됩니다.
역 DCT 방정식은 임의의 M×N 행렬 A
가 다음과 같은 형태를 갖는 MN 함수의 합으로 표현될 수 있음을 의미하는 것으로 해석될 수 있습니다.
이러한 함수를 DCT의 기저 함수라고 합니다. DCT 계수 Bpq는 각 기저 함수에 적용되는 가중치라고 생각할 수 있습니다. 다음 그림은 8×8 행렬에 대한 64개의 기저 함수를 보여줍니다.
8×8 행렬에 대한 64개의 기저 함수
가로 주파수는 왼쪽에서 오른쪽으로 증가하고, 세로 주파수는 위에서 아래로 증가합니다. 왼쪽 상단에 있는 상수 값 기저 함수를 DC 기저 함수라 하며, 이에 대응하는 DCT 계수 B00을 DC 계수라고 합니다.
DCT 변환 행렬
Image Processing Toolbox™를 사용하여 DCT를 계산하는 방법에는 두 가지가 있습니다. 첫 번째 방법은 dct2
함수를 사용하는 것입니다. dct2
는 입력값이 클 때 빠르게 계산하기 위해 FFT 기반 알고리즘을 사용합니다. 두 번째 방법은 DCT 변환 행렬을 사용하는 것입니다. DCT 변환 행렬은 함수 dctmtx
에서 반환하며, 8×8, 16×16과 같이 작은 정사각 입력값의 경우 더 효율적일 수 있습니다. M×M 변환 행렬 T
는 다음과 같이 표현됩니다.
M×M 행렬 A
에서 T*A
는 각 열이 A
열의 1차원 DCT를 포함하는 M×M 행렬입니다. A
의 2차원 DCT는 B=T*A*T'
로 계산할 수 있습니다. T
는 실수 정규 직교 행렬이므로 그 역은 전치와 같습니다. 따라서 B
의 2차원 역 DCT는 T'*B*T
로 표현됩니다.
이산 코사인 변환을 사용한 영상 압축
이 예제에서는 이산 코사인 변환(DCT)을 사용하여 영상을 압축하는 방법을 보여줍니다. 이 예제에서는 입력 영상에서 8×8 블록의 2차원 DCT를 계산하고, 각 블록에서 64개의 DCT 계수 중 10개만 남기고 모두 버린 다음(0으로 설정), 각 블록의 2차원 역 DCT를 사용하여 영상을 복원합니다. 이 예제에서는 변환 행렬 계산 방법을 사용합니다.
DCT는 JPEG 영상 압축 알고리즘에서 사용됩니다. 입력 영상을 8×8 또는 16×16 블록으로 나눈 후에 각 블록에 대해 2차원 DCT를 계산합니다. 그런 다음 DCT 계수를 양자화하고 부호화하여 전달합니다. JPEG 수신기(또는 JPEG 파일 판독기)는 양자화된 DCT 계수를 복호화하고, 각 블록의 역 2차원 DCT를 계산한 다음, 이 블록들을 다시 합쳐 하나의 영상으로 만듭니다. 일반적인 영상은 대부분의 DCT 계수가 0에 가까운 값을 갖습니다. 이러한 계수는 버려도 복원된 영상의 품질에 심각한 영향을 주지 않습니다.
영상을 작업 공간으로 읽어 들인 후 double
형 클래스로 변환합니다.
I = imread('cameraman.tif');
I = im2double(I);
영상에서 8×8 블록 단위로 2차원 DCT를 계산합니다. 함수 dctmtx
에서 N×N DCT 변환 행렬을 반환합니다.
T = dctmtx(8); dct = @(block_struct) T * block_struct.data * T'; B = blockproc(I,[8 8],dct);
각 블록에서 64개의 DCT 계수 중 10개만 남기고 모두 버립니다.
mask = [1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]; B2 = blockproc(B,[8 8],@(block_struct) mask .* block_struct.data);
각 블록의 2차원 역 DCT를 사용하여 영상을 복원합니다.
invdct = @(block_struct) T' * block_struct.data * T; I2 = blockproc(B2,[8 8],invdct);
원본 영상과 복원 영상을 나란히 표시합니다. 복원된 영상에서 어느 정도의 품질 저하가 발생하긴 하지만 DCT 계수의 85% 정도를 버렸음에도 불구하고 영상을 분명히 알아볼 수 있습니다.
imshow(I)
figure imshow(I2)