昊虹AI笔记网

 找回密码
 立即注册
搜索
查看: 2054|回复: 0
收起左侧

尺寸相同的两幅图像的两个相似度评价指标-PSNR和SSIM(原理介绍及C++代码实现)

[复制链接]

238

主题

241

帖子

931

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
931
昊虹君 发表于 2022-11-25 13:04 | 显示全部楼层 |阅读模式
尺寸相同的两幅图像的两个相似度评价指标-PSNR和SSIM(原理介绍及C++代码实现)

图像的相似度在目标检测跟踪、图像内容搜索、特征分析领域有着广泛的应用。

对于尺寸相同的图像,常见的图像相似度评较指标有:峰值信噪比PSNR与结构相似性SSIM。
峰值信噪比PSNR的原理比结构相似性SSIM的原理简单。

下面分别介绍两种相似度评较指标。

1 峰值信噪比PSNR(Peak Signal to Noise Ratio)
PSNR基于图像像素灰度值进行统计分析。
由于与人类视觉的特点有差异,PSNR通常出现的评价结果与人的主要感觉不一致,但其仍然是一个有参考价值的评价指标。

PSNR可简单地由均方差MSE进行定义。
对于两幅图像I与K,尺寸大小均为m×n,它们的均方误差(MSE)的定义为:


峰值信噪比PSNR的定义为:

其中,
MSE表示当前图像I与K的均方误差,
MAX表示图像I像素点的最大可取值,如果每个像素点用8位表示,那么最大值就是255;如果每个像素点用N位表示,那么MAX就为2^{N}-1。
如果图像是三通道的,那么MSE为所有通道的方差之和除以图像尺寸再除以3。
PSNR的单位为dB,PSNR的值越大,图像相似度越高。在图像压缩中,压缩前和压缩后的图像峰值信噪比PSNR通常为30~40dB。

可以使用OpenCV的函数cv::PSNR()来求PSNR。
函数cv::PSNR()的官方资料如下:

该函数的使用示例代码如下:
代码中用到的图像下载链接:
https://pan.baidu.com/s/1jY1Qd1IzGh-5Ah2iK_PmRQ?pwd=ctdf
[C++] 纯文本查看 复制代码
//出处:昊虹AI笔记网(hhai.cc)
//用心记录计算机视觉和AI技术

//博主微信/QQ 2487872782
//QQ群 271891601
//欢迎技术交流与咨询

//OpenCV版本 OpenCV3.0

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{

	// 读取源图像及两幅待检测相似度的图像  
	cv::Mat srcImage1 = cv::imread("F:/material/images/2022/2022-11/PSNR-SSIM/hand1.jpg", 1);
	if (srcImage1.empty())
		return -1;

	cv::Mat srcImage2 = cv::imread("F:/material/images/2022/2022-11/PSNR-SSIM/hand2.jpg", 1);
	if (srcImage2.empty())
		return -1;

	cv::Mat srcImage3 = cv::imread("F:/material/images/2022/2022-11/PSNR-SSIM/circle.jpg", 1);
	if (srcImage3.empty())
		return -1;

	double psnr1, psnr2;

	psnr1 = cv::PSNR(srcImage1, srcImage2);
	std::cout << "hand1.jpg VS hand2.jpg PSNR is: " << psnr1 << std::endl << std::endl;

	psnr2 = cv::PSNR(srcImage1, srcImage3);
	std::cout << "hand1.jpg VS circle.jpg PSNR is: " << psnr2 << std::endl << std::endl;

	return 0;
}

运行结果如下:

                                          


也可以根据上面的原理自己实现对PSNR指标值的求取。
自己写的计算两幅图像峰值信噪比PSNR的C++代码如下:
代码中用到的图像下载链接:
https://pan.baidu.com/s/1jY1Qd1IzGh-5Ah2iK_PmRQ?pwd=ctdf
[C++] 纯文本查看 复制代码
//出处:昊虹AI笔记网(hhai.cc)
//用心记录计算机视觉和AI技术

//博主微信/QQ 2487872782
//QQ群 271891601
//欢迎技术交流与咨询

//OpenCV版本 OpenCV3.0

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

