import numpy as np import cv2 import sklearn.metrics as skm from scipy.signal import convolve2d import math from skimage.metrics import structural_similarity as ssim def image_read_cv2(path, mode='RGB'): img_BGR = cv2.imread(path).astype('float32') assert mode == 'RGB' or mode == 'GRAY' or mode == 'YCrCb', 'mode error' if mode == 'RGB': img = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2RGB) elif mode == 'GRAY': img = np.round(cv2.cvtColor(img_BGR, cv2.COLOR_BGR2GRAY)) elif mode == 'YCrCb': img = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2YCrCb) return img class Evaluator(): @classmethod def input_check(cls, imgF, imgA=None, imgB=None): if imgA is None: assert type(imgF) == np.ndarray, 'type error' assert len(imgF.shape) == 2, 'dimension error' else: assert type(imgF) == type(imgA) == type(imgB) == np.ndarray, 'type error' assert imgF.shape == imgA.shape == imgB.shape, 'shape error' assert len(imgF.shape) == 2, 'dimension error' @classmethod def EN(cls, img): # entropy cls.input_check(img) a = np.uint8(np.round(img)).flatten() h = np.bincount(a) / a.shape[0] return -sum(h * np.log2(h + (h == 0))) @classmethod def SD(cls, img): cls.input_check(img) return np.std(img) @classmethod def SF(cls, img): cls.input_check(img) return np.sqrt(np.mean((img[:, 1:] - img[:, :-1]) ** 2) + np.mean((img[1:, :] - img[:-1, :]) ** 2)) @classmethod def AG(cls, img): # Average gradient cls.input_check(img) Gx, Gy = np.zeros_like(img), np.zeros_like(img) Gx[:, 0] = img[:, 1] - img[:, 0] Gx[:, -1] = img[:, -1] - img[:, -2] Gx[:, 1:-1] = (img[:, 2:] - img[:, :-2]) / 2 Gy[0, :] = img[1, :] - img[0, :] Gy[-1, :] = img[-1, :] - img[-2, :] Gy[1:-1, :] = (img[2:, :] - img[:-2, :]) / 2 return np.mean(np.sqrt((Gx ** 2 + Gy ** 2) / 2)) @classmethod def MI(cls, image_F, image_A, image_B): cls.input_check(image_F, image_A, image_B) return skm.mutual_info_score(image_F.flatten(), image_A.flatten()) + skm.mutual_info_score(image_F.flatten(), image_B.flatten()) @classmethod def MSE(cls, image_F, image_A, image_B): # MSE cls.input_check(image_F, image_A, image_B) return (np.mean((image_A - image_F) ** 2) + np.mean((image_B - image_F) ** 2)) / 2 @classmethod def CC(cls, image_F, image_A, image_B): cls.input_check(image_F, image_A, image_B) rAF = np.sum((image_A - np.mean(image_A)) * (image_F - np.mean(image_F))) / np.sqrt( (np.sum((image_A - np.mean(image_A)) ** 2)) * (np.sum((image_F - np.mean(image_F)) ** 2))) rBF = np.sum((image_B - np.mean(image_B)) * (image_F - np.mean(image_F))) / np.sqrt( (np.sum((image_B - np.mean(image_B)) ** 2)) * (np.sum((image_F - np.mean(image_F)) ** 2))) return (rAF + rBF) / 2 @classmethod def PSNR(cls, image_F, image_A, image_B): cls.input_check(image_F, image_A, image_B) return 10 * np.log10(np.max(image_F) ** 2 / cls.MSE(image_F, image_A, image_B)) @classmethod def SCD(cls, image_F, image_A, image_B): # The sum of the correlations of differences cls.input_check(image_F, image_A, image_B) imgF_A = image_F - image_A imgF_B = image_F - image_B corr1 = np.sum((image_A - np.mean(image_A)) * (imgF_B - np.mean(imgF_B))) / np.sqrt( (np.sum((image_A - np.mean(image_A)) ** 2)) * (np.sum((imgF_B - np.mean(imgF_B)) ** 2))) corr2 = np.sum((image_B - np.mean(image_B)) * (imgF_A - np.mean(imgF_A))) / np.sqrt( (np.sum((image_B - np.mean(image_B)) ** 2)) * (np.sum((imgF_A - np.mean(imgF_A)) ** 2))) return corr1 + corr2 @classmethod def VIFF(cls, image_F, image_A, image_B): cls.input_check(image_F, image_A, image_B) return cls.compare_viff(image_A, image_F)+cls.compare_viff(image_B, image_F) @classmethod def compare_viff(cls,ref, dist): # viff of a pair of pictures sigma_nsq = 2 eps = 1e-10 num = 0.0 den = 0.0 for scale in range(1, 5): N = 2 ** (4 - scale + 1) + 1 sd = N / 5.0 # Create a Gaussian kernel as MATLAB's m, n = [(ss - 1.) / 2. for ss in (N, N)] y, x = np.ogrid[-m:m + 1, -n:n + 1] h = np.exp(-(x * x + y * y) / (2. * sd * sd)) h[h < np.finfo(h.dtype).eps * h.max()] = 0 sumh = h.sum() if sumh != 0: win = h / sumh if scale > 1: ref = convolve2d(ref, np.rot90(win, 2), mode='valid') dist = convolve2d(dist, np.rot90(win, 2), mode='valid') ref = ref[::2, ::2] dist = dist[::2, ::2] mu1 = convolve2d(ref, np.rot90(win, 2), mode='valid') mu2 = convolve2d(dist, np.rot90(win, 2), mode='valid') mu1_sq = mu1 * mu1 mu2_sq = mu2 * mu2 mu1_mu2 = mu1 * mu2 sigma1_sq = convolve2d(ref * ref, np.rot90(win, 2), mode='valid') - mu1_sq sigma2_sq = convolve2d(dist * dist, np.rot90(win, 2), mode='valid') - mu2_sq sigma12 = convolve2d(ref * dist, np.rot90(win, 2), mode='valid') - mu1_mu2 sigma1_sq[sigma1_sq < 0] = 0 sigma2_sq[sigma2_sq < 0] = 0 g = sigma12 / (sigma1_sq + eps) sv_sq = sigma2_sq - g * sigma12 g[sigma1_sq < eps] = 0 sv_sq[sigma1_sq < eps] = sigma2_sq[sigma1_sq < eps] sigma1_sq[sigma1_sq < eps] = 0 g[sigma2_sq < eps] = 0 sv_sq[sigma2_sq < eps] = 0 sv_sq[g < 0] = sigma2_sq[g < 0] g[g < 0] = 0 sv_sq[sv_sq <= eps] = eps num += np.sum(np.log10(1 + g * g * sigma1_sq / (sv_sq + sigma_nsq))) den += np.sum(np.log10(1 + sigma1_sq / sigma_nsq)) vifp = num / den if np.isnan(vifp): return 1.0 else: return vifp @classmethod def Qabf(cls, image_F, image_A, image_B): cls.input_check(image_F, image_A, image_B) gA, aA = cls.Qabf_getArray(image_A) gB, aB = cls.Qabf_getArray(image_B) gF, aF = cls.Qabf_getArray(image_F) QAF = cls.Qabf_getQabf(aA, gA, aF, gF) QBF = cls.Qabf_getQabf(aB, gB, aF, gF) # 计算QABF deno = np.sum(gA + gB) nume = np.sum(np.multiply(QAF, gA) + np.multiply(QBF, gB)) return nume / deno @classmethod def Qabf_getArray(cls,img): # Sobel Operator Sobel h1 = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]]).astype(np.float32) h2 = np.array([[0, 1, 2], [-1, 0, 1], [-2, -1, 0]]).astype(np.float32) h3 = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]).astype(np.float32) SAx = convolve2d(img, h3, mode='same') SAy = convolve2d(img, h1, mode='same') gA = np.sqrt(np.multiply(SAx, SAx) + np.multiply(SAy, SAy)) aA = np.zeros_like(img) aA[SAx == 0] = math.pi / 2 aA[SAx != 0]=np.arctan(SAy[SAx != 0] / SAx[SAx != 0]) return gA, aA @classmethod def Qabf_getQabf(cls,aA, gA, aF, gF): L = 1 Tg = 0.9994 kg = -15 Dg = 0.5 Ta = 0.9879 ka = -22 Da = 0.8 GAF,AAF,QgAF,QaAF,QAF = np.zeros_like(aA),np.zeros_like(aA),np.zeros_like(aA),np.zeros_like(aA),np.zeros_like(aA) GAF[gA>gF]=gF[gA>gF]/gA[gA>gF] GAF[gA == gF] = gF[gA == gF] GAF[gA 1: refA = convolve2d(refA, np.rot90(win, 2), mode='valid') refB = convolve2d(refB, np.rot90(win, 2), mode='valid') dist = convolve2d(dist, np.rot90(win, 2), mode='valid') refA = refA[::2, ::2] refB = refB[::2, ::2] dist = dist[::2, ::2] mu1A = convolve2d(refA, np.rot90(win, 2), mode='valid') mu1B = convolve2d(refB, np.rot90(win, 2), mode='valid') mu2 = convolve2d(dist, np.rot90(win, 2), mode='valid') mu1_sq_A = mu1A * mu1A mu1_sq_B = mu1B * mu1B mu2_sq = mu2 * mu2 mu1A_mu2 = mu1A * mu2 mu1B_mu2 = mu1B * mu2 sigma1A_sq = convolve2d(refA * refA, np.rot90(win, 2), mode='valid') - mu1_sq_A sigma1B_sq = convolve2d(refB * refB, np.rot90(win, 2), mode='valid') - mu1_sq_B sigma2_sq = convolve2d(dist * dist, np.rot90(win, 2), mode='valid') - mu2_sq sigma12_A = convolve2d(refA * dist, np.rot90(win, 2), mode='valid') - mu1A_mu2 sigma12_B = convolve2d(refB * dist, np.rot90(win, 2), mode='valid') - mu1B_mu2 sigma1A_sq[sigma1A_sq < 0] = 0 sigma1B_sq[sigma1B_sq < 0] = 0 sigma2_sq[sigma2_sq < 0] = 0 gA = sigma12_A / (sigma1A_sq + eps) gB = sigma12_B / (sigma1B_sq + eps) sv_sq_A = sigma2_sq - gA * sigma12_A sv_sq_B = sigma2_sq - gB * sigma12_B gA[sigma1A_sq < eps] = 0 gB[sigma1B_sq < eps] = 0 sv_sq_A[sigma1A_sq < eps] = sigma2_sq[sigma1A_sq < eps] sv_sq_B[sigma1B_sq < eps] = sigma2_sq[sigma1B_sq < eps] sigma1A_sq[sigma1A_sq < eps] = 0 sigma1B_sq[sigma1B_sq < eps] = 0 gA[sigma2_sq < eps] = 0 gB[sigma2_sq < eps] = 0 sv_sq_A[sigma2_sq < eps] = 0 sv_sq_B[sigma2_sq < eps] = 0 sv_sq_A[gA < 0] = sigma2_sq[gA < 0] sv_sq_B[gB < 0] = sigma2_sq[gB < 0] gA[gA < 0] = 0 gB[gB < 0] = 0 sv_sq_A[sv_sq_A <= eps] = eps sv_sq_B[sv_sq_B <= eps] = eps numA += np.sum(np.log10(1 + gA * gA * sigma1A_sq / (sv_sq_A + sigma_nsq))) numB += np.sum(np.log10(1 + gB * gB * sigma1B_sq / (sv_sq_B + sigma_nsq))) denA += np.sum(np.log10(1 + sigma1A_sq / sigma_nsq)) denB += np.sum(np.log10(1 + sigma1B_sq / sigma_nsq)) vifpA = numA / denA vifpB =numB / denB if np.isnan(vifpA): vifpA=1 if np.isnan(vifpB): vifpB = 1 return vifpA+vifpB