掘金 人工智能 05月22日
图像质量评价详解
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入探讨了图像质量评价的各种方法,包括峰值信噪比(PSNR)、结构相似性(SSIM)、均方误差(MSE)和视觉信息保真度(VIF)。PSNR通过计算均方误差衡量图像失真,SSIM评估图像结构保持程度,MSE计算像素差异,VIF则基于人类视觉系统特性评估图像质量。此外,还介绍了无需参考图像的质量评价方法,这些方法通过分析图像的自然统计特性来评估质量。文章提供了C++和Python代码示例,方便读者理解和应用。

📈峰值信噪比(PSNR)通过计算原始图像和失真图像之间的均方误差(MSE),并转换为分贝(dB)值来衡量图像的失真程度。PSNR值越高,代表图像失真越小,质量越好。文章提供了PSNR的数学表达式以及C++和Python的代码实现。

🧩结构相似性(SSIM)不仅考虑像素值的差异,还考虑了图像的结构信息,用于评估图像结构保持程度。SSIM的取值范围是0到1,值越大表示图像结构相似度越高,质量越好。文章同样给出了SSIM的数学表达式以及C++和Python的代码实现。

📐均方误差(MSE)用于计算两个图像之间的像素差异,是最基本的图像质量评价指标,也是PSNR计算的基础。MSE值越小,表示图像差异越小,质量越好。文章提供了MSE的数学表达式以及C++和Python的代码实现。

👁️视觉信息保真度(VIF)基于自然场景统计和人类视觉系统特性,评估图像质量,考虑了图像中的信息量以及这些信息在失真过程中的保留程度。文章给出了VIF的数学表达式和C++、Python代码示例。

👓无参考质量评价不需要参考图像就能评估图像质量,通过分析图像的自然统计特性来评估质量,主要方法包括基于自然场景统计、基于图像特征分析和基于深度学习。文章提供了基于C++的NIQE(自然图像质量评估器)的代码实现。

图像质量评价详解 🔍

图像质量评价就像是数字世界的"品质鉴定师"!通过各种"鉴定工具"和"评价标准",我们可以对图像质量进行专业评估,就像鉴定师对艺术品进行专业鉴定一样。让我们一起来探索这个神奇的图像"鉴定工作室"吧!

目录

1. 峰值信噪比(PSNR)

PSNR就像是"信噪比测量仪",用于衡量图像失真程度。它通过计算原始图像和失真图像之间的均方误差(MSE),然后转换为分贝(dB)值来表示。

数学表达式:

PSNR=10log10(MAXI2MSE)PSNR = 10 \cdot \log_{10}\left(\frac{MAX_I^2}{MSE}\right)

其中:

代码实现(C++):

