MSE(Mean Squared Error)均方誤差
MSE公式?
MSE 計(jì)算模型的預(yù)測 ? 與真實(shí)標(biāo)簽 Y 的接近程度。公式表示為:
?
對(duì)于兩個(gè)m×n的單通道圖像I和K,它們的均方誤差可定義為:
優(yōu)點(diǎn):MSE的函數(shù)曲線光滑、連續(xù),處處可導(dǎo),便于使用梯度下降算法,是一種常用的損失函數(shù)。而且,隨著誤差的減小,梯度也在減小,這有利于收斂,即使使用固定的學(xué)習(xí)速率,也能較快的收斂到最小值。
缺點(diǎn):當(dāng)真實(shí)值y和預(yù)測值f(x)的差值大于1時(shí),會(huì)放大誤差;而當(dāng)差值小于1時(shí),則會(huì)縮小誤差,這是平方運(yùn)算決定的。MSE對(duì)于較大的誤差(>1)給予較大的懲罰,較小的誤差(<1)給予較小的懲罰。也就是說,對(duì)離群點(diǎn)比較敏感,受其影響較大。
代碼實(shí)現(xiàn)
# MSE
# 方法一:自定義函數(shù)
import numpy as np
def MSE(img1,img2):
mse = np.mean( (img1 - img2) ** 2 )
return mse
# 方法二:調(diào)用庫函數(shù)
# 老版本的scikit-image,加載SSIM、PSNR、MSE的方式:
from skimage.measure import compare_mse as mse
# 新版本的scikit-image,加載方式:
from skimage.metrics import mean_squared_error as mse
PSNR(Peak Signal-to-Noise Ratio)峰值信噪比
?PSNR(Peak Signal to Noise Ratio),峰值信噪比,是一種評(píng)價(jià)圖像的客觀標(biāo)準(zhǔn)。,應(yīng)用場景有很多。它具有局性,PSNR是“Peak Signal to Noise Ratio”的縮寫。peak的中文意思是頂點(diǎn)。而ratio的意思是比率或比列的。整個(gè)意思就是到達(dá)噪音比率的頂點(diǎn)信號(hào),psnr一般是用于最大值信號(hào)和背景噪音之間的一個(gè)工程項(xiàng)目。通常在經(jīng)過影像壓縮之后,通常輸出的影像都會(huì)在某種程度與原始影像不同。為了衡量經(jīng)過處理后的影像品質(zhì),通常會(huì)參考PSNR值來衡量某個(gè)處理程序能否令人滿意。它是原圖像與被處理圖 像之間的均方誤差相對(duì)于(2n-1)2的對(duì)數(shù)值(信號(hào)最大值的平方,n是每個(gè)采樣值的比特?cái)?shù)),它的單位是dB。
PSNR是最普遍和使用最為廣泛的一種圖像客觀評(píng)價(jià)指標(biāo),然而它是基于對(duì)應(yīng)像素點(diǎn)間的誤差,即 基于誤差敏感的圖像質(zhì)量評(píng)價(jià)。由于并未考慮到人眼的視覺特性(人眼對(duì)空間頻率較低的對(duì)比差異敏感度較高,人眼對(duì)亮度對(duì)比差異的敏感度較色度高,人眼對(duì)一個(gè) 區(qū)域的感知結(jié)果會(huì)受到其周圍鄰近區(qū)域的影響等),因而經(jīng)常出現(xiàn)評(píng)價(jià)結(jié)果與人的主觀感覺不一致的情況。
PSNR公式
PSNR是通過MSE得出來的,公式如下:?
?其中,MAXI是表示圖像點(diǎn)顏色的最大數(shù)值,如果每個(gè)采樣點(diǎn)用 8 位表示,那么就是 255。
?所以MSE越小,則PSNR越大;所以PSNR越大,代表著圖像質(zhì)量越好。一般來說,
- PSNR高于40dB說明圖像質(zhì)量極好(即非常接近原始圖像);
- 在30—40dB通常表示圖像質(zhì)量是好的(即失真可以察覺但可以接受);
- 在20—30dB說明圖像質(zhì)量差;
- 最后,PSNR低于20dB圖像不可接受。
代碼實(shí)現(xiàn)
# PSNR
# 方法一:自定義函數(shù)
import numpy
import math
def psnr(img1, img2):
mse = numpy.mean( (img1 - img2) ** 2 )
if mse == 0:
return 100
PIXEL_MAX = 255.0
return 20 * math.log10(PIXEL_MAX / math.sqrt(mse))
# 方法二:調(diào)用庫函數(shù)
# 老版本的scikit-image,加載SSIM、PSNR、MSE的方式:
from skimage.measure import compare_ssim as ssim
from skimage.measure import compare_psnr as psnr
from skimage.measure import compare_mse as mse
# 新版本的scikit-image,加載方式:
from skimage.metrics import structural_similarity as ssim
from skimage.metrics import peak_signal_noise_ratio as psnr
from skimage.metrics import mean_squared_error as mse
SSIM(structural similarity)結(jié)構(gòu)相似性
SSIM(structural similarity),結(jié)構(gòu)相似性,是一種衡量兩幅圖像相似度的指標(biāo)。
SSIM算法主要用于檢測兩張相同尺寸的圖像的相似度、或者檢測圖像的失真程度。
SSIM公式基于樣本x和y之間的三個(gè)比較衡量:亮度 (luminance)、對(duì)比度 (contrast) 和結(jié)構(gòu) (structure)。
SSIM公式
?常數(shù)????, ????, ????是為了避免當(dāng)分母為 0 時(shí)造成的不穩(wěn)定問題。
????為均值, ???? 為方差, ?????? 表示協(xié)方差。
?
?
SSIM取值范圍為[0,1],值越大表示輸出圖像和無失真圖像的差距越小,即圖像質(zhì)量越好。
缺點(diǎn):結(jié)構(gòu)相似性指標(biāo)有其限制,對(duì)于影像出現(xiàn)位移、縮放、旋轉(zhuǎn)(皆屬于非結(jié)構(gòu)性的失真)的情況無法有效的運(yùn)作。
代碼實(shí)現(xiàn)
# SSIM
# https://github.com/scikit-image/scikit-image/blob/v0.21.0/skimage/metrics/_structural_similarity.py
# 方法一:自定義函數(shù)
import numpy as np
def ssim(y_true , y_pred):
u_true = np.mean(y_true)
u_pred = np.mean(y_pred)
var_true = np.var(y_true)
var_pred = np.var(y_pred)
std_true = np.sqrt(var_true)
std_pred = np.sqrt(var_pred)
R = 255
c1 = np.square(0.01*R)
c2 = np.square(0.03*R)
ssim = (2 * u_true * u_pred + c1) * (2 * std_pred * std_true + c2)
denom = (u_true ** 2 + u_pred ** 2 + c1) * (var_pred + var_true + c2)
return ssim / denom
# 方法二:調(diào)用庫函數(shù)
# 老版本的scikit-image,加載SSIM、PSNR、MSE的方式:
from skimage.measure import compare_ssim as ssim
from skimage.measure import compare_psnr as psnr
from skimage.measure import compare_mse as mse
# 新版本的scikit-image,加載方式:
from skimage.metrics import structural_similarity as ssim
from skimage.metrics import peak_signal_noise_ratio as psnr
from skimage.metrics import mean_squared_error as mse
函數(shù) structural_similarity
def structural_similarity(*, im1, im2,
win_size=None, gradient=False, data_range=None,
multichannel=False, gaussian_weights=False,
full=False, **kwargs)
處理RGB等多通道圖像或劃分為多塊時(shí)
上述原始計(jì)算方式僅法針對(duì)單通道灰度圖,
求RGB圖或多通道圖時(shí),PSNR有三種方式,其他類似:
- 分別計(jì)算 RGB 三個(gè)通道的 PSNR,然后取平均值。
- 計(jì)算 RGB 三通道的 MSE ,然后再除以 3 。
- 將圖片轉(zhuǎn)化為 YCbCr 格式,然后只計(jì)算 Y 分量也就是亮度分量的 PSNR。
分為多塊時(shí),在實(shí)際應(yīng)用中,可以利用滑動(dòng)窗將圖像分塊,令分塊總數(shù)為N,考慮到窗口形狀對(duì)分塊的影響,采用高斯加權(quán)計(jì)算每一窗口的均值、方差以及協(xié)方差,然后計(jì)算對(duì)應(yīng)塊的結(jié)構(gòu)相似度SSIM,最后將平均值作為兩圖像的結(jié)構(gòu)相似性度量,即平均結(jié)構(gòu)相似性SSIM。??
例:計(jì)算兩個(gè)RGB圖像的MSE(均方誤差):?
- ?從紅色通道開始?;
- ?計(jì)算兩個(gè)圖像的紅色通道中每個(gè)像素的灰度值之間的差異(所有像素位置的(redA(0,0)-redB(0,0)等);
- ?對(duì)每個(gè)像素的差異進(jìn)行平方? (redA(0,0)-redB(0,0)^2;
- ?計(jì)算紅色通道中所有像素的平方差之和?;
- ?對(duì)綠色和藍(lán)色通道重復(fù)上述操作?;
- ?將 3 個(gè)通道的總和相加并除以 3,即 (紅色通道和+綠色通道和+藍(lán)色通道和)/ 3?;
- ?除以圖像面積(寬度高度)??以形成平均值或平均值,即(紅和+綠和+藍(lán)和)/(3* 寬度*高度)??= MSE?。
?
余弦相似度
把圖片表示成一個(gè)向量,通過計(jì)算向量之間的余弦距離來表征兩張圖片的相似度。
余弦相似度算法:一個(gè)向量空間中兩個(gè)向量夾角間的余弦值作為衡量兩個(gè)個(gè)體之間差異的大小,余弦值接近1,夾角趨于0,表明兩個(gè)向量越相似,余弦值接近于0,夾角趨于90度,表明兩個(gè)向量越不相似。?
余弦公式?


代碼實(shí)現(xiàn)
圖片相似度計(jì)算方法總結(jié) - 知乎 (zhihu.com)
# -*- coding: utf-8 -*-
# !/usr/bin/env python
# 余弦相似度計(jì)算
from PIL import Image
from numpy import average, dot, linalg
# 對(duì)圖片進(jìn)行統(tǒng)一化處理
def get_thum(image, size=(64, 64), greyscale=False):
# 利用image對(duì)圖像大小重新設(shè)置, Image.ANTIALIAS為高質(zhì)量的
image = image.resize(size, Image.ANTIALIAS)
if greyscale:
# 將圖片轉(zhuǎn)換為L模式,其為灰度圖,其每個(gè)像素用8個(gè)bit表示
image = image.convert('L')
return image
# 計(jì)算圖片的余弦距離
def image_similarity_vectors_via_numpy(image1, image2):
image1 = get_thum(image1)
image2 = get_thum(image2)
images = [image1, image2]
vectors = []
norms = []
for image in images:
vector = []
for pixel_tuple in image.getdata():
vector.append(average(pixel_tuple))
vectors.append(vector)
# linalg=linear(線性)+algebra(代數(shù)),norm則表示范數(shù)
# 求圖片的范數(shù)
norms.append(linalg.norm(vector, 2))
a, b = vectors
a_norm, b_norm = norms
# dot返回的是點(diǎn)積,對(duì)二維數(shù)組(矩陣)進(jìn)行計(jì)算
res = dot(a / a_norm, b / b_norm)
return res
image1 = Image.open('010.jpg')
image2 = Image.open('011.jpg')
cosin = image_similarity_vectors_via_numpy(image1, image2)
print('圖片余弦相似度', cosin)
哈希相似度 Hash
圖片相相似度計(jì)算(Hash、SSIM、compareHist)_南蘇月的博客-CSDN博客_圖像相似度計(jì)算公式
哈希算法-圖片相似度計(jì)算_chenghaoy的博客-CSDN博客_均值哈希算法相似度
實(shí)現(xiàn)圖片相似度比較的hash算法有三種:均值哈希算法(AHash),差值哈希算法(DHash),感知哈希算法 (PHash)。
- aHash:平均值哈希。速度比較快,但是常常不太精確。
- pHash:感知哈希。精確度比較高,但是速度方面較差一些。
- dHash:差異值哈希。精確度較高,且速度也非???。
哈希不是以嚴(yán)格的方式計(jì)算Hash值,而是以更加相對(duì)的方式計(jì)算哈希值,因?yàn)椤跋嗨啤迸c否,就是一種相對(duì)的判定。值哈希算法、差值哈希算法和感知哈希算法都是值越小,相似度越高,取值為0-64,即漢明距離中,64位的hash值有多少不同。三直方圖和單通道直方圖的值為0-1,值越大,相似度越高。
均值哈希算法(AHash)
一張圖片就是一個(gè)二維信號(hào),它包含了不同頻率的成分。亮度變化小的區(qū)域是低頻成分,它描述大范圍的信息。而亮度變化劇烈的區(qū)域(比如物體的邊緣)就是高頻的成分,它描述具體的細(xì)節(jié)?;蛘哒f高頻可以提供圖片詳細(xì)的信息,而低頻可以提供一個(gè)框架。 而一張大的,詳細(xì)的圖片有很高的頻率,而小圖片缺乏圖像細(xì)節(jié),所以都是低頻的。所以我們平時(shí)的下采樣,也就是縮小圖片的過程,實(shí)際上是損失高頻信息的過程。均值哈希算法就是利用圖片的低頻信息。
具體步驟:
- 縮小尺寸:將圖片縮小到8x8的尺寸,總共64個(gè)像素。這一步的作用是去除圖片的細(xì)節(jié),只保留結(jié)構(gòu)、明暗等基本信息,摒棄不同尺寸、比例帶來的圖片差異。
- 簡化色彩:將縮小后的圖片,轉(zhuǎn)為64級(jí)灰度。也就是說,所有像素點(diǎn)總共只有64種顏色。
- 計(jì)算平均值:計(jì)算所有64個(gè)像素的灰度平均值
- 比較像素的灰度:將每個(gè)像素的灰度,與平均值進(jìn)行比較。大于或等于平均值,記為1;小于平均值,記為0。
- 計(jì)算哈希值:將上一步的比較結(jié)果,組合在一起,就構(gòu)成了一個(gè)64位的整數(shù),這就是這張圖片的指紋。組合的次序并不重要,只要保證所有圖片都采用同樣次序就行了。
最后得到兩張圖片的指紋信息后,計(jì)算兩組64位數(shù)據(jù)的漢明距離,即對(duì)比數(shù)據(jù)不同的位數(shù),不同位數(shù)越少,表明圖片的相似度越大。
分析: 均值哈希算法計(jì)算速度快,不受圖片尺寸大小的影響,但是缺點(diǎn)就是對(duì)均值敏感,例如對(duì)圖像進(jìn)行伽馬校正或直方圖均衡就會(huì)影響均值,從而影響最終的hash值。
感知哈希算法 (PHash)
感知哈希算法是一個(gè)比均值哈希算法更為健壯的一種算法,與均值哈希算法的區(qū)別在于感知哈希算法是通過DCT(離散余弦變換)來獲取圖片的低頻信息。
離散余弦變換(DCT)是種圖像壓縮算法,它將圖像從像素域變換到頻率域。然后一般圖像都存在很多冗余和相關(guān)性的,所以轉(zhuǎn)換到頻率域之后,只有很少的一部分頻率分量的系數(shù)才不為0,大部分系數(shù)都為0(或者說接近于0)。經(jīng)過DCT變換后的系數(shù)矩陣從左上角到右下角頻率越來越高,因此圖片的能量主要保留在左上角的低頻系數(shù)上了。
具體步驟:
- 縮小尺寸:pHash以小圖片開始,但圖片大于8x8,32x32是最好的。這樣做的目的是簡化了DCT的計(jì)算,而不是減小頻率。
- 簡化色彩:將圖片轉(zhuǎn)化成灰度圖像,進(jìn)一步簡化計(jì)算量。
- 計(jì)算DCT:計(jì)算圖片的DCT變換,得到32x32的DCT系數(shù)矩陣。
- 縮小DCT:雖然DCT的結(jié)果是32x32大小的矩陣,但我們只要保留左上角的8x8的矩陣,這部分呈現(xiàn)了圖片中的最低頻率。
- 計(jì)算平均值:如同均值哈希一樣,計(jì)算DCT的均值。
- 計(jì)算hash值:這是最主要的一步,根據(jù)8x8的DCT矩陣,設(shè)置0或1的64位的hash值,大于等于DCT均值的設(shè)為”1”,小于DCT均值的設(shè)為“0”。組合在一起,就構(gòu)成了一個(gè)64位的整數(shù),這就是這張圖片的指紋。
分析: 結(jié)果并不能告訴我們真實(shí)性的低頻率,只能粗略地告訴我們相對(duì)于平均值頻率的相對(duì)比例。只要圖片的整體結(jié)構(gòu)保持不變,hash結(jié)果值就不變。能夠避免伽馬校正或顏色直方圖被調(diào)整帶來的影響。對(duì)于變形程度在25%以內(nèi)的圖片也能精準(zhǔn)識(shí)別。
差值哈希算法(DHash)
比pHash,dHash的速度要快的多,相比aHash,dHash在效率幾乎相同的情況下的效果要更好,它是基于漸變實(shí)現(xiàn)的。
主要步驟:
- 縮小尺寸:收縮到8x9(高x寬)的大小,一遍它有72的像素點(diǎn)
- 轉(zhuǎn)化為灰度圖:把縮放后的圖片轉(zhuǎn)化為256階的灰度圖。
- 計(jì)算差異值:dHash算法工作在相鄰像素之間,這樣每行9個(gè)像素之間產(chǎn)生了8個(gè)不同的差異,一共8行,則產(chǎn)生了64個(gè)差異值
- 獲得指紋:如果左邊的像素比右邊的更亮,則記錄為1,否則為0.
代碼實(shí)現(xiàn)
import cv2
import numpy as np
#感知哈希算法
def pHash(image):
image = cv2.resize(image,(32,32), interpolation=cv2.INTER_CUBIC)
image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# cv2.imshow('image', image)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# 將灰度圖轉(zhuǎn)為浮點(diǎn)型,再進(jìn)行dct變換
dct = cv2.dct(np.float32(image))
# print(dct)
# 取左上角的8*8,這些代表圖片的最低頻率
# 這個(gè)操作等價(jià)于c++中利用opencv實(shí)現(xiàn)的掩碼操作
# 在python中進(jìn)行掩碼操作,可以直接這樣取出圖像矩陣的某一部分
dct_roi = dct[0:8,0:8]
avreage = np.mean(dct_roi)
hash = []
for i in range(dct_roi.shape[0]):
for j in range(dct_roi.shape[1]):
if dct_roi[i,j] > avreage:
hash.append(1)
else:
hash.append(0)
return hash
#均值哈希算法
def aHash(image):
#縮放為8*8
image=cv2.resize(image,(8,8),interpolation=cv2.INTER_CUBIC)
#轉(zhuǎn)換為灰度圖
image=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
avreage = np.mean(image)
hash = []
for i in range(image.shape[0]):
for j in range(image.shape[1]):
if image[i,j] > avreage:
hash.append(1)
else:
hash.append(0)
return hash
#差值感知算法
def dHash(image):
#縮放9*8
image=cv2.resize(image,(9,8),interpolation=cv2.INTER_CUBIC)
#轉(zhuǎn)換灰度圖
image=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# print(image.shape)
hash=[]
#每行前一個(gè)像素大于后一個(gè)像素為1,相反為0,生成哈希
for i in range(8):
for j in range(8):
if image[i,j]>image[i,j+1]:
hash.append(1)
else:
hash.append(0)
return hash
#計(jì)算漢明距離
def Hamming_distance(hash1,hash2):
num = 0
for index in range(len(hash1)):
if hash1[index] != hash2[index]:
num += 1
return num
if __name__ == "__main__":
image_file1 = './data/cartoon1.jpg'
image_file2 = './data/cartoon3.jpg'
img1 = cv2.imread(image_file1)
img2 = cv2.imread(image_file2)
hash1 = pHash(img1)
hash2 = pHash(img2)
dist = Hamming_distance(hash1, hash2)
#將距離轉(zhuǎn)化為相似度
similarity = 1 - dist * 1.0 / 64
print(dist)
print(similarity)
直方圖距離
圖片的相似度--直方圖距離 - 知乎 (zhihu.com)文章來源地址http://www.zghlxwxcb.cn/news/detail-781699.html
直方圖距離描述
方法描述:按照某種距離度量的標(biāo)準(zhǔn)對(duì)兩幅圖像的直方圖進(jìn)行相似度的測量。
圖像直方圖豐富的圖像細(xì)節(jié)信息,反映了圖像像素點(diǎn)的概率分布情況,統(tǒng)計(jì)每一個(gè)像素點(diǎn)強(qiáng)度值具有的像素個(gè)數(shù)。
- 優(yōu)點(diǎn):計(jì)算量比較小。
- 缺點(diǎn): 直方圖反應(yīng)的是圖像灰度值得概率分布,并沒有圖像的空間位置信息在里面,因此,會(huì)出現(xiàn)誤判;比如紋理結(jié)構(gòu)相同,但明暗不同的圖像,應(yīng)該相似度很高,但實(shí)際結(jié)果是相似度很低,而紋理結(jié)構(gòu)不同,但明暗相近的圖像,相似度卻很高。
計(jì)算步驟:
- 將圖片resize,得到相同大小的圖片;
- 將圖片灰度,灰度后圖片的像素在[0-255]之間;
- 計(jì)算圖片的直方圖數(shù)據(jù),統(tǒng)計(jì)相同像素點(diǎn)的概率分布;
- 根據(jù)相關(guān)性計(jì)算公式,計(jì)算兩個(gè)圖片直方圖的相關(guān)性。
代碼實(shí)現(xiàn)
import cv2
def calculate(image1, image2):
# 灰度直方圖算法
# 計(jì)算單通道的直方圖的相似值
hist1 = cv2.calcHist([image1], [0], None, [256], [0.0, 255.0])
hist2 = cv2.calcHist([image2], [0], None, [256], [0.0, 255.0])
# 計(jì)算直方圖的重合度
degree = 0
for i in range(len(hist1)):
if hist1[i] != hist2[i]:
degree = degree + (1 - abs(hist1[i] - hist2[i]) / max(hist1[i], hist2[i]))
else:
degree = degree + 1
degree = degree / len(hist1)
return degree
def classify_hist_with_split(image1, image2, size=(256, 256)):
# RGB每個(gè)通道的直方圖相似度
# 將圖像resize后,分離為RGB三個(gè)通道,再計(jì)算每個(gè)通道的相似值
image1 = cv2.resize(image1, size)
image2 = cv2.resize(image2, size)
sub_image1 = cv2.split(image1)
sub_image2 = cv2.split(image2)
sub_data = 0
for im1, im2 in zip(sub_image1, sub_image2):
sub_data += calculate(im1, im2)
sub_data = sub_data / 3
return sub_data
互信息(Mutual Information)
歸一化互信息(NMI)評(píng)價(jià)指標(biāo)_易_的博客-CSDN博客_nmi指標(biāo)
信息熵、相對(duì)熵、互信息?
信息熵:對(duì)信息進(jìn)行量化度量。可以理解為某種特定信息的出現(xiàn)概率。
相對(duì)熵:(relative entropy),又被稱為Kullback-Leibler散度(Kullback-Leibler divergence,KL散度)或信息散度(information divergence),是兩個(gè)概率分布(probability distribution)間差異的非對(duì)稱性度量 。在在信息理論中,相對(duì)熵等價(jià)于兩個(gè)概率分布的信息熵(Shannon entropy)的差值。
互信息:(Mutual Information)是信息論里一種有用的信息度量,它可以看成是一個(gè)隨機(jī)變量中包含的關(guān)于另一個(gè)隨機(jī)變量的信息量,或者說是一個(gè)隨機(jī)變量由于已知另一個(gè)隨機(jī)變量而減少的不肯定性。
歸一化互信息:將互信息放在[0,1]之間,容易評(píng)價(jià)算法的好壞。?
?代碼實(shí)現(xiàn)
from sklearn import metrics as mr
img1 = cv2.imread('1.png')
img2 = cv2.imread('2.png')
img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0])
nmi = mr.normalized_mutual_info_score(img1.reshape(-1), img2.reshape(-1))
像素匹配 pixelmatch
GitHub - whtsky/pixelmatch-py: A fast pixel-level image comparison library, originally created to compare screenshots in tests.
利用像素之間的匹配來計(jì)算相似度?
# https://github.com/whtsky/pixelmatch-py
# 第一步:
pip install pixelmatch
# 第二步:
from PIL import Image
from pixelmatch.contrib.PIL import pixelmatch
img_a = Image.open("a.png")
img_b = Image.open("b.png")
img_diff = Image.new("RGBA", img_a.size)
# note how there is no need to specify dimensions
mismatch = pixelmatch(img_a, img_b, img_diff, includeAA=True)
img_diff.save("diff.png")
舉例1——使用四種方法計(jì)算圖片相似度:MD5、直方圖、PSNR、SSIM
有史以來最全的圖像相似度算法_小殊小殊的博客-CSDN博客_圖片相似度
使用四種方法計(jì)算圖片相似度:MD5(粗暴的md5比較,判斷是否完全相同)、直方圖、PSNR、SSIM。
import numpy as np
from PIL import Image
from skimage.metrics import structural_similarity
import cv2
import os
import hashlib
import math
'''
粗暴的md5比較 返回是否完全相同
'''
def md5_similarity(img1_path, img2_path):
file1 = open(img1_path, "rb")
file2 = open(img2_path, "rb")
md = hashlib.md5()
md.update(file1.read())
res1 = md.hexdigest()
md = hashlib.md5()
md.update(file2.read())
res2 = md.hexdigest()
return res1 == res2
def normalize(data):
return data / np.sum(data)
'''
直方圖相似度
相關(guān)性比較 cv2.HISTCMP_CORREL:值越大,相似度越高
相交性比較 cv2.HISTCMP_INTERSECT:值越大,相似度越高
卡方比較 cv2.HISTCMP_CHISQR:值越小,相似度越高
巴氏距離比較 cv2.HISTCMP_BHATTACHARYYA:值越小,相似度越高
'''
def hist_similarity(img1, img2, hist_size=256):
imghistb1 = cv2.calcHist([img1], [0], None, [hist_size], [0, 256])
imghistg1 = cv2.calcHist([img1], [1], None, [hist_size], [0, 256])
imghistr1 = cv2.calcHist([img1], [2], None, [hist_size], [0, 256])
imghistb2 = cv2.calcHist([img2], [0], None, [hist_size], [0, 256])
imghistg2 = cv2.calcHist([img2], [1], None, [hist_size], [0, 256])
imghistr2 = cv2.calcHist([img2], [2], None, [hist_size], [0, 256])
distanceb = cv2.compareHist(normalize(imghistb1), normalize(imghistb2), cv2.HISTCMP_CORREL)
distanceg = cv2.compareHist(normalize(imghistg1), normalize(imghistg2), cv2.HISTCMP_CORREL)
distancer = cv2.compareHist(normalize(imghistr1), normalize(imghistr2), cv2.HISTCMP_CORREL)
meandistance = np.mean([distanceb, distanceg, distancer])
return meandistance
def PSNR(img1, img2):
mse = np.mean((img1/255. - img2/255.) ** 2)
if mse == 0:
return 100
PIXEL_MAX = 1
return 20 * math.log10(PIXEL_MAX / math.sqrt(mse))
def SSIM(img1, img2):
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
# 計(jì)算兩個(gè)灰度圖像之間的結(jié)構(gòu)相似度
score, diff = structural_similarity(gray1, gray2, win_size=101, full=True)
# diff = (diff * 255).astype("uint8")
# print("SSIM:{}".format(score))
return score, diff
def ssim(img1, img2):
u_true = np.mean(img1)
u_pred = np.mean(img2)
var_true = np.var(img1)
var_pred = np.var(img2)
std_true = np.sqrt(var_true)
std_pred = np.sqrt(var_pred)
c1 = np.square(0.01*7)
c2 = np.square(0.03*7)
ssim = (2 * u_true * u_pred + c1) * (2 * std_pred * std_true + c2)
denom = (u_true ** 2 + u_pred ** 2 + c1) * (var_pred + var_true + c2)
return ssim/denom
def MSE(img1,img2):
mse = np.mean( (img1 - img2) ** 2 )
return mse
if __name__ == '__main__':
img1_path = '1_08.jpg'
img2_path = '2_08.jpg'
img1 = cv2.imread(img1_path)
img2 = cv2.imread(img2_path)
# 1.粗暴的md5比較 返回是否完全相同
print('md5_similarity:', md5_similarity(img1_path, img2_path))
# 2.直方圖相似度
print('hist_similarity:', hist_similarity(img1, img2))
# 3.PSNR
print('PSNR:', PSNR(img1, img2))
# 4.SSIM
print('灰度圖SSIM:', SSIM(img1, img2)[0])
print('RGB圖_ssim:', ssim(img1, img2))
print('RGB圖_structural_similarity:', structural_similarity(img1,img2, multichannel=True))
# 5.MSE
print('MSE:', MSE(img1, img2))
效果展示:

