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

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


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


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


PSNR可简单地由均方差MSE进行定义。

对于两幅图像I与K,尺寸大小均为m×n,它们的均方误差(MSE)的定义为:

Siamese neural network图像相似性衡量 图像相似度分析_相似度


峰值信噪比PSNR的定义为:


Siamese neural network图像相似性衡量 图像相似度分析_信噪比_02

其中,
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()的官方资料如下:

Siamese neural network图像相似性衡量 图像相似度分析_PSNR_03

 该函数的使用示例代码如下:
代码中用到的图像下载链接:
https://pan.baidu.com/s/1jY1Qd1IzGh-5Ah2iK_PmRQ?pwd=ctdf

//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;
}

运行结果如下:

Siamese neural network图像相似性衡量 图像相似度分析_PSNR_04

Siamese neural network图像相似性衡量 图像相似度分析_相似度_05

也可以根据上面的原理自己实现对PSNR指标值的求取。
自己写的计算两幅图像峰值信噪比PSNR的C++代码如下:
代码中用到的图像下载链接:
https://pan.baidu.com/s/1jY1Qd1IzGh-5Ah2iK_PmRQ?pwd=ctdf

//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;
}

 运行结果如下:

Siamese neural network图像相似性衡量 图像相似度分析_相似度_06

Siamese neural network图像相似性衡量 图像相似度分析_SSIM_07

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


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


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

Siamese neural network图像相似性衡量 图像相似度分析_信噪比_08

其中:
μ_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的代码。

计算SSIM的代码运行结果如下:

Siamese neural network图像相似性衡量 图像相似度分析_PSNR_09

Siamese neural network图像相似性衡量 图像相似度分析_SSIM_10

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