압축 알고리즘(Compression Algorithm)

JPEG 압축 (DCT 기반 압축)

임베디드 친구 2025. 3. 12. 09:19
728x90
반응형

JPEG 압축 (DCT 기반 압축)

1. JPEG 압축 개요

JPEG(Joint Photographic Experts Group) 압축은 디지털 이미지 데이터를 효율적으로 저장하고 전송하기 위해 널리 사용되는 손실 압축 방식입니다. 이 압축 방식은 사람이 시각적으로 인식하기 어려운 정보를 제거하여 높은 압축률을 달성할 수 있도록 설계되었습니다. JPEG 압축은 주로 DCT(Discrete Cosine Transform, 이산 코사인 변환)를 기반으로 작동하며, 이를 통해 이미지 데이터를 주파수 영역으로 변환하여 저주파 성분을 보존하고 고주파 성분을 제거합니다.

2. JPEG 압축 과정

JPEG 압축 과정은 다음과 같은 주요 단계로 이루어집니다.

  1. 색 공간 변환 (Color Space Conversion)

    • RGB 색 공간을 YCbCr 색 공간으로 변환합니다. 이 과정에서 밝기 성분(Y)과 색차 성분(Cb, Cr)으로 분리됩니다.
  2. 서브샘플링 (Chroma Subsampling)

    • 사람의 시각적 특성을 이용하여 색차 성분(Cb, Cr)의 해상도를 낮춥니다. 일반적으로 4:2:2 또는 4:2:0 방식이 사용됩니다.
  3. 블록 분할 (Block Splitting)

    • 이미지를 8x8 크기의 블록으로 나눕니다. 각 블록은 독립적으로 처리됩니다.
  4. DCT 변환 (Discrete Cosine Transform)

    • 각 8x8 블록에 대해 DCT를 수행하여 주파수 영역으로 변환합니다. 이 과정에서 저주파 성분이 블록의 좌측 상단에 집중되고, 고주파 성분이 우측 하단으로 배치됩니다.
  5. 양자화 (Quantization)

    • 인간의 시각적 특성을 고려하여 DCT 변환 후 얻어진 주파수 계수를 양자화합니다. 높은 주파수 성분을 더 큰 값으로 나누어 정보 손실을 유도하며, 이를 통해 데이터의 크기를 줄입니다.
  6. 엔트로피 부호화 (Entropy Encoding)

    • 양자화된 값을 런렝스 인코딩(RLE) 및 허프만 부호화를 적용하여 압축합니다.
  7. 압축 데이터 저장

    • 최종적으로 압축된 데이터를 JPEG 파일 포맷에 맞게 저장합니다.

3. 손실 압축의 품질과 압축률 조정

JPEG 압축에서 품질과 압축률은 양자화 과정에서 결정됩니다. 양자화 테이블을 조정함으로써 압축률과 화질 간의 균형을 조절할 수 있습니다.

  • 높은 품질(낮은 압축률): 원본 이미지와 유사한 품질을 유지하면서 파일 크기가 상대적으로 큽니다.
  • 낮은 품질(높은 압축률): 파일 크기는 작아지지만, 블록 아티팩트 및 디테일 손실이 발생할 수 있습니다.

양자화 테이블을 조정하여 특정 응용에 적합한 압축률과 품질을 선택할 수 있습니다. 예를 들어, 고품질 이미지를 요구하는 경우 저주파 성분의 손실을 최소화하도록 조정할 수 있으며, 웹 페이지에서 빠른 로딩이 필요한 경우 압축률을 높여 파일 크기를 줄일 수 있습니다.

4. JPEG 압축 구현 예제

다음은 Java와 C를 사용하여 JPEG 압축을 구현하는 예제 코드입니다.

4.1 Java를 이용한 DCT 변환

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;

public class DCTCompression {
    private static final int BLOCK_SIZE = 8;

    public static double[][] applyDCT(double[][] block) {
        int N = BLOCK_SIZE;
        double[][] dct = new double[N][N];
        double cU, cV, sum;

        for (int u = 0; u < N; u++) {
            for (int v = 0; v < N; v++) {
                cU = (u == 0) ? 1 / Math.sqrt(2) : 1;
                cV = (v == 0) ? 1 / Math.sqrt(2) : 1;
                sum = 0.0;

                for (int x = 0; x < N; x++) {
                    for (int y = 0; y < N; y++) {
                        sum += block[x][y] *
                            Math.cos(((2 * x + 1) * u * Math.PI) / (2 * N)) *
                            Math.cos(((2 * y + 1) * v * Math.PI) / (2 * N));
                    }
                }
                dct[u][v] = 0.25 * cU * cV * sum;
            }
        }
        return dct;
    }
}

4.2 C를 이용한 DCT 변환

#include <stdio.h>
#include <math.h>

#define BLOCK_SIZE 8

void applyDCT(double block[BLOCK_SIZE][BLOCK_SIZE], double dct[BLOCK_SIZE][BLOCK_SIZE]) {
    int u, v, x, y;
    double cU, cV, sum;

    for (u = 0; u < BLOCK_SIZE; u++) {
        for (v = 0; v < BLOCK_SIZE; v++) {
            cU = (u == 0) ? 1 / sqrt(2) : 1;
            cV = (v == 0) ? 1 / sqrt(2) : 1;
            sum = 0.0;

            for (x = 0; x < BLOCK_SIZE; x++) {
                for (y = 0; y < BLOCK_SIZE; y++) {
                    sum += block[x][y] *
                        cos(((2 * x + 1) * u * M_PI) / (2 * BLOCK_SIZE)) *
                        cos(((2 * y + 1) * v * M_PI) / (2 * BLOCK_SIZE));
                }
            }
            dct[u][v] = 0.25 * cU * cV * sum;
        }
    }
}

int main() {
    double block[BLOCK_SIZE][BLOCK_SIZE] = { /* 8x8 pixel values */ };
    double dct[BLOCK_SIZE][BLOCK_SIZE];

    applyDCT(block, dct);

    return 0;
}

5. 결론

JPEG 압축은 DCT 변환을 기반으로 한 손실 압축 방식으로, 이미지의 저장 및 전송을 효율적으로 수행할 수 있도록 설계되었습니다. 품질과 압축률을 조정할 수 있으며, 다양한 응용에서 활용됩니다. 본문에서 소개한 Java와 C 코드 예제를 활용하여 JPEG 압축의 핵심 개념을 직접 구현해 볼 수 있습니다.

반응형