اگر تا اینجا اومدید قطعا میدونید SNR و PSNR تصویر چی هستن و به چه دردی میخورن! پس چی بهتر از اینکه بریم و اونها رو در پایتون محاسبه کنیم؟!
اول تفاوت SNR و PSNR رو بدونیم:
Signal to Noise Ratio:
It shows the relationship between the real image and estimated image. This ratio indicates how strong the noise corrupted the original image.Peak Signal to Noise Ratio:
In PSNR we are interested in signal peak. This is more content specific than pure SNR.Here we say how high intensity regions of the image come through the noise and paying much less attention to low intensity regions.
فرمولهای SNR و PSNR رو با هم ببینیم:
حالا که بخش ریاضی کار رو میدونیم کد نویسی ساده و شیرین میشه.
فقط یک نکتهی خیلی مهم داریم: وقتی تصویر رو در OpenCV میخونیم به شکل پیشفرض فرمت داده Uint-8 هست، یعنی اعداد در بازهی ۰ تا ۲۵۵ قرار دارن.
توی فرمولهای بالا ما باید مقدار پیکسلها رو به توان ۲ برسونیم پس اگر فرمت داده رو تغییر ندیم، اووپس! محاسباتمون اشتباه میشن:)
تابع محاسبه SNR:
def snr(img, ref): #convert imput images to float64 _img = np.float64(np.copy(img)) _ref = np.float64(np.copy(ref)) sum_img = np.sum((_img)**2) sum_noise = np.sum((_img - _ref)**2) if sum_noise == 0: return 100 return 10 * math.log10(sum_img / sum_noise)
تابع محاسبهی PSNR:
def psnr(img, ref): #convert imput images to float64 _img = np.float64(np.copy(img)) _ref = np.float64(np.copy(ref)) mse = np.mean((_img - _ref) ** 2) if mse == 0: return 100 PIXEL_MAX = 255.0 return 20 * math.log10(PIXEL_MAX / math.sqrt(mse))
کد کامل برنامه:
#!/usr/bin/env python3 # coding: utf-8 import cv2 import numpy as np import math def show_image_and_wait(title, image, resize_scale=None): if resize_scale: disp_img = cv2.resize(image, (0, 0), None, resize_scale, resize_scale) else: disp_img = image key = 0 while True: cv2.imshow(title, disp_img) key = cv2.waitKey(1) & 0xFF if key == 27: print('<ESC> pressed') break elif key == ord('q'): print('<q> pressed') break if cv2.getWindowProperty(title ,cv2.WND_PROP_VISIBLE) < 1: print('Close (X) button clicked') break cv2.destroyWindow(title) def concat_images(img1, img2, direction='H'): assert img1.shape == img2.shape , "Both images MUST be in same shape!" if direction == 'H': new_img = cv2.hconcat([img1, img2]) elif direction == 'V': new_img = cv2.vconcat([img1, img2]) else: print('Plese use [V] or [H] for direction') return new_img def snr(img, ref): #convert imput images to float64 _img = np.float64(np.copy(img)) _ref = np.float64(np.copy(ref)) sum_img = np.sum((_img)**2) sum_noise = np.sum((_img - _ref)**2) if sum_noise == 0: return 100 return 10 * math.log10(sum_img / sum_noise) def psnr(img, ref): #convert imput images to float64 _img = np.float64(np.copy(img)) _ref = np.float64(np.copy(ref)) mse = np.mean((_img - _ref) ** 2) if mse == 0: return 100 PIXEL_MAX = 255.0 return 20 * math.log10(PIXEL_MAX / math.sqrt(mse)) img_path = 'oggy.jpeg' img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED) if img is None: raise ValueError('Coud not open or find the image') noisy_img_path = "oggy_noise_10.jpg" noisy_img = cv2.imread(noisy_img_path, cv2.IMREAD_UNCHANGED) if noisy_img is None: raise ValueError('Coud not open or find the image') psnr_val = psnr(noisy_img, img) snr_val = snr(noisy_img, img) print('PSNR: {0}'.format(psnr_val)) print('SNR: {0}'.format(snr_val)) disp_img = noisy_img.copy() cv2.putText(disp_img,'SNR: {0: 4.5f}'.format(snr_val), (60,40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) cv2.putText(disp_img,'PSNR: {0: 4.5f}'.format(psnr_val), (60,80), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) show_image_and_wait('www.mh-salari.me/snr-and-psnr-in-python', disp_img, 0.5)
از نظر من نیازی به توضیح بیشتر نیست، اگر جایی از کد رو متوجه نشدید کامنت بذارید.
و در نهایت صحت سنجی خروجی توابع ما در کنار دستور psnr نرمافزار octave:
پ.ن:
در نوشتهی قبلی [+اینجا] یاد گرفتیم که چطور نویز گاوسی رو به تصویرمون اضافه کنیم، برای ایجاد این تصاویر نویزی از همون برنامهی قبلی استفاده کردم.
+اینجا در مورد تابعی که برای کنار هم قرار دادن تصاویر استفاده کردم توضیح دادم.
منابع:
http://bigwww.epfl.ch/sage/soft/snr/
https://octave.sourceforge.io/image/function/psnr.html
https://dsp.stackexchange.com/questions/11326/difference-between-snr-and-psnr
نویسنده: محمد حسین سالاری