본문으로 바로가기

이미지 품질 측정_PSNR

category Domain/Computer Vision 2021. 3. 5. 17:21

이미지 축소 시,

이미지 축소로 인한 어느정도 소실은 발생하며 사용한 보간법에 따라 그 정도의 크기가 다름

육안으로 식별이 안되지만 수치적으로 비교해봤을 때, 어느정도 차이가 있음

 

해당 포스트에서는 파이썬 Pillow 라이브러리를 사용해 이미지 축소 시 보간법마다의 소실 정도를 확인

- 정량적 : PSNR(이미지 품질 평가 방법 중 하나) 를 사용한 수치 비교

    * 육안으로 식별 불가능한 경우에 사용

- 정성적 : 축소된 이미지 간 차이 비교

 

 

# 보간법 (Interpolation)

 

원본 이미지의 주변 픽셀값을 이용해 그 사이에 있는 픽셀값을 예측하는 방법

 

 

# 사용한 보간법 종류

1. Nearest

2. Lanczos

3. Bilinear

4. Box

5. Hamming

6. Bicubic

 

* 이미지 보간법에 대해서는 추후 예정

* 원리 이해 부족

 

 

# PSNR (Peak Signal-to-Noise Ratio)

최대 신호 대 잡음비

이미지 품질 평가 방법 중 하나

- 품질이 좋은 이미지 : 큰 psnr 값을 가짐

- 품질이 나쁜 이미지 : 작은 psnr 값을 가짐

 

> 개념

신호가 가질 수 있는 최대 신호에 대한 잡음의 비

압축된 이미지의 화질에 대한 손실 정보를 평가하기 위한 목적으로 사용

 

SRCNN 모델에서 출력된 이미지 Evaluation 하는 과정에서 사용

* SRCNN(Super Resolution CNN) : 저품질(blur image)  Patch 이미지를 입력으로 고품질 이미지를 출력하는 딥러닝 알고리즘 

 

> 단위

db(log scale),  데시벨

 

> 계산식

PSNR = 20 * log_10 ( MAX_f / 루트(MSE) )

출처 : 위키백과

 

> 적용

원본 이미지와 압축(축소) 이미지 사이의 품질 측정

 

> 단점

수치 평가 결과와 사람이 느끼는 결과가 다르게 보일순 있음

보완 : PSNR-HVS, SSIM, VIF 등의 다른 metric를 사용

 

 

# 원본 이미지

0 ~255 픽셀을 나타내는 Grayscale 이미지를 사용

* Pixabay 에서 가져온 풍차 이미지 사용

640 x 425, windmill

 

 

# 보간법에 따른 이미지 축소 & 저장

from PIL import Image

# resize 할 이미지 사이즈 
img_size = 300

# Nearest
img_resize_nearest = img.resize((img_size, img_size), Image.NEAREST).convert("L")
img_resize_nearest.save('/gdrive/MyDrive/Colab/datasets/test/re_nearest.jpg')

# Lanczos
img_resize_lanczos = img.resize((img_size, img_size), Image.LANCZOS).convert("L")
img_resize_lanczos.save('/gdrive/MyDrive/Colab/datasets/test/re_lanczos.jpg')

# Bilinear
img_resize_bilinear = img.resize((img_size, img_size), Image.BILINEAR).convert("L")
img_resize_bilinear.save('/gdrive/MyDrive/Colab/datasets/test/re_bilinear.jpg')

# Box
img_resize_box = img.resize((img_size, img_size), Image.BOX).convert("L")
img_resize_box.save('/gdrive/MyDrive/Colab/datasets/test/re_box.jpg')

# Hamming
img_resize_hamming = img.resize((img_size, img_size), Image.HAMMING).convert("L")
img_resize_hamming.save('/gdrive/MyDrive/Colab/datasets/test/re_hamming.jpg')

# Bicubic
img_resize_bicubic = img.resize((img_size, img_size), Image.BICUBIC).convert("L")
img_resize_bicubic.save('/gdrive/MyDrive/Colab/datasets/test/re_bicubic.jpg')

* Pillow (Python Imaging Library): 이미지 처리에 대한 기능을 제공하는 라이브러리,  PIL

 

 

# PSNR 함수 구현

# 최대 신호 대 잡음비
def psnr(ori_img, con_img):
  """
  
  @params ori_img: 원본 이미지
  @params con_img: 비교 대상 이미지
  """
  
  # 해당 이미지의 최대값 (채널 최대값 - 최솟값)
  max_pixel = 255.0

  # MSE 계산
  mse = np.mean((ori_img - con_img)**2)

  if mse ==0:
    return 100
  
  # PSNR 계산
  psnr = 20* math.log10(max_pixel / math.sqrt(mse))
  
  return psnr

 

 

