import cv2
import numpy as np
import math
def psnr(target, ref):
#将图像格式转为float64
target_data = np.array(target, dtype=np.float64)
ref_data = np.array(ref,dtype=np.float64)
# 直接相减,求差值
diff = ref_data - target_data
# 按第三个通道顺序把三维矩阵拉平
diff = diff.flatten('C')
# 计算MSE值
rmse = math.sqrt(np.mean(diff ** 2.))
# 精度
eps = np.finfo(np.float64).eps
if(rmse == 0):
rmse = eps
return 20*math.log10(255.0/rmse)
# 计算单通道图像
IMG_1 = cv2.imread("yuer.jpg",0)
IMG_2 = cv2.imread("june.jpg",0)
# 计算三通道图像(假如输入的是三通道图像的话)
# IMG_1 = cv2.imread("yuer.jpg")
# IMG_2 = cv2.imread("june.jpg")
# 这里resize是因为我使用的两张图大小不一样,所以resize到同样的大小
# 正常情况下待计算psnr的两张图一般是相同大小的,不需要resize
# 而且大小不同的两张图,resize后求得的psnr也没有啥意义
IMG_1 = np.resize(IMG_1, (100,100))
IMG_2 = np.resize(IMG_2, (100,100))
print(psnr(IMG_1,IMG_2))
python计算psnr的时候可能会出现和其他方法计算出的psnr结果不同,相差比较大,这种情况一般是因为python里面的unit8和float数据类型造成的,把图片数据先转成float类型的再计算,一般不会出错。
另外,假如两个人算的psnr不同,但误差不大不小,差个一两dB,不是特别夸张的情况下,有可能是其中一个是按三通道计算的,另一个是按照单通道计算的。
这些都是容易忽略的坑,特此记录一下。
//输入格式是Mat类型,I1,I2代表是输入的两幅图像
double getPSNR(const Mat& I1, const Mat& I2)
{
Mat s1;
absdiff(I1, I2, s1); // |I1 - I2|AbsDiff函数是 OpenCV 中计算两个数组差的绝对值的函数
s1.convertTo(s1, CV_32F); // 这里我们使用的CV_32F来计算,因为8位无符号char是不能进行平方计算
s1 = s1.mul(s1); // |I1 - I2|^2
Scalar s = sum(s1); //对每一个通道进行加和
double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
if (sse <= 1e-10) // 对于非常小的值我们将约等于0
return 0;
else
{
double mse = sse / (double)(I1.channels() * I1.total());//计算MSE
double psnr = 10.0 * log10((255 * 255) / mse);
return psnr;//返回PSNR
}
}
int main()
{
//先定义PSNR
double psnr;
//然后读取输入的两幅图像
Mat img1 = imread("101.jpg");
Mat img2 = imread("103.jpg");
//调用函数
psnr = getPSNR(img1, img2);
cout << psnr << endl;
}