// PSNR 峰值信噪比计算,如果两幅图像相似度较高,那么返回数值通常为30-50dB,值越大相似度越高
double PSNR(const Mat& I1, const Mat& I2)//注意,两幅图的大小要一致
{
	cv::Mat s1;
	// 计算图像差|I1 - I2|
	absdiff(I1, I2, s1);
	// 转成32浮点数进行平方
	s1.convertTo(s1, CV_32F);
	// s1*s1,即|I1 - I2|^2
	s1 = s1.mul(s1);
	// 分别叠加每个通道的元素,存于s中
	cv::Scalar s = sum(s1);
	// 计算所有通道元素和
	double sse = s.val[0] + s.val[1] + s.val[2];
	// 当元素很小时返回0值
	if (sse <= 1e-10)
		return 0;
	else
	{
		// 根据公式计算当前I1与I2的均方误差
		double mse = sse / (double)(I1.channels() * I1.total());
		// 计算峰值信噪比
		double psnr = 10.0*log10((255 * 255) / mse);
		return psnr;
	}
}

int main()
{
	// 读取源图像及两幅待检测相似度的图像  
	cv::Mat srcImage1 = cv::imread("F:/material/images/2022/2022-11/PSNR-SSIM/hand1.jpg", 1);
	if (srcImage1.empty())
		return -1;

	cv::Mat srcImage2 = cv::imread("F:/material/images/2022/2022-11/PSNR-SSIM/hand2.jpg", 1);
	if (srcImage2.empty())
		return -1;

	cv::Mat srcImage3 = cv::imread("F:/material/images/2022/2022-11/PSNR-SSIM/circle.jpg",1);
	if (srcImage3.empty())
		return -1;

	cv::imshow("hand1", srcImage1);
	cv::imshow("hand3", srcImage2);
	cv::imshow("circle", srcImage3);

	double psnr_01 = 0;
	psnr_01 = PSNR(srcImage1, srcImage2);//注意,两幅图的大小要一致
	std::cout << "hand1.jpg VS hand2.jpg PSNR is: " << psnr_01 << std::endl;

	double psnr_02 = 0;
	psnr_02 = PSNR(srcImage1, srcImage3);//注意,两幅图的大小要一致
	std::cout << "hand1.jpg VS circle.jpg PSNR is: " << psnr_02 << std::endl;



	cv::waitKey(0);
	return 0;
}

运行结果如下:

                                          

从上面的运行结果可以看出,用OpenCV的函数cv::PSNR()和自己写的求解PSNR的函数,结果相同。


2 结构相似性SSIM(Structural Similarity)
SSIM是一种衡量两幅图像相似程度的结构相似性指标,相对PSNR而言,结构相似性在评价图像质量上更能符合人类的视觉特性。
结构相似于基于的原理是自然影像是高度结构化的,领域像素具有较强的关联性。

给定两幅图像,分别为x和y,二者的结构相似性SSIM定义为:

其中:
μ_x与μ_y分别表示图像x与图像y的均值;

σ_x和σ_y分别表示图像x与图像y的标准差;

C1、C2是用来维持稳定的常数:
C1=(k1*L)^2,C2=(k2*L)^2
k1=0.01,k2= 0.03
L是像素值的动态范围,如果图像某个通道的像素值用一个字节存储,则动态范围L=255。
当L=255,k1=0.01,k2= 0.03时
C1 = 6.5025,C2 = 58.5225

结构相似性的值范围为0到1,当两张图像一模一样时,SSIM的值等于1。

根据上述的计算式,利用OpenCV容易写出计算SSIM的代码。

基于OpenCV计算SSIM的C++代码如下:
下面代码中用到的图像百度网盘下载链接如下:
https://pan.baidu.com/s/1jY1Qd1IzGh-5Ah2iK_PmRQ?pwd=ctdf

各位朋友,很抱歉,写文不易,
如果您需要这个计算SSIM的C++代码,请您花费5元移步淘宝购买(自动发货):
淘宝购买链接:https://item.taobao.com/item.htm?ft=t&id=696136635898

运行结果如下:

                                          

结果说明:
上面每个结果都是四个数,之所以是四个数,是因为我们用容器Scalar来存储各通道的SSIM值,一个Scalar容器里有四个dobuble类型的数,所以每个结果都是四个数。
四个数我们只用了前面三个,分别表示第0通道,1通道,2通道的SSIM值。
关于容器Scalar的详细介绍,见链接 https://www.hhai.cc/thread-144-1-1.html
从上面的结果来看,两幅图像的相似度越高,SSIM的值越大,当两幅图像完全相同时,值为1。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|昊虹AI笔记网 ( 蜀ICP备2024076726 )

GMT+8, 2024-5-19 08:01 , Processed in 0.026767 second(s), 22 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表