반응형

JPEG 포맷은 표준안이 나온지 30년이 되어가지만, 여전히 널리 사용되는 포맷이다.

심지어, 차세대 JPEG을 표방하는 코덱이 좀 나왔었는데, 다 나가떨어질 때까지 JPEG는 버티고 있다.

물론, 영상을 전문으로 하시는 분들께는 그냥 한물 간 포맷이겠지만, 현실세계에선 그렇지 않다.

 

JPEG는 압축률이 꽤 뛰어나다는 장점이 있지만, artifacts라 흔히 통칭되는 노이즈가 가장 큰 약점[각주:1]이다.

그리고, 나온지 오래된 포맷답게 이 artifacts를 없애는 방법들이 꽤 검토되었고, 대표적으로 다음 두 가지 방식이 있다.

 

1. 이미지 자체에서 artifacts로 인식되는 영역 제거

가장 손쉽게 접근한 방식은 파일을 읽은 뒤에 각 픽셀을 인접 픽셀들과 비교하는 것이다.

Paint.NET의 플러그인 중 하나인 JPGNoiseReduction이 대표적이다.

 

대략 아래와 같은 코드[각주:2]로 설명할 수 있는데, 요지는 주변의 ±5 픽셀들과 모두 비교해서 유사한 색이면 평균을 계산하는 것.

 

ColorBgra color0 = src[x, y];

int count = 0;
double vR = 0;
double vG = 0;
double vB = 0;
for (int y2 = y - 5; y2 < y + 6; ++y2)
{
	for (int x2 = x - 5; x2 < x + 6; ++x2)
	{
		ColorBgra colorT = src[x2, y2];

		double yR = 0.299 * (colorT.R - color0.R);
		double yG = 0.587 * (colorT.G - color0.G);
		double yB = 0.114 * (colorT.B - color0.B);
		if (yR * yR + yG * yG + yB * yB <= (amount * 10))
		{
			vR += colorT.R;
			vG += colorT.G;
			vB += colorT.B;
			++count;
		}
	}
}
color0.R = (byte)(vR / count);
color0.G = (byte)(vG / count);
color0.B = (byte)(vB / count);

dst[x, y] = color0;

 

실제로 돌려본 결과는 아래와 같다.

 

우선 작업할 이미지를 하나 고른다.

항간에 떠도는 이미지를 하나 선택했다.

아무래도 artifacts를 비교하는 것이라 실사 이미지보다는 복잡한 인공 이미지가 더 적합하다.

 

 

이 이미지의 특정 영역을 4배 확대하면 아래와 같다.

복잡한 영역이라 artifacts가 눈에 크게 띈다.

 

 

이 플러그인을 적용한 결과는 아래와 같다.

 

이미지 중간 쪽에는 노이즈가 좀 남아있긴 함

 

지글거리는 영역이 상당부분 제거됐다는 것을 볼 수 있다.

알고리즘 자체는 그리 복잡하지 않지만, 결과는 강력하다.

 

2. JPEG를 읽으면서 사라진 DCT 계수를 복원

JPEG의 압축 원리는 간단히 말해 이미지를 8x8 블록으로 자른 뒤 DCT 변환 후 양자화[각주:3]하는 것이다.

이 과정에서 계수를 제거함으로써 파일의 크기를 줄이는 것.

 

이렇게 제거된 계수를 양자화 테이블을 기반으로 복원하는 JPEG Quant Smooth라는 알고리즘이 있다.

 

적용 방법은 간단[각주:4]하다.

libjpeg에서 파일을 읽으면서 기존의 jpeg_start_decompress() 함수 대신 jpegqs_start_decompress() 함수를 적용하는 것.

나머지 함수들[각주:5]은 기존과 동일하게 호출하면 된다.

 

이 알고리즘을 기본값(iteration = 3 등)으로 적용한 결과는 아래와 같다.

 

이미지 중간의 노이즈가 없어졌고, 하단 부분 복원된 형태가 상당히 다름

 

위의 1번과 비교해보면 복원되는 결과가 상당히 다르다는 것을 볼 수 있다.

 

3. 위의 두 알고리즘을 동시에 적용

이 두 알고리즘은 적용되는 단계가 다르기 때문에 둘을 동시에 적용하는 것에 큰 문제는 없다.

그런데, 이러한 복원은 복원과 동시에 어떤 부분의 데이터는 손실된다는 점을 고려해야 한다.

 

일단 위의 이미지에 둘을 모두 적용한 결과는 아래와 같다.

 

 

이 이미지에 한정해서 생각하면, 복원 결과는 상당히 훌륭하다.

하지만, 다양한 이미지들에 놓고 테스트를 해보면 그때그때 다를 것이라 생각해야 한다.

 

 

  1. 물론, 압축률을 올리면 노이즈 뿐만 아니라 전체적으로 뭉개지는 특성이 있음 [본문으로]
  2. C#으로 작성된 코드인데, 의사 코드 정도로 이해해도 무방함 [본문으로]
  3. 물론, 앞뒤의 많은 과정이 생략됨 [본문으로]
  4. 언제나 그렇듯 이게 실제로 간단한 적은 없음 [본문으로]
  5. jpeg_create_decompress(), jpeg_stdio_src(), jpeg_read_header() 등등 [본문으로]
반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band