一、SSIM 结构相似性
SSIM算法主要用于检测两张相同尺寸的图像的相似度、或者检测图像的失真程序。该指标首先是由德州大学奥斯丁分校的图像和视频工程实验室提出。而如果两幅图像是压缩前和压缩后的图像,那么SSIM图像就可以用来评估压缩后的图像质量。
SSIM评价将两幅图的相似性比较拆成了三个维度:亮度(luminance)、对比度(contrast)、结构(structure)。最终的相似度为这三个函数的乘积。
该相似度的设计遵循三个原则
- 对称性:即

- 有界性:即

- 极限值唯一:即
,当且仅当X=Y
给定两个图像X和Y,两张图像的结构相似度可按照以下方式求出




式中
是X的平均值,
是Y的平均值,
是X的方差,
是Y的方差,
是X和Y的协方差。
,
,
是用来避免分母为0 而维持稳定的常数。L是像素值的动态范围,一般为255。
,
。
当设定
时,可将SSIM相似度的公式改写为更为简单的形式:

结构相似度的范围为-1到1。当两张图像一摸一样时,SSIM的值等于1。
二、函数及其说明
cpp
Scalar getSSIM(Mat cImg1, Mat cImg2)
{
Mat i1 = cImg1;
Mat i2 = cImg2;
const double C1 = 6.5025, C2 = 58.5225; // (0.01 * 255)^2 ; (0.03 * 255)^2
Mat cImgExt1, cImgExt2;
cImg1.convertTo(cImgExt1, CV_32F);
cImg2.convertTo(cImgExt2, CV_32F);
Mat cImgGaus1, cImgGaus2;
GaussianBlur(cImgExt1, cImgGaus1, Size(11, 11), 1.5); //以高斯代替均值
GaussianBlur(cImgExt2, cImgGaus2, Size(11, 11), 1.5);
Mat cL;
Mat cImgGaus1_2 = cImgGaus1.mul(cImgGaus2);
Mat cImgGaus1_1 = cImgGaus1.mul(cImgGaus1);
Mat cImgGaus2_2 = cImgGaus2.mul(cImgGaus2);
divide(2 * cImgGaus1_2 + C1, cImgGaus1_1 + cImgGaus2_2 + C1,cL); //亮度
Mat cCS;
Mat cImgDelt1 = cImgExt1 - cImgGaus1;
Mat cImgDelt2 = cImgExt2 - cImgGaus2;
Mat cImgDelt1_2 = cImgDelt1.mul(cImgDelt2);
Mat cImgDelt1_1 = cImgDelt1.mul(cImgDelt1);
Mat cImgDelt2_2 = cImgDelt2.mul(cImgDelt2);
divide(2 * cImgDelt1_2 + C2, cImgDelt1_1 + cImgDelt2_2 + C2, cCS); //对比度与结构
Mat cSSIMRsl = cL.mul(cCS);
return mean(cSSIMRsl);
}
在SSIM(结构相似性)算法中经常会使用高斯模糊(GaussianBlur ) 代替**均值模糊(均值滤波)**,主要出于以下原因:
- 高斯加权更符合人眼视觉特性
人眼对图像中心区域的敏感度高于边缘区域。高斯滤波对中心像素赋予更高权重,能更好地模拟人类视觉系统对局部结构的感知方式,而均值滤波对邻域内所有像素等权处理,忽略了这种空间重要性差异。 - 避免边缘模糊失真
均值滤波在图像边缘或细节处容易造成过度平滑,破坏结构信息;高斯滤波则在保留主要结构的同时平滑噪声,更有利于准确计算亮度、对比度和结构三要素。 - 数学建模更合理
SSIM公式中需计算局部窗口内的均值、方差和协方差。高斯加权能提供更平滑、连续的统计估计,减少因窗口边界突变带来的计算波动,提升SSIM值的稳定性与准确性。
简言之:高斯Blur 比均值Blur 更贴合人眼感知模型,能更精确地反映图像的结构相似性,因此被SSIM算法优先采用。
三、应用限制
结构相似性指标有其限制,对于影像出现位移、缩放、旋转(皆属于非结构性的失真)的情况无法有效的运作。当图片出现平移、旋转或是缩放时,结构相似度指标会改变得十分剧烈,并很容易将两张类似的图片视为不相似的。原因与在计算SSIM时所使用的局部性视窗有关,平移、旋转或是缩放都会导致视窗内的像素结构完全改变,使SSIM无法正确估计相似度。
四、补充说明
1、 convertTo(cImgExt1, CV_32F)
convertTo函数只改变数据类型,不改变通道数。
2、GaussianBlur(cImgExt1, cImgGaus1, Size(11, 11), 1.5);
是 OpenCV 中常用的图像模糊函数之一。它使用高斯滤波器对图像进行平滑处理。高斯模糊通过给不同的像素赋予不同的权重来平滑图像,常用于减少图像中的噪声和细节,同时比均值模糊更好地保留图像的边缘。
其函数原型:
cpp
void cv::GaussianBlur(
InputArray src, // 输入图像
OutputArray dst, // 输出图像
Size ksize, // 滤波器的核大小 (宽度和高度)
double sigmaX, // X方向的高斯核标准差
double sigmaY = 0, // Y方向的高斯核标准差,默认为0
int borderType = BORDER_DEFAULT // 边界类型
);
3、cImgGaus1.mul(cImgGaus2):Opencv中对于矩阵乘法有三种
- A*B:即常规理解的矩阵乘法

- A.mul(B):即常规立即的矩阵点乘

- A.dot(B):在点乘的基础上做一个累加

4、divide(2 * cImgGaus1_2 + C1, cImgGaus1_1 + cImgGaus2_2 + C1,cL)
cv::divide() 是 OpenCV 中用于执行数组或标量的逐元素除法操作的函数。它允许对矩阵进行元素级的除法操作,支持两种使用方式:矩阵与矩阵之间的除法,或矩阵与标量之间的除法。其函数原型如下:
cpp
void cv::divide(
InputArray src1, //分子
InputArray src2, //分母
OutputArray dst, //输出
double scale=1, //可选的缩放因子。
int dtype=-1); //可选的输出矩阵类型
5、方差:用于衡量一组数据的离散程度。在统计描述中,方差用来计算每一个变量(观察值)与总体均数之间的差异。

6、标准差:是离均差平方的算术平均数(方差)的算术平方根。标准差也被称为标准偏差,或者实验标准差,在概率统计中最常使用作为统计分布程度上的测量依据。标准差越小说明数据越集中。

7、协方差:用来刻画两个随机变量 X,Y 之间的相关性。如果两个变量的变化趋势一致,也就是说如果其中一个大于自身的期望值,另外一个也大于自身的期望值,那么两个变量之间的协方差就是正值。
如果两个变量的变化趋势相反,即其中一个大于自身的期望值,另外一个却小于自身的期望值,那么两个变量之间的协方差就是负值。
协方差的公式如下:

方差就是协方差的一种特殊形式,当两个变量相同时,协方差就是方差了。