md5_similarity: False
hist_similarity: 0.1344447074377748
PSNR: 12.980832701995697
灰度圖SSIM: 0.5966066785284522
RGB圖_ssim: 0.9917382398395064
RGB圖_structural_similarity: 0.525279441002218
MSE: 86.05895699395074
舉例2——批量計(jì)算PSNR、SSIM、MSE
import os
import numpy as np
from glob import glob
import cv2
from skimage.measure import compare_mse,compare_ssim,compare_psnr
def read_img(path):
return cv2.imread(path,cv2.IMREAD_GRAYSCALE)
def mse(tf_img1, tf_img2):
return compare_mse(tf_img1,tf_img2)
def psnr(tf_img1, tf_img2):
return compare_psnr(tf_img1,tf_img2)
def ssim(tf_img1, tf_img2):
return compare_ssim(tf_img1,tf_img2)
def main():
WSI_MASK_PATH1 = 'E:/test/A/'
WSI_MASK_PATH2 = 'E:/test/B/'
path_real = glob(os.path.join(WSI_MASK_PATH1, '*.jpg'))
path_fake = glob(os.path.join(WSI_MASK_PATH2, '*.jpg'))
list_psnr = []
list_ssim = []
list_mse = []
for i in range(len(path_real)):
t1 = read_img(path_real[i])
t2 = read_img(path_fake[i])
result1 = np.zeros(t1.shape,dtype=np.float32)
result2 = np.zeros(t2.shape,dtype=np.float32)
cv2.normalize(t1,result1,alpha=0,beta=1,norm_type=cv2.NORM_MINMAX,dtype=cv2.CV_32F)
cv2.normalize(t2,result2,alpha=0,beta=1,norm_type=cv2.NORM_MINMAX,dtype=cv2.CV_32F)
mse_num = mse(result1, result2)
psnr_num = psnr(result1, result2)
ssim_num = ssim(result1, result2)
list_psnr.append(psnr_num)
list_ssim.append(ssim_num)
list_mse.append(mse_num)
#輸出每張圖像的指標(biāo):
print("{}/".format(i+1)+"{}:".format(len(path_real)))
str = "\\"
print("image:"+path_real[i][(path_real[i].index(str)+1):])
print("PSNR:", psnr_num)
print("SSIM:", ssim_num)
print("MSE:",mse_num)
#輸出平均指標(biāo):
print("平均PSNR:", np.mean(list_psnr)) # ,list_psnr)
print("平均SSIM:", np.mean(list_ssim)) # ,list_ssim)
print("平均MSE:", np.mean(list_mse)) # ,list_mse)
if __name__ == '__main__':
main()
舉例3——計(jì)算Y通道或RGB通道的PSNR和SSIM
?Python計(jì)算Y通道或者RGB通道的PSNR_SSIM_未知量0520的博客-CSDN博客_folder_gt?
- 添加:PSNR/SSIM計(jì)算結(jié)果,保存文件(txt),便于后期導(dǎo)入excel列表分析。
- 代碼介紹:PSNR_SSIM效果和matlab計(jì)算的結(jié)果一致(本人沒有驗(yàn)證)。
- 代碼功能,能夠計(jì)算圖像的Y_channel 或者RGB_channel狀態(tài)下的PSNR_SSIM結(jié)果
- 用法:將真實(shí)圖片,生成圖片分別放入兩個(gè)文件夾,代碼中有選擇兩種方式(only_Y, RGB),切換注釋相應(yīng)的代碼行即可。
- 注意:安裝相應(yīng)的代碼庫。
'''
calculate the PSNR and SSIM.
same as MATLAB's results
https://blog.csdn.net/qq_45041702/article/details/120997743
'''
import os
import math
import numpy as np
import cv2
import glob
import os
def main():
# Configurations
# GT - Ground-truth;
# Gen: Generated / Restored / Recovered images
folder_GT = '/content/drive/MyDrive/Experiment/codes/26_PSNR_SSIM/All/groud_truth_png'
folder_Gen = '/content/drive/MyDrive/Experiment/codes/26_PSNR_SSIM/All/1_ESPCN_png'
#save the psnr and ssim score by txt
PS_path = '/content/drive/MyDrive/Experiment/codes/26_PSNR_SSIM/Score'
if not os.path.exists(PS_path):
print('NO_path to sava the NIQE_Score,Making....')
os.makedirs(PS_path)
else:
print("The NIQE_Score_path has existed")
PS_txt = open(PS_path +'/score1.txt', 'a' )
crop_border = 4 # same with scale
suffix = '' # suffix for Gen images
test_Y = False # True: test Y channel only; False: test RGB channels
PSNR_all = []
SSIM_all = []
img_list = sorted(glob.glob(folder_GT + '/*'))
if test_Y:
print('Testing Y channel.')
else:
print('Testing RGB channels.')
for i, img_path in enumerate(img_list):
base_name = os.path.splitext(os.path.basename(img_path))[0]
print(base_name)
im_GT = cv2.imread(img_path) / 255.
#不同格式圖像
# im_Gen = cv2.imread(os.path.join(folder_Gen, base_name + suffix + '.tif')) / 255.
im_Gen = cv2.imread(os.path.join(folder_Gen, base_name + suffix + '.png')) / 255.
if test_Y and im_GT.shape[2] == 3: # evaluate on Y channel in YCbCr color space
im_GT_in = bgr2ycbcr(im_GT)
im_Gen_in = bgr2ycbcr(im_Gen)
else:
im_GT_in = im_GT
im_Gen_in = im_Gen
# crop borders
if crop_border == 0:
cropped_GT = im_GT_in
cropped_Gen = im_Gen_in
else:
if im_GT_in.ndim == 3:
cropped_GT = im_GT_in[crop_border:-crop_border, crop_border:-crop_border, :]
cropped_Gen = im_Gen_in[crop_border:-crop_border, crop_border:-crop_border, :]
elif im_GT_in.ndim == 2:
cropped_GT = im_GT_in[crop_border:-crop_border, crop_border:-crop_border]
cropped_Gen = im_Gen_in[crop_border:-crop_border, crop_border:-crop_border]
else:
raise ValueError('Wrong image dimension: {}. Should be 2 or 3.'.format(im_GT_in.ndim))
#不同通道數(shù)(Y通道和RGB三個(gè)通道),需要更改
# calculate PSNR and SSIM
# PSNR = calculate_psnr(cropped_GT * 255, cropped_Gen * 255)
PSNR = calculate_rgb_psnr(cropped_GT * 255, cropped_Gen * 255)
SSIM = calculate_ssim(cropped_GT * 255, cropped_Gen * 255)
print('{:3d} - {:25}. \tPSNR: {:.4f} dB, \tSSIM: {:.4f}'.format(
i + 1, base_name, PSNR, SSIM))
PSNR_all.append(PSNR)
SSIM_all.append(SSIM)
single_info = '[{}],PSNR(dB),{:.4f}, SSIM,{:.4f}'
PS_txt.write(single_info.format(base_name,PSNR,SSIM))
PS_txt.write("\n")
Mean_format = 'Mean_PSNR: {:.4f}, Mean_SSIM: {:.4f}'
Mean_PSNR = sum(PSNR_all) / len(PSNR_all)
Mean_SSIM = sum(SSIM_all) / len(SSIM_all)
print(Mean_format.format(Mean_PSNR,Mean_SSIM))
PS_txt.write(Mean_format.format(Mean_PSNR,Mean_SSIM))
PS_txt.write('\n')
def calculate_psnr(img1, img2):
# img1 and img2 have range [0, 255]
img1 = img1.astype(np.float64)
img2 = img2.astype(np.float64)
mse = np.mean((img1 - img2)**2)
if mse == 0:
return float('inf')
return 20 * math.log10(255.0 / math.sqrt(mse))
def calculate_rgb_psnr(img1, img2):
"""calculate psnr among rgb channel, img1 and img2 have range [0, 255]
"""
n_channels = np.ndim(img1)
sum_psnr = 0
for i in range(n_channels):
this_psnr = calculate_psnr(img1[:,:,i], img2[:,:,i])
sum_psnr += this_psnr
return sum_psnr/n_channels
def ssim(img1, img2):
C1 = (0.01 * 255)**2
C2 = (0.03 * 255)**2
img1 = img1.astype(np.float64)
img2 = img2.astype(np.float64)
kernel = cv2.getGaussianKernel(11, 1.5)
window = np.outer(kernel, kernel.transpose())
mu1 = cv2.filter2D(img1, -1, window)[5:-5, 5:-5] # valid
mu2 = cv2.filter2D(img2, -1, window)[5:-5, 5:-5]
mu1_sq = mu1**2
mu2_sq = mu2**2
mu1_mu2 = mu1 * mu2
sigma1_sq = cv2.filter2D(img1**2, -1, window)[5:-5, 5:-5] - mu1_sq
sigma2_sq = cv2.filter2D(img2**2, -1, window)[5:-5, 5:-5] - mu2_sq
sigma12 = cv2.filter2D(img1 * img2, -1, window)[5:-5, 5:-5] - mu1_mu2
ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) *
(sigma1_sq + sigma2_sq + C2))
return ssim_map.mean()
def calculate_ssim(img1, img2):
'''calculate SSIM
the same outputs as MATLAB's
img1, img2: [0, 255]
'''
if not img1.shape == img2.shape:
raise ValueError('Input images must have the same dimensions.')
if img1.ndim == 2:
return ssim(img1, img2)
elif img1.ndim == 3:
if img1.shape[2] == 3:
ssims = []
for i in range(img1.shape[2]):
ssims.append(ssim(img1[..., i], img2[..., i]))
return np.array(ssims).mean()
elif img1.shape[2] == 1:
return ssim(np.squeeze(img1), np.squeeze(img2))
else:
raise ValueError('Wrong input image dimensions.')
def bgr2ycbcr(img, only_y=True):
'''same as matlab rgb2ycbcr
only_y: only return Y channel
Input:
uint8, [0, 255]
float, [0, 1]
'''
in_img_type = img.dtype
img.astype(np.float32)
if in_img_type != np.uint8:
img *= 255.
# convert
if only_y:
rlt = np.dot(img, [24.966, 128.553, 65.481]) / 255.0 + 16.0
else:
rlt = np.matmul(img, [[24.966, 112.0, -18.214], [128.553, -74.203, -93.786],
[65.481, -37.797, 112.0]]) / 255.0 + [16, 128, 128]
if in_img_type == np.uint8:
rlt = rlt.round()
else:
rlt /= 255.
return rlt.astype(in_img_type)
if __name__ == '__main__':
main()
結(jié)果展示:?
舉例4——調(diào)用SSIM算法,結(jié)合opencv閾值分割和輪廓提取,找兩圖差異
SSIM---結(jié)構(gòu)相似性算法(OpenCV+Python)_hedgehog__的博客-CSDN博客_python 結(jié)構(gòu)相似性?通過調(diào)用skimage.metrics包下的SSIM算法,結(jié)合OpenCV的閾值分割及輪廓提取算法,找出兩幅圖像的差異。
# https://blog.csdn.net/hedgehog__/article/details/107257755
import cv2
import imutils
from skimage.metrics import structural_similarity
import time
from skimage import filters, img_as_ubyte
import numpy as np
start = time.time()
# 讀入圖像,轉(zhuǎn)為灰度圖像
src = cv2.imread('C:/Users/Hedgehog/Desktop/right.jpg')
img = cv2.imread('C:/Users/Hedgehog/Desktop/left.jpg')
grayA = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 計(jì)算兩個(gè)灰度圖像之間的結(jié)構(gòu)相似度
(score, diff) = structural_similarity(grayA, grayB, win_size=101, full=True)
diff = (diff * 255).astype("uint8")
cv2.namedWindow("diff", cv2.WINDOW_NORMAL)
cv2.imshow("diff", diff)
print("SSIM:{}".format(score))
# 找到不同的輪廓以致于可以在表示為 '不同'的區(qū)域放置矩形
# 全局自適應(yīng)閾值分割(二值化),返回值有兩個(gè),第一個(gè)是閾值,第二個(gè)是二值圖像
dst = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cv2.namedWindow("threshold", cv2.WINDOW_NORMAL)
cv2.imshow('threshold', dst)
# findContours找輪廓,返回值有兩個(gè),第一個(gè)是輪廓信息,第二個(gè)是輪廓的層次信息(“樹”狀拓?fù)浣Y(jié)構(gòu))
# cv2.RETR_EXTERNAL:只檢測最外層輪廓
# cv2.CHAIN_APPROX_SIMPLE:壓縮水平方向、垂直方向和對(duì)角線方向的元素,保留該方向的終點(diǎn)坐標(biāo),如矩形的輪廓可用4個(gè)角點(diǎn)表示
contours, hierarchy = cv2.findContours(dst.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print(contours)
newimg = np.zeros(dst.shape, np.uint8) # 定義一個(gè)和圖像分割處理后相同大小的黑色圖
# drawContours畫輪廓,將找到的輪廓信息畫出來
cv2.drawContours(newimg, contours, -1, (255, 255, 255), 1)
cv2.namedWindow("contours", cv2.WINDOW_NORMAL)
cv2.imshow('contours', newimg)
# cnts = cnts[0] if imutils.is_cv3() else cnts[0] 取findContours函數(shù)的第一個(gè)返回值,即取輪廓信息
# 找到一系列區(qū)域,在區(qū)域周圍放置矩形
for c in contours:
(x, y, w, h) = cv2.boundingRect(c) # boundingRect函數(shù):計(jì)算輪廓的垂直邊界最小矩形,矩形是與圖像上下邊界平行的
cv2.rectangle(src, (x, y), (x + w, y + h), (0, 255, 0), 2) # rectangle函數(shù):使用對(duì)角線的兩點(diǎn)pt1,pt2畫一個(gè)矩形輪廓
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) # 畫矩形的圖, pt1, pt2,(對(duì)角線兩點(diǎn)的坐標(biāo)), 矩形邊框的顏色,矩形邊框的粗細(xì)
end = time.time()
print(end - start)
# 用cv2.imshow 展現(xiàn)最終對(duì)比之后的圖片
cv2.namedWindow("right", cv2.WINDOW_NORMAL)
cv2.imshow('right', src)
cv2.namedWindow("left", cv2.WINDOW_NORMAL)
cv2.imshow('left', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果展示:
參考博客
計(jì)算兩幅圖像的相似度總結(jié)_JerrySing的博客-CSDN博客_compare_ssim
Python計(jì)算圖片之間的相似度_~小瘋子~的博客-CSDN博客_python 識(shí)別圖片相似度
有史以來最全的圖像相似度算法_小殊小殊的博客-CSDN博客_圖片相似度
(超詳細(xì))實(shí)現(xiàn)計(jì)算圖片相似度MSE和PSNR_Natuki丶的博客-CSDN博客_計(jì)算psnr和mse
Python批量計(jì)算PSNR、SSIM、MSE_楊楊楊Garrick的博客-CSDN博客
圖像質(zhì)量評(píng)價(jià)指標(biāo)MSE/PSNR/SSIM_秋天的從從的博客-CSDN博客_圖像mse
圖片相相似度計(jì)算(Hash、SSIM、compareHist)_南蘇月的博客-CSDN博客_圖像相似度計(jì)算公式
【OpenCV-Python】:圖像PSNR、SSIM、MSE計(jì)算_米開朗琪羅~的博客-CSDN博客_圖像的mse計(jì)算
Python計(jì)算Y通道或者RGB通道的PSNR_SSIM_未知量0520的博客-CSDN博客_folder_gt
scikit-image 0.18.0版本計(jì)算PSNR、SSIM、MSE(Python代碼)_YZBshanshan的博客-CSDN博客_scikit-image版本
圖像質(zhì)量評(píng)估中的PSNR和SSIM的定義,公式和含義_·如煙·的博客-CSDN博客_psnr定義
【基礎(chǔ)知識(shí)】圖像去噪評(píng)估—PSNR和SSIM - 梁君牧 - 博客園 (cnblogs.com)
SSIM---結(jié)構(gòu)相似性算法(OpenCV+Python)_hedgehog__的博客-CSDN博客_python 結(jié)構(gòu)相似性
圖片相似度計(jì)算方法總結(jié) - 知乎 (zhihu.com)
相似度計(jì)算方法(三) 余弦相似度_潘永青的博客-CSDN博客_余弦相似度文章來源:http://www.zghlxwxcb.cn/news/detail-781699.html
圖片的相似度--直方圖距離 - 知乎 (zhihu.com)
到了這里,關(guān)于計(jì)算兩幅圖像的相似度(PSNR、SSIM、MSE、余弦相似度、MD5、直方圖、互信息、Hash)& 代碼實(shí)現(xiàn) 與舉例的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!