98 lines
3.3 KiB
C#
98 lines
3.3 KiB
C#
using SixLabors.ImageSharp;
|
|
using SixLabors.ImageSharp.PixelFormats;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using SixLabors.ImageSharp.Processing;
|
|
|
|
namespace VideoAnalysisCore.Common
|
|
{
|
|
/// <summary>
|
|
/// ssim计算器
|
|
/// </summary>
|
|
public class SSIMCalculator
|
|
{
|
|
// SSIM计算常量 (基于8-bit图像范围0-255)
|
|
private const double C1 = (0.01 * 255) * (0.01 * 255);
|
|
private const double C2 = (0.03 * 255) * (0.03 * 255);
|
|
|
|
/// <summary>
|
|
/// 计算连续帧的SSIM 值
|
|
/// </summary>
|
|
/// <param name="img1"></param>
|
|
/// <param name="img2"></param>
|
|
/// <returns>返回阈值 0-1 越小变化越大<para>清晰视频:阈值 0.90-0.95 </para> <para>低质量视频:阈值 0.85-0.90</para></returns>
|
|
public static double CalculateFrameSSIM(Image<Rgb24> img1, Image<Rgb24> img2)
|
|
{
|
|
// 转换为灰度图
|
|
var gray1 = CreateResizedGrayImage(img1);
|
|
var gray2 = CreateResizedGrayImage(img2);
|
|
|
|
// 计算全局统计量
|
|
CalculateStats(gray1, gray2, out double mean1, out double mean2,
|
|
out double var1, out double var2, out double covar);
|
|
|
|
// 计算SSIM分量
|
|
double luminance = (2 * mean1 * mean2 + C1) / (mean1 * mean1 + mean2 * mean2 + C1);
|
|
double contrast = (2 * Math.Sqrt(var1) * Math.Sqrt(var2) + C2) / (var1 + var2 + C2);
|
|
double structure = (covar + C2 / 2) / (Math.Sqrt(var1) * Math.Sqrt(var2) + C2 / 2);
|
|
|
|
// 返回SSIM值 (值越接近1表示越相似)
|
|
return luminance * contrast * structure;
|
|
}
|
|
|
|
private static Image<L8> CreateResizedGrayImage(Image<Rgb24> image)
|
|
{
|
|
return image
|
|
.Clone(x => x.Grayscale())
|
|
.CloneAs<L8>(); // 转换为8位灰度格式
|
|
}
|
|
|
|
private static void CalculateStats(
|
|
Image<L8> img1,
|
|
Image<L8> img2,
|
|
out double mean1,
|
|
out double mean2,
|
|
out double var1,
|
|
out double var2,
|
|
out double covar)
|
|
{
|
|
int width = img1.Width;
|
|
int height = img1.Height;
|
|
int totalPixels = width * height;
|
|
|
|
double sum1 = 0, sum2 = 0;
|
|
double sum1Sq = 0, sum2Sq = 0, sumProduct = 0;
|
|
|
|
// 单次遍历计算所有统计量
|
|
for (int y = 0; y < height; y++)
|
|
{
|
|
for (int x = 0; x < width; x++)
|
|
{
|
|
double val1 = img1[x, y].PackedValue;
|
|
double val2 = img2[x, y].PackedValue;
|
|
|
|
sum1 += val1;
|
|
sum2 += val2;
|
|
sum1Sq += val1 * val1;
|
|
sum2Sq += val2 * val2;
|
|
sumProduct += val1 * val2;
|
|
}
|
|
}
|
|
|
|
// 计算均值
|
|
mean1 = sum1 / totalPixels;
|
|
mean2 = sum2 / totalPixels;
|
|
|
|
// 计算方差: Var(X) = E[X²] - E[X]²
|
|
var1 = (sum1Sq / totalPixels) - (mean1 * mean1);
|
|
var2 = (sum2Sq / totalPixels) - (mean2 * mean2);
|
|
|
|
// 计算协方差: Cov(X,Y) = E[XY] - E[X]E[Y]
|
|
covar = (sumProduct / totalPixels) - (mean1 * mean2);
|
|
}
|
|
}
|
|
}
|