double compute_psnr(const Mat& src1, const Mat& src2) {    CV_Assert(src1.size() == src2.size());    CV_Assert(src1.type() == src2.type());    Mat diff;    absdiff(src1, src2, diff);    diff.convertTo(diff, CV_64F);    multiply(diff, diff, diff);    double mse = mean(diff)[0];    if(mse < EPSILON) return INFINITY;    double max_val = 255.0;  // Assume 8-bit image    return 20 * log10(max_val) - 10 * log10(mse);}

代码实现(Python):

def compute_psnr(img1: np.ndarray, img2: np.ndarray) -> float:    """计算峰值信噪比(PSNR)    Args:        img1: 第一张图像        img2: 第二张图像    Returns:        float: PSNR值(dB)    """    # 确保图像大小相同    assert img1.shape == img2.shape    # 计算均方误差(MSE)    mse = np.mean((img1.astype(np.float32) - img2.astype(np.float32)) ** 2)    # 避免除以0    if mse == 0:        return float('inf')    # 计算PSNR    max_pixel = 255.0    psnr = 20 * np.log10(max_pixel) - 10 * np.log10(mse)    return psnr

2. 结构相似性(SSIM)

SSIM就像是"结构相似度分析仪",用于评估图像结构保持程度。它不仅考虑像素值的差异,还考虑了图像的结构信息。

数学表达式:

SSIM(x,y)=(2μxμy+c1)(2σxy+c2)(μx2+μy2+c1)(σx2+σy2+c2)SSIM(x,y) = \frac{(2\mu_x\mu_y + c_1)(2\sigma_{xy} + c_2)}{(\mu_x^2 + \mu_y^2 + c_1)(\sigma_x^2 + \sigma_y^2 + c_2)}

其中:

代码实现(C++):

double compute_ssim(    const Mat& src1,    const Mat& src2,    int window_size) {    CV_Assert(src1.size() == src2.size());    CV_Assert(src1.type() == src2.type());    // 转换为浮点数    Mat img1, img2;    src1.convertTo(img1, CV_64F);    src2.convertTo(img2, CV_64F);    // 计算局部统计量    Mat mu1, mu2, sigma1, sigma2;    compute_local_stats(img1, mu1, sigma1, window_size);    compute_local_stats(img2, mu2, sigma2, window_size);    // 计算协方差    Mat mu1_mu2, sigma12;    multiply(img1, img2, sigma12);    filter2D(sigma12, sigma12, CV_64F, create_gaussian_kernel(window_size, window_size/6.0));    multiply(mu1, mu2, mu1_mu2);    sigma12 -= mu1_mu2;    // 计算SSIM    double C1 = (K1 * 255) * (K1 * 255);    double C2 = (K2 * 255) * (K2 * 255);    Mat ssim_map;    multiply(2*mu1_mu2 + C1, 2*sigma12 + C2, ssim_map);    Mat denom;    multiply(mu1.mul(mu1) + mu2.mul(mu2) + C1,            sigma1 + sigma2 + C2, denom);    divide(ssim_map, denom, ssim_map);    return mean(ssim_map)[0];}

代码实现(Python):

def compute_ssim(img1: np.ndarray, img2: np.ndarray,                window_size: int = 11) -> float:    """计算结构相似性(SSIM)    Args:        img1: 第一张图像        img2: 第二张图像        window_size: 窗口大小    Returns:        float: SSIM值(0-1之间,越大越好)    """    # 确保图像大小相同    assert img1.shape == img2.shape    # 转换为浮点数    img1 = img1.astype(np.float32)    img2 = img2.astype(np.float32)    # 创建高斯窗口    window = gaussian_filter(np.ones((window_size, window_size)),                           sigma=1.5)    window = window / np.sum(window)    # 计算均值    mu1 = signal.convolve2d(img1, window, mode='valid')    mu2 = signal.convolve2d(img2, window, mode='valid')    # 计算方差和协方差    mu1_sq = mu1 * mu1    mu2_sq = mu2 * mu2    mu1_mu2 = mu1 * mu2    sigma1_sq = signal.convolve2d(img1 * img1, window, mode='valid') - mu1_sq    sigma2_sq = signal.convolve2d(img2 * img2, window, mode='valid') - mu2_sq    sigma12 = signal.convolve2d(img1 * img2, window, mode='valid') - mu1_mu2    # SSIM参数    C1 = (0.01 * 255) ** 2    C2 = (0.03 * 255) ** 2    # 计算SSIM    ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / \               ((mu1_sq + mu2_sq + C1) * (sigma1_sq + sigma2_sq + C2))    return np.mean(ssim_map)

3. 均方误差(MSE)

MSE就像是"误差测量尺",用于计算两个图像之间的像素差异。它是PSNR计算的基础,也是最基本的图像质量评价指标。

数学表达式:

MSE=1MNi=1Mj=1N[I(i,j)K(i,j)]2MSE = \frac{1}{MN}\sum_{i=1}^M\sum_{j=1}^N[I(i,j) - K(i,j)]^2

其中:

代码实现(C++):

double compute_mse(const Mat& src1, const Mat& src2) {    CV_Assert(src1.size() == src2.size());    CV_Assert(src1.type() == src2.type());    Mat diff;    absdiff(src1, src2, diff);    diff.convertTo(diff, CV_64F);    multiply(diff, diff, diff);    return mean(diff)[0];}

代码实现(Python):

def compute_mse(img1: np.ndarray, img2: np.ndarray) -> float:    """计算均方误差(MSE)    Args:        img1: 第一张图像        img2: 第二张图像    Returns:        float: MSE值    """    # 确保图像大小相同    assert img1.shape == img2.shape    # 计算MSE    mse = np.mean((img1.astype(np.float32) - img2.astype(np.float32)) ** 2)    return mse

4. 视觉信息保真度(VIF)

VIF就像是"视觉保真度检测仪",它基于自然场景统计和人类视觉系统特性,评估图像质量。VIF考虑了图像中的信息量,以及这些信息在失真过程中的保留程度。

数学表达式:

VIF=jsubbandsI(CjN;FjNsjN)jsubbandsI(CjN;EjNsjN)VIF = \frac{\sum_{j\in\text{subbands}} I(C_j^N;F_j^N|s_j^N)}{\sum_{j\in\text{subbands}} I(C_j^N;E_j^N|s_j^N)}

其中:

代码实现(C++):

double compute_vif(    const Mat& src1,    const Mat& src2,    int num_scales) {    CV_Assert(src1.size() == src2.size());    CV_Assert(src1.type() == src2.type());    // 转换为浮点型    Mat ref, dist;    src1.convertTo(ref, CV_64F);    src2.convertTo(dist, CV_64F);    double vif = 0.0;    double total_bits = 0.0;    // 多尺度分解    for(int scale = 0; scale < num_scales; scale++) {        // 计算局部统计量        Mat mu1, mu2, sigma1, sigma2;        compute_local_stats(ref, mu1, sigma1, 3);        compute_local_stats(dist, mu2, sigma2, 3);        // 计算互信息        Mat g = sigma2 / (sigma1 + EPSILON);        Mat sigma_n = 0.1 * sigma1;  // 假设噪声方差        Mat bits_ref, bits_dist;        log(1 + sigma1/(sigma_n + EPSILON), bits_ref);        log(1 + g.mul(g).mul(sigma1)/(sigma_n + EPSILON), bits_dist);        vif += sum(bits_dist)[0];        total_bits += sum(bits_ref)[0];        // 降采样        if(scale < num_scales-1) {            pyrDown(ref, ref);            pyrDown(dist, dist);        }    }    return vif / total_bits;}

代码实现(Python):

def compute_vif(img1: np.ndarray, img2: np.ndarray, num_scales: int = 4) -> float:    """计算视觉信息保真度(VIF)    Args:        img1: 第一张图像        img2: 第二张图像        num_scales: 尺度数量    Returns:        float: VIF值    """    # 转换为浮点数    img1 = img1.astype(np.float32)    img2 = img2.astype(np.float32)    vif = 0.0    total_bits = 0.0    # 多尺度分解    for scale in range(num_scales):        # 计算局部统计量        mu1 = gaussian_filter(img1, sigma=1.5)        mu2 = gaussian_filter(img2, sigma=1.5)        sigma1 = gaussian_filter(img1**2, sigma=1.5) - mu1**2        sigma2 = gaussian_filter(img2**2, sigma=1.5) - mu2**2        sigma12 = gaussian_filter(img1*img2, sigma=1.5) - mu1*mu2        # 计算互信息        g = sigma2 / (sigma1 + 1e-10)        sigma_n = 0.1 * sigma1  # 假设噪声方差        bits_ref = np.log2(1 + sigma1/(sigma_n + 1e-10))        bits_dist = np.log2(1 + g**2 * sigma1/(sigma_n + 1e-10))        vif += np.sum(bits_dist)        total_bits += np.sum(bits_ref)        # 降采样        if scale < num_scales-1:            img1 = cv2.pyrDown(img1)            img2 = cv2.pyrDown(img2)    return vif / total_bits

5. 无参考质量评价

无参考质量评价就像是"独立鉴定师",不需要参考图像就能评估图像质量。它通过分析图像的自然统计特性来评估质量。

主要方法:

    基于自然场景统计基于图像特征分析基于深度学习

代码实现(C++):

double compute_niqe(const Mat& src, int patch_size) {    // 转换为灰度图    Mat gray;    cvtColor(src, gray, COLOR_BGR2GRAY);    gray.convertTo(gray, CV_64F);    // 提取局部特征    vector<double> features;    int stride = patch_size/2;    for(int i = 0; i <= gray.rows-patch_size; i += stride) {        for(int j = 0; j <= gray.cols-patch_size; j += stride) {            Mat patch = gray(Rect(j,i,patch_size,patch_size));            // 计算局部统计量            Scalar mean, stddev;            meanStdDev(patch, mean, stddev);            // 计算偏度和峰度            double m3 = 0, m4 = 0;            Mat centered = patch - mean[0];            Mat centered_pow3, centered_pow4;            pow(centered, 3, centered_pow3);            m3 = sum(centered_pow3)[0] / (patch_size * patch_size);            pow(centered, 4, centered_pow4);            m4 = sum(centered_pow4)[0] / (patch_size * patch_size);            double skewness = m3 / pow(stddev[0], 3);            double kurtosis = m4 / pow(stddev[0], 4) - 3;            features.push_back(mean[0]);            features.push_back(stddev[0]);            features.push_back(skewness);            features.push_back(kurtosis);        }    }    // 计算特征均值和协方差    int rows = static_cast<int>(features.size() / 4);    Mat feat_mat(rows, 4, CV_64F);    for(int i = 0; i < rows; i++) {        for(int j = 0; j < 4; j++) {            feat_mat.at<double>(i, j) = features[i*4 + j];        }    }    Mat mean, cov;    calcCovarMatrix(feat_mat, cov, mean, COVAR_NORMAL | COVAR_ROWS);    // 计算与MVG模型的距离    Mat diff = feat_mat - repeat(mean, feat_mat.rows, 1);    Mat dist = diff * cov.inv() * diff.t();    // 提取对角线元素    Mat diagonal;    diagonal.create(1, dist.rows, CV_64F);    for(int i = 0; i < dist.rows; i++) {        diagonal.at<double>(0, i) = dist.at<double>(i, i);    }    // 正确计算对角线元素的均值    double mean_val = cv::mean(diagonal)[0];    return sqrt(mean_val);}

代码实现(Python):

def no_reference_quality_assessment(img: np.ndarray) -> float:    """无参考质量评估    Args:        img: 输入图像    Returns:        float: 质量分数(0-1之间,越大越好)    """    # 计算图像梯度    sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)    sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)    # 计算梯度幅值    gradient_magnitude = np.sqrt(sobelx**2 + sobely**2)    # 计算局部对比度    local_contrast = np.std(gradient_magnitude)    # 计算图像熵    hist = cv2.calcHist([img], [0], None, [256], [0, 256])    hist = hist / np.sum(hist)    entropy = -np.sum(hist * np.log2(hist + 1e-10))    # 计算噪声水平    noise = np.std(img - cv2.GaussianBlur(img, (5, 5), 0))    # 综合评分    score = (local_contrast * 0.4 + entropy * 0.3 + (1 - noise/255) * 0.3)    return np.clip(score, 0, 1)

注意事项

    图像预处理

      在进行质量评价前,确保输入图像已经过适当的预处理(如去噪、对齐等)对于彩色图像,建议先转换为灰度图再进行评价注意图像尺寸的一致性,必要时进行缩放

    评价指标选择

      PSNR适合评估压缩质量,但对结构失真不敏感SSIM更适合评估结构相似性,计算量较大MSE计算简单但与人眼感知相关性较差VIF计算复杂但更符合人眼感知无参考评价适合实时应用,但准确性较低

    性能优化

      对于大尺寸图像,考虑使用ROI(感兴趣区域)进行评价可以使用多线程或GPU加速计算对于实时应用,可以降低采样率或使用快速算法

    实际应用建议

      根据具体应用场景选择合适的评价指标可以组合多个指标进行综合评价定期验证评价结果的准确性考虑评价指标的计算效率

总结

图像质量评价就像是数字世界的"品质鉴定师"!通过客观评价指标、主观评价方法和无参考质量评价等"鉴定工具",我们可以对图像质量进行专业评估。在实际应用中,需要根据具体场景选择合适的"鉴定方案",就像鉴定师根据不同艺术品选择不同的鉴定方法一样。

记住:好的图像质量评价就像是一个经验丰富的"鉴定师",既要准确评估,又要考虑实际应用需求!🔍

参考资料

    Wang Z, et al. Image quality assessment: from error visibility to structural similarity[J]. TIP, 2004Sheikh H R, et al. A statistical evaluation of recent full reference image quality assessment algorithms[J]. TIP, 2006Mittal A, et al. No-reference image quality assessment in the spatial domain[J]. TIP, 2012Zhang L, et al. FSIM: A feature similarity index for image quality assessment[J]. TIP, 2011OpenCV官方文档: docs.opencv.org/更多资源: IP101项目主页

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

图像质量评价 PSNR SSIM MSE VIF
相关文章