FFmpeg计算图像的SSIM的原理

SSIM算法基于HVS更擅长从图像中提取结构信息的事实,并且利用结构相似度来计算图像的感知质量。

在Z. Wang等人的论文Multi-scale structural similarity for image quality assessment中也提到, S S I M SSIM SSIM算法要好于当时的其它的感知图像质量指标。

SSIM的计算公式:

SSIM计算中的图像分割

==在整幅图片的跨度上,图像亮度的均值和方差变化较为剧烈;并且图像上不同区块的失真程度也有可能不同;再者人眼睛每次只能聚焦于一处,更关注局部数据而非全局数据。==因此如上的 S S I M SSIM SSIM算法不能直接作用于一整副图像。

在论文Image quality assessment: From error visibility to structural similarity中,作者采用 11 × 11 11 \times 11 11×11的滑动窗口将整副图像分割为 N N N个patch,然后计算每一个patch的 S S I M SSIM SSIM,最后计算所有patch的 S S I M SSIM SSIM值的平均数( M e a n S S I M : M S S I M Mean \ \ SSIM:MSSIM Mean SSIM:MSSIM)作为整副图像的 S S I M SSIM SSIM。

为避免滑动窗口带来的块效应,在计算每个patch的均值 μ \mu μ和方差 σ 2 \sigma^2 σ2时,作者采用 σ = 1.5 \sigma=1.5 σ=1.5的高斯卷积核作加权平均。整副图像有 N N N个patch,则 M S S I M MSSIM MSSIM的计算公式为:

FFmpeg计算SSIM的实际实现

FFmpeg提供了计算 S S I M SSIM SSIM的实现:
https://github.com/FFmpeg/FFmpeg/blob/master/tests/tiny_ssim.c。

从代码注释中看到:为提升算法性能,没采用论文中的高斯加权方式计算每个patch的 S S I M SSIM SSIM,而采用了 8 × 8 8 \times 8 8×8的块来计算每个patch的 S S I M SSIM SSIM。

standard approximation of overlapped 8x8 block sums

解释一下注释中的standard approximation of overlapped 8x8 block sums 的含义。分解成两个部分来解释:overlapped 8x8 block和sums。
overlapped 8x8 block的含义:

FFmpeg在计算图像 S S I M SSIM SSIM时,首先以 4 × 4 4 \times 4 4×4的块大小把图1所示的分辨率为 W × H W \times H W×H的图像:

图1:原始图像

图2:分割后的图像

对图2中的每一块用 b l o c k ( i , j ) block(i,j) block(i,j)来表示(图2中的红色块),FFmpeg使用 b l o c k ( i , j ) block(i,j) block(i,j)及其上、右、右上块(图2中的绿色块)来计算 S S I M : S S I M ( x i j , y i j ) SSIM:SSIM(x_{ij},y_{ij}) SSIM:SSIM(xij,yij)。
b l o c k ( i , j ) block(i,j) block(i,j)及其上、右、右上块构成一个 8 × 8 8\times8 8×8的像素块,并且该 8 × 8 8\times8 8×8块和计算 b l o c k ( i , j + 1 ) block(i,j+1) block(i,j+1)的 S S I M SSIM SSIM用到的 8 × 8 8\times8 8×8的块存在重合像素,这就是注释中的overlapped 8x8 block的真正含义。

根据如上规则: i ∈ [ 1 , H 4 ] , j ∈ [ 0 , W 4 − 1 ] i \in [1,\frac{H}{4}],j \in [0,\frac{W}{4}-1] i∈[1,4H],j∈[0,4W−1],即第0行和最后一列的块不会计算 S S I M SSIM SSIM。最后FFmpeg中的 S S I M SSIM SSIM公式为:

sums的含义

如前所述,分析了FFmpeg计算图像的 S S I M SSIM SSIM的整体思路,接下来分析FFmpeg是如何计算 b l o c k ( i , j ) block(i,j) block(i,j)的 S S I M ( x i j , y i j ) SSIM(x_{ij},y_{ij}) SSIM(xij,yij)的,即可解释sums的含义。

首先利用源码中的函数ssim_4x4x2_core()来计算 b l o c k ( i , j ) block(i,j) block(i,j)块的结构相似性指标,包含4个指标:

s1:参考图像在 b l o c k ( i , j ) block(i,j) block(i,j)块的像素之和

s2:受损图像在 b l o c k ( i , j ) block(i,j) block(i,j)块的像素之和

ss:参考图像和受损图像在 b l o c k ( i , j ) block(i,j) block(i,j)块的像素平方之和

s12:参考图像和受损图像在 b l o c k ( i , j ) block(i,j) block(i,j)块的对应像素乘积之和。

如上4个指标是后续会用到的sums(4类sum,称为sums),该sums也就是overlapped 8x8 block sums中的sums的概念。