# 이미지 확대

PSNR을 적용하기 위해서, 이미지 간의 사이즈가 같아야 함

 

일종의 야매방법으로,

축소에 사용한 보간법으로 다시 원본 이미지 크기에 맞게 확대함

* 좋은 방법이 있으면 그 방법으로 하면 됨

ex. 원본이미지 -> (Nearest 보간법) -> 축소된 이미지 -> (Nearest 보간법) -> 확대된 이미지

# 이미지 확대
#     - PSNR 이미지 비교를 위해 원본 사이즈로 이미지 확대 (축소때 사용한 보간법 그대로 적용)

img_nearest = img_resize_nearest.resize((w, h), Image.NEAREST)
img_nearest.save('/gdrive/MyDrive/Colab/datasets/test/nearest.jpg')

img_lanczos = img_resize_lanczos.resize((w, h), Image.LANCZOS)
img_lanczos.save('/gdrive/MyDrive/Colab/datasets/test/lanczos.jpg')

img_bilinear = img_resize_bilinear.resize((w, h), Image.BILINEAR)
img_bilinear.save('/gdrive/MyDrive/Colab/datasets/test/bilinear.jpg')

img_box = img_resize_box.resize((w, h), Image.BOX)
img_box.save('/gdrive/MyDrive/Colab/datasets/test/box.jpg')

img_hamming = img_resize_hamming.resize((w, h), Image.HAMMING)
img_hamming.save('/gdrive/MyDrive/Colab/datasets/test/hamming.jpg')

img_bicubic = img_resize_bicubic.resize((w, h), Image.BICUBIC)
img_bicubic.save('/gdrive/MyDrive/Colab/datasets/test/bicubic.jpg')

 

+ Image.fromarray(array_img) : 픽셀 이미지 -> PIL 타입의 Image

+ np.array(PIL_type_img) : PIL 타입의 Image -> 픽셀 이미지

PSNR 계산 시, pil_type_image 는 안됨*

# 원 사이즈 -> (보간법 적용된) 축소된 이미지 -> 원 사이즈로 확대 (축소에 사용한 보간법과 동일한 보간법 사용)
# PIL 타입 변경

origin_img = cv2.imread('/gdrive/MyDrive/Colab/datasets/test/origin_img.jpg')
nearest_img = cv2.imread('/gdrive/MyDrive/Colab/datasets/test/nearest.jpg')
lanczos_img = cv2.imread('/gdrive/MyDrive/Colab/datasets/test/lanczos.jpg')
bilinear_img = cv2.imread('/gdrive/MyDrive/Colab/datasets/test/bilinear.jpg')
box_img = cv2.imread('/gdrive/MyDrive/Colab/datasets/test/box.jpg')
bicubic_img = cv2.imread('/gdrive/MyDrive/Colab/datasets/test/bicubic.jpg')
hamming_img = cv2.imread('/gdrive/MyDrive/Colab/datasets/test/hamming.jpg')

> 확대된 이미지 확인

 

 

# PSNR 결과 출력

PSNR(원본 이미지, 보간법 이미지)

# PSNR 결과 출력 (클수록 원본이미지와 품질 근사함)
print("Nearest : ", psnr(origin_img, nearest_img))
print("Bicubic : ", psnr(origin_img, bicubic_img))
print("Bilinear : ", psnr(origin_img, bilinear_img))
print("Box : ", psnr(origin_img, box_img))
print("Lanzos : ", psnr(origin_img, lanczos_img))
print("Hamming : ", psnr(origin_img, hamming_img))

 

> 수치 비교

원본 이미지와 보간법 적용된 이미지 간 품질 평가 결과,

Nearest Neighbor 보간법이 품질이 높게 나옴

PSNR 결과

 

> 이미지

원본
Bicubic
Bilinear
Box
Lanczos
Nearest Neighbor

 

# 정리

이미지를 축소/확대 시, 발생할 수있는 손실을 확인 하기 위해서 이미지 품질 평가 방법 중 하나인 PSNR을 사용

단, PSNR 수행 시 두 이미지의 사이즈가 같아야하기 때문에 똑같은 보간법으로 축소/확대를 사용해서 비교 수행

 

# 결론

PSNR 식 자체에 대해서는 문제없다고 생각

보간법을 두번 사용(축소/확대)한 것에 대해서 PSNR을 수행했기 때문에 정확한 이미지 품질 평가 결과라고도 할 수 없음