SSIM for color
by DINHO
오늘은 SSIM(Structural Similarity Index Measure)에 대해서 이야기 해보겠습니다. SSIM은 디지털 TV, 사진, 비디오 등의 인지된 품질을 예측하는 방법입니다. 이 방법은 두 이미지 간의 유사성을 측정하는 데에도 사용돼서 생성형 AI에서는 원본 이미지와 생성 이미지를 비교하기 위해 SSIM을 평가지표로 사용하기도 합니다.
SSIM은 두 픽셀 값의 차이로 유사도를 계산합니다. 제가 검색해 봤을 때(저의 검색 실력이 안 좋은 건지 모르겠지만,,,) 컬러 이미지에 대한 SSIM 코드는 없더라고요… 흑백 이미지에 대한 SSIM 코드들은 많아서 이번에 직접 이론과 수식을 바탕으로 코드를 만들어 보았습니다.
SSIM의 주요 요소는 세 가지 입니다.
-
밝기(Luminance) : 두 이미지의 평균 밝기 비교
-
대비(Contrast) : 두 이미지의 대비 비교
-
구조(Structure) 두 이미지의 구조 비교
SSIM 계산은 아래와 같은 수식으로 이루어집니다.
\[\text{SSIM}(x, y) = \frac{(2\mu_x \mu_y + C_1)(2\sigma_{xy} + C_2)}{(\mu_x^2 + \mu_y^2 + C_1)(\sigma_x^2 + \sigma_y^2 + C_2)}\]여기서,
- ( x )와 ( y )는 비교할 두 이미지의 창(window)입니다.
- ( \mu_x )와 ( \mu_y )는 각각 ( x )와 ( y )의 평균 밝기입니다.
- ( \sigma_x )와 ( \sigma_y )는 각각 ( x )와 ( y )의 표준 편차입니다.
- ( \sigma_{xy} )는 ( x )와 ( y )의 공분산입니다.
- ( C_1 )과 ( C_2 )는 안정화를 위한 상수입니다.
SSIM 값은 -1에서 1 사이의 값을 가지며, 1에 가까울수록 두 이미지가 더 유사함을 의미합니다. 일반적으로 SSIM 값이 0.9 이상이면 두 이미지가 거의 동일하다고 간주됩니다.
SSIM을 컬러 이미지에 적용하려면 각 색상 채널, 즉, RGB채널에 대한 SSIM을 각각 계산하고 평균을 구해주면 됩니다. 수식은 아래와 같습니다.
\[\text{SSIM}_{r}(R_{1}, R_{2}), \text{SSIM}_{r}(G_{1}, G_{2}), \text{SSIM}_{r}(B_{1}, B_{2}),\] \[\text{SSIM}_{rgb} = \frac{1}{3} \text{SSIM}_{r} + \frac{1}{3} \text{SSIM}_{g} + \frac{1}{3} \text{SSIM}_{b}\]이 수식을 Python코드와 함께 SSIM을 적용해보겠습니다.
아래 코드는 제가 캡스톤 디자인을 진행하면서 구성한 코드입니다. img1은 Ground Truth 멜-스펙트로그램 이미지이고 img2,3,4와 ssim을 비교하여 어떤 GAN 모델이 멜-스펙트로그램을 잘 복원했는지를 평가하기 위해 아래 코드를 작성했습니다. MSE 계산도 들어가 있지만 무시하시면 됩니다.
import numpy as np
import matplotlib.pyplot as plt
import imageio.v2 as imageio
from skimage import img_as_float
from skimage.metrics import structural_similarity as ssim
from skimage.metrics import mean_squared_error
import os
# 파일 경로 수정
path1 = os.path.expanduser('C:\\capstone\\test4_origin.wav_mel_spectrogram.png')
path2 = os.path.expanduser('C:\\capstone\\test4_msdmpd_converted_generated.wav_mel_spectrogram.png')
path3 = os.path.expanduser('C:\\capstone\\test4_medmpdsnake_converted_generated.wav_mel_spectrogram.png')
path4 = os.path.expanduser('C:\\capstone\\test4_mrdmpd_converted_generated.wav_mel_spectrogram.png')
# 이미지 로드
img1 = img_as_float(imageio.imread(path1))
img2 = img_as_float(imageio.imread(path2))
img3 = img_as_float(imageio.imread(path3))
img4 = img_as_float(imageio.imread(path4))
# 이미지 크기 조정
min_rows = min(img1.shape[0], img2.shape[0], img3.shape[0], img4.shape[0])
min_cols = min(img1.shape[1], img2.shape[1], img3.shape[1], img4.shape[1])
img1 = img1[:min_rows, :min_cols]
img2 = img2[:min_rows, :min_cols]
img3 = img3[:min_rows, :min_cols]
img4 = img4[:min_rows, :min_cols]
# win_size 선택
win_size = min(3, min_rows, min_cols) if min(min_rows, min_cols) >= 3 else 1
# SSIM과 MSE 계산
def calculate_metrics(imgA, imgB):
ssim_total = 0
mse_total = 0
for i in range(3): # RGB 채널을 순회
ssim_val = ssim(imgA[:,:,i], imgB[:,:,i], win_size=win_size, data_range=imgB[:,:,i].max() - imgB[:,:,i].min())
mse_val = mean_squared_error(imgA[:,:,i], imgB[:,:,i])
ssim_total += ssim_val
mse_total += mse_val
return ssim_total / 3, mse_total / 3 # 평균값 반환
ssim12, mse12 = calculate_metrics(img1, img2)
ssim13, mse13 = calculate_metrics(img1, img3)
ssim14, mse14 = calculate_metrics(img1, img4)
# 시각화
fig, axes = plt.subplots(nrows=1, ncols=4, figsize=(20, 4), sharex=True, sharey=True)
ax = axes.ravel()
ax[0].imshow(img1)
ax[0].set_xlabel('Original Image')
ax[0].set_title('original')
ax[1].imshow(img2)
ax[1].set_xlabel(f'MSE: {mse12:.2f}, SSIM: {ssim12:.2f}')
ax[1].set_title('msdmpd')
ax[2].imshow(img3)
ax[2].set_xlabel(f'MSE: {mse13:.2f}, SSIM: {ssim13:.2f}')
ax[2].set_title('medmpdsnake')
ax[3].imshow(img4)
ax[3].set_xlabel(f'MSE: {mse14:.2f}, SSIM: {ssim14:.2f}')
ax[3].set_title('mrdmpd')
plt.tight_layout()
plt.show()
이상으로 SSIM 포스팅을 마치겠습니다. 감사합니다😁😁
Follow my github