利用sums计算各4x4块的SSIM
接下来利用该sums值计算 S S I M SSIM SSIM。为提升效率,FFmpeg会按照行来计算每一行的各个块的sums数据,并将每个行块的sums数据存储在长度为 W 4 \frac{W}{4} 4W的数组指针sum((int(*)[4]))中。

sum指针有两种:

sum0:存储当前行的各块的sums结果

sum1:存储当前行的上一行的sums结果

先计算第 i − 1 i-1 i−1行块和第 i i i行块的sums结果,并分别存入sum1和sum0中。然后遍历第 i i i行块的每一个块,并利用sum1和sum0中计算的结果来计算每一块的 S S I M SSIM SSIM。

函数ssim_end4()展示了如何利用 b l o c k ( i − 1 , j ) block(i-1,j) block(i−1,j), b l o c k ( i − 1 , j + 1 ) block(i-1,j+1) block(i−1,j+1), b l o c k ( i , j ) block(i,j) block(i,j), b l o c k ( i , j + 1 ) block(i,j+1) block(i,j+1)的sums信息来计算 S S I M ( x i j , y i j ) SSIM(x_{ij},y_{ij}) SSIM(xij,yij):

  1. 先对4个块的sums结果进行加和处理,得到 8 × 8 8\times8 8×8块的sums结果
  2. 利用该 8 × 8 8\times8 8×8块的sums来计算 b l o c k ( i , j ) block(i,j) block(i,j)的 S S I M SSIM SSIM
    源码中ssim_end1()展示了如何利用 8 × 8 8\times8 8×8块的sums信息来计算 S S I M SSIM SSIM。具体的计算方法如下。
    将红色区块 b l o c k ( i , j ) block(i,j) block(i,j)的图像放大一点,如图3所示。我们接下来计算其 S S I M SSIM SSIM。

    图3: b l o c k ( i , j ) block(i,j) block(i,j)的示意图

在计算时,首先将4个区块的sums值求和,得到 8 × 8 8\times8 8×8区块的sums值,分别为:

利用如上的公式对 S S I M SSIM SSIM的公式进行计算可以得到:

FFmpeg源码中,对 C 1 C_1 C1和 C 2 C_2 C2的定义中的因子64或63也是根据上面的公式,但是从公式看,FFmpeg对ssim_c1的计算少乘了64:

为简化计算,FFmpeg还做了如下的定义:

最终在FFmpeg中,计算 S S I M SSIM SSIM的公式为:

如上公式就是源码的函数ssim_end1()中最终的计算方式。

利用各块的SSIM计算图像的SSIM

计算完所有块的 S S I M SSIM SSIM之后,所有块的平均 S S I M SSIM SSIM作为该图像的 S S I M SSIM SSIM

编码过程中的技巧

FFmpeg计算 S S I M SSIM SSIM的实现中,为提升效率和抽象代码逻辑,利用很多的编程技巧,如:

  1. 计算YUV各分量图像宽度时用w >> !!i
  2. 为了避免对第0行的特殊处理,采用两层循环来处理
  3. 计算每一行的各块的sums信息时,为了降低循环次数,每次循环计算2个块的sums结果,ssim_4x4x2_core的函数名可能就是这么来的。
  4. 计算每一行的各块的 S S I M SSIM SSIM时,为了降低循环次数,每次循环计算4个块的 S S I M SSIM SSIM,源码中的ssim_end4的函数名可能就是这么来的。
相关推荐
MonkeyKing_sunyuhua8 小时前
FFmpeg将mp4的文件转化为m4a
ffmpeg
zanglengyu10 小时前
RK3568硬解码并与Qt界面融合显示深入探究
开发语言·qt·ffmpeg·rk3568硬解码rtsp
橘子味的茶二1 天前
ffmpeg内存模型
ffmpeg
TPCloud1 天前
windows 11编译安装ffmpeg(包含ffplay)
windows·ffmpeg·源码安装·mysys
runing_an_min2 天前
ffmpeg视频滤镜:缓入缓出-fade
ffmpeg·音视频·fade·缓出·缓入
ssslar3 天前
FFMPEG录屏(22)--- Linux 下基于X11枚举所有显示屏,并获取大小和截图等信息
linux·运维·ffmpeg
MonkeyKing_sunyuhua3 天前
FFmpeg 怎么裁剪m4a的音频,从一个时间点开始,裁剪15秒钟的视频
ffmpeg·音视频
DO_Community3 天前
教程:FFmpeg结合GPU实现720p至4K视频转换
ffmpeg·音视频
x66ccff3 天前
使用NVIDIA GPU加速FFmpeg视频压制:完全指南
ffmpeg·音视频
冷眼Σ(-᷅_-᷄๑)3 天前
如何使用ffmpeg命令行进行录屏
ffmpeg