Search
Duplicate
3️⃣

영상 디스플레이의 기초 [2021/02/08~2021/02/15]

영상에서 화질을 결정하는 두 가지 요소

공간 해상도
양자화

공간 해상도 (spatial resolution)

영상에 대한 화소들의 밀도를 공간 해상도라고 한다.

샘플링 (Sampling)

python 에서는 cv2.resize 를 통해 이미지의 공간 해상도를 변경할 수 있다. 위 사진에서는, N by N 이미지를 N/2 by N/2 이미지로 공간 해상도를 줄이고, 이를 다시 N by N 이미지로 공간 해상도를 다시 늘렸다.
입력 영상과 최종 영상의 크기는 같지만, 정보의 양이 다르고, 실제적인 해상도가 다르다. 이러한 실제적인 해상도를 effective resolution 이라고 한다.

블록화 / 화소화 (pixelization)

샘플링을 더 적게 하게 되면 블록화(화소화, pixelization) 현상이 나타나게 된다.

양자화 (quantization)

영상의 밝기 (intensity) 를 표현하는 데 사용되는 밝기값의 개수를 정하고 표현하는 것을 양자화라고 한다.
기본 영상은 256개의 ( = uint8 = 2^8 ) 개의 숫자로 양자화한다. 상황에 따라 256개보다 적은 수의 밝기값으로 양자화할 필요가 있다.

균일 양자화 (uniform quantization)

밝기값의 범위를 균등하게 나누어 양자화하는 것을 균일 양자화 (Uniform quantization) 라고 한다.
이렇듯, 균일 양자화를 하면, 원 영상에서는 존재한다고 느끼지 못하는 "거짓 윤곽" 이 나타날 수 있다. 이것은 양자화가 더 심하게 될수록 더 극단적으로 나타날 수밖에 없다.

디더링 (Dithering)

디더링 (dithering) 은 quantization 을 하면서도 영상의 quality 를 떨어뜨리지 않는, 컬러의 수 축소 방법이다.
halftoning 은 디더링 (dithering) 의 한 형태로, 영상을 두 가지 톤 (tone) 으로 표현하는 것을 의미한다.
특히, halftoning 은 dithering 의 극단적인 경우로, 영상의 밝기값을 0, 1 로만 양자화해야 한다. 하지만 균일한 양자화는 앞서 보았듯 거짓 윤곽이 정말 많이 나타난다. 이를 해결하는 방법을 알아보자.
우선, 패턴 처리를 활용한 방법이다. 위 그림처럼, 하나의 화소가 아닌 영역의 밝기에 따라 흑과 백 두 톤의 픽셀비율을 조절하는 방법을 상상할 수 있다.
강의에서는 이것을 달성하기 위한 방법들 중, 아주 간단한 방법을 소개한다고 한다. 강의에서 소개한 방법은 dithering matrix 을 통한 방법이다.
갑자기 행렬이 나와서 당황스러울 수 있지만, 결국 그냥 네 픽셀과 행렬의 네 요소를 비교해서 크면 1, 작으면 0 을 그 위치에 대입하겠다는 것이다.
n = 4 dithering_4 = np.linspace(uint8_min, uint8_max, n).astype(np.uint8) print(dithering_4) dithering_4_mat = dithering_4.reshape([np.sqrt(n).astype(np.uint8), np.sqrt(n).astype(np.uint8)]) print(dithering_4_mat)
Python
복사
[ 0 85 170 255] [[ 0 85] [170 255]]
Python
복사
n = 4 dithering_4_mat = np.tile(dithering_4_mat, [h//np.sqrt(n).astype(np.uint8), w//np.sqrt(n).astype(np.uint8)]) print(dithering_4_mat.shape) dithering_4_im = (im > dithering_4_mat) plt.figure(121, figsize = [13, 8]) plt.imshow(dithering_4_im, cmap='gray') plt.show()
Python
복사
좋은 디더링 알고리즘을 사용하면 아래와 같이 더욱 디테일한 영상을 만들어 볼 수 있다.
이제 n-output grayscale dithering 을 해 보자.
dithering 의 한 형태인 halfolding 은 binary 형태로 나타내는 것을 의미하므로, 다음에 시도해볼 내용은 halfolding 이 아니기 때문에 0 과 1 만으로 이루어져 있지는 않다.
4-output grayscale dithering 은 다음과 같은 과정으로 이루어진다.
q(i,j)=floor(x(i,j)/85)q(i,j) = floor(x(i,j)/85)
이때, 85 라는 값은 85=ceil(255/(41)))85 = ceil(255 / (4-1))) 를 통해 도출된 값이다. 여기서 q(i,j)q(i,j) 까지는 uniform quantization 결과물과 별반 다를 것이 없다. 하지만 우리는 dithering 을 하고 있지 않은가.
final output dithering image qfinal\ output\ dithering\ image\ q
if x(i,j)85q(i,j)<d(i,j), p(i,j)=q(i,j)+1if\ x(i,j)-85q(i,j) < d(i,j),\ p(i,j) = q(i,j)+1
else p(i,j)=q(i,j)else\ p(i,j) = q(i,j)
왜 이게 가능할까지 아래 예시 이미지 x(i,j) 를 통해 해 보도록 하자.
n-output grayscale dithering 으로 일반화해 보자.
s=ceil(255/(n1))s=ceil(255/(n-1))
q(i,j)=floor(x(i,j)/s)q(i,j) = floor(x(i,j)/s)
final output dithering image qfinal\ output\ dithering\ image\ q
if x(i,j)q(i,j)s<d(i,j), p(i,j)=q(i,j)+1if\ x(i,j)-q(i,j)s < d(i,j),\ p(i,j) = q(i,j)+1
else p(i,j)=q(i,j)else\ p(i,j) = q(i,j)
# 4-scale dithering n = 4 s = np.ceil(uint8_max / (n-1)) print(s) dithering_4 = np.linspace(uint8_min, s, n).astype(np.uint8) print(dithering_4) dithering_4_mat = dithering_4.reshape([np.sqrt(n).astype(np.uint8), np.sqrt(n).astype(np.uint8)]) print(dithering_4_mat) print('---') dithering_4_mat = np.tile(dithering_4_mat, [h//np.sqrt(n).astype(np.uint8), w//np.sqrt(n).astype(np.uint8)]) print(dithering_4_mat.shape) dithering_4_im = np.floor(im / s) + (im > im - s * dithering_4_mat) plt.figure(131, figsize = [13, 8]) plt.imshow(dithering_4_im, cmap='gray') plt.show()
Python
복사