天天看點

圖像品質評價1 簡介

深度學習中,圖檔的品質往往決定了結果如何,這裡抄了幾種方法

1 簡介

圖像算法評估 = 定性(主觀,觀察) + 定量(客觀,特征值) + 算法時間

  •     定性:主要是觀察+分析
  •     定量:主要是各參數名額,又分為 參考品質+非參考品質
  1.     參考品質:處理後的圖和原圖之間的相關品質度量,比如對比度提升,輪廓複原率,過飽和率,結構相似度, PSN, SSIM, RMSE and UIQ
  2.     非參考品質:圖像本身的一些名額,e, σ, r and CNR

2  圖像品質評價

2.1  圖像品質主觀評價

  •   絕對評價
  •   相對評價

2.2  圖像品質客觀評價

2.2.1 參考品質

        A)基于圖像像素統計基礎:計算待評圖像和和參考圖像對應像素點灰階值之間的差異,從統計角度衡量圖像品質優劣。待評圖像未F,參考圖像為R,大小都為M*N。

  • PSNR,峰值信噪比Peak Signal to Noise Ratio

PSNR值越大,表明待評圖像與參考圖像之間的失真較小,圖像品質較好。

psnr是“Peak Signal to Noise Ratio”的縮寫,即峰值信噪比,是一種評價圖像的客觀标準,它具有局限性,一般是用于最大值信号和背景噪音之間的一個工程項目。

PSNR是最普遍,最廣泛使用的評鑒畫質的客觀量測法,不過許多實驗結果都顯示,PSNR的分數無法和人眼看到的視覺品質完全一緻,有可能PSNR較高者看起來反而比PSNR較低者差。這是因為人眼的視覺對于誤差的敏感度并不是絕對的,其感覺結果會受到許多因素的影響而産生變化(例如:人眼對空間頻率較低的對比差異敏感度較高,人眼對亮度對比差異的敏感度較色度高,人眼對一個區域的感覺結果會受到其周圍鄰近區域的影響)https://www.cnblogs.com/qrlozte/p/5340216.html

圖像品質評價1 簡介
  • MSE,均方誤差

均方誤差(mean-square error, MSE)是反映估計量與被估計量之間差異程度的一種度量。

https://stackoverflow.com/questions/20271479/what-does-it-mean-to-get-the-mse-mean-error-squared-for-2-images

    MSE,均方誤差,Mean Squared Error。MSE值越小,表明圖像品質越好。

圖像品質評價1 簡介

缺點:從圖像像素值的全局統計出發,未考慮人眼的局部視覺因素,是以對圖像局部品質無法把握。

注:部分參考資料中,對上述兩個公式采用多通道處理。

B)基于資訊論基礎:基于資訊論中的資訊熵基礎,提出

  • 視覺資訊保真度(Visual Information Fidelity, VIF)

VIF是Sheikh等結合自然圖像統計模型、圖像失真模型和人眼視覺系統模型提出的圖像品質評價名額.

與峰值信噪比(Peak Signal-to-Noise Ratio, PSNR)、結構相似性(Structural Similarity, SSIM)等名額相比,VIF與主觀視覺有更高的一緻性。其值越大,表明圖像品質越好。

  •  IFC,資訊保真度準則,Information Fidelity Criterion

通過計算待評圖像和參考圖像之間的互資訊來衡量圖像的品質優劣。擴充了圖像與人眼之間的聯系。

缺點:對圖像的結構資訊沒有反應。

C)基于結構資訊基礎:提出者認為圖像的結構失真的度量應是圖像感覺品質的最好近似。在此基礎上提出了結構相似性度量。

    SSIM,結構相似度,Structure Similarity。

SSIM(structural similarity index),結構相似性,是一種衡量兩幅圖像相似度的名額。該名額首先由德州大學奧斯丁分校的圖像和視訊工程實驗室(Laboratory for Image and Video Engineering)提出。

SSIM使用的兩張圖像中,一張為未經壓縮的無失真圖像,另一張為失真後的圖像.其中值的範圍在0~1之間,1為完全一緻,0為完全不一至。http://blog.csdn.net/chaipp0607/article/details/70160307

假設兩幅給定M*N的圖像為X,Y,其中X的均值,标準差,及X與Y的協方差分别用ux,σx,σxy 表示,定義了亮度、對比度和結構的比較函數分别為

圖像品質評價1 簡介

其中正常數C1,C2,C3,用來調節分母接近0時的不穩定性,這三個成分因素綜合起來就是SSIM名額。

圖像品質評價1 簡介

SSIM值越大,圖像品質越好,該名額算法實作簡單,品質評估效果比較可靠。

半參考,也叫部分參考,Reduced-Reference,RR

2.2.2 無參考

也叫盲評價,blind quality,No-Reference,NR,由于理想圖像很難擷取,是以這種完全脫離了對理想參考圖像依賴的品質評估方法應用較為廣泛,無參考方法一般都是基于圖像統計特征。

A)均值:圖像像素的平均值,反應圖像的平均亮度,平均亮度越大,圖像品質越好,

圖像品質評價1 簡介

B)标準差:圖像像素灰階值相對于均值的離散程度,标準差越大,表明圖像中灰階級分布越散,圖像品質頁就越好。

圖像品質評價1 簡介

C)平均梯度(mean gradient):反應圖像中細節反差和紋理變化,他在一定程度上反應圖像的清晰度。

指圖像的邊界或影線兩側附近灰階有明顯差異,即灰階變化率大,這種變化率的大小可用來表示圖像清晰度。

它反映了圖像微小細節反差變化的速率,即圖像多元方向上密度變化的速率,表征圖像的相對清晰程度。

 一般而言,評價梯度越大,圖像層次越多,也就越清晰。

圖像品質評價1 簡介

表示像素點(i,j)在x上的一階差分,ΔyF(i,j)

表示該點在y方向上的一階差分。該公式有待商榷!

D) 資訊熵:

圖像資訊熵也是圖像品質評價的常用名額,它從資訊論的角度反映圖像資訊豐富程度。通常情況下,圖像資訊熵越大

其資訊量就越豐富,品質越好。

指圖像的平均資訊量從資訊論的角度衡量圖像中資訊的多少,資訊熵越大,說明圖像包含的資訊越多。假設圖像中各個像素點的灰階值之間時互相獨立的,圖像的灰階分布為p={p1,p2,…..,pi,…….pn},其中Pi表示灰階值為i的像素的個數與總像素個數之比,而n為灰階級總數,則計算公式為

圖像品質評價1 簡介

P(l)為灰階值l在圖像中出現的機率,L為圖像的灰階等級,如256灰階等級的圖像,L=255.

3 圖像評價參數代碼實作

實驗需要以下資料:MSE,PSNR,SSIM,mean、std、gradient、entropy。

/*
 單幅圖像資訊熵計算
 定義中,圖像的資訊熵通常采用灰階圖計算
 */
double entropy(Mat & img)
{
    double temp[256] = { 0.0f };
    // 計算每個像素的累積值
    int row = img.rows;
    int col = img.cols;
    for (int r = 0; r<row; r++)
    {   
        for (int c = 0; c<col; c++)
        {
            const uchar * i = img.ptr<uchar>(r,c);
            temp[*i] ++;
        }
    }

    // 計算每個像素的機率
    int size = row * col;
    for (int i = 0; i<256; i++)
    {
        temp[i] = temp[i] / size;
    }

    double result = 0.0f;
    // 計算圖像資訊熵
    for (int i = 0; i<256; i++)
    {
        if (temp[i] != 0.0) {
            result += temp[i] * log2(temp[i]);
        }
    }
    return -result;
}

/*
計算平均梯度
梯度的計算應采用灰階圖
公式?通用的都是 sqrt( (dx^2 + dy^2) /2  )
筆記中從書《數字圖像處理及應用――謝鳳英》摘錄的公式有待商榷
*/
double meanGradient(Mat & grayImg) {
    if (grayImg.channels() != 1) {
        printf("avgGradient 參數錯誤,必須輸入單通道圖!");
        return 0.0;
    }
    // 原灰階圖轉換成浮點型資料類型
    Mat src;
    grayImg.convertTo(src, CV_64FC1);

    double temp = 0.0f;
    // 由于求一階差分的邊界問題,這裡行列都要-1
    int rows = src.rows - 1;
    int cols = src.cols - 1;

    // 根據公式計算平均梯度
    for (int r = 0; r < rows; r++)
    {
        for (int c = 0; c < cols; c++)
        {
            // 離散的delta就是相鄰的離散點的內插補點
            double dx = src.at<double>(r, c + 1) - src.at<double>(r, c);
            double dy = src.at<double>(r + 1, c) - src.at<double>(r, c);
            double ds = sqrt((dx*dx + dy * dy) / 2);
            temp += ds;
        }
    }
    double imageAVG = temp / (rows*cols);

    return imageAVG;
}

/*計算灰階圖的均值和方差*/
void mean_std(const Mat & grayImg, double & mean, double & std) {
    if (grayImg.channels() != 1) {
        printf("mean_std 參數錯誤,必須輸入單通道圖!");
        return ;
    }
    Mat mat_mean, mat_stddev;
    meanStdDev(grayImg, mat_mean, mat_stddev);
    mean = mat_mean.at<double>(0, 0);
    std = mat_stddev.at<double>(0, 0);
}


double getMSE(const Mat & src1, const Mat & src2)
{
    Mat s1;
    absdiff(src1, src2, s1);    // |src1 - src2|
    s1.convertTo(s1, CV_32F);   // 不能在8位矩陣上做平方運算
    s1 = s1.mul(s1);            // |src1 - src2|^2
    Scalar s = sum(s1);         // 疊加每個通道的元素

    double result = 0.0f;
    int ch = s1.channels();
    for (int i = 0; i < ch; i++) {
        // 疊加所有通道
        result += s.val[i];
    }

    if (result <= 1e-10) // 如果值太小就直接等于0
        return 0;
    else
        return result / (ch*s1.total());
}


double getPSNR(const Mat& src1, const Mat& src2, double MSE) {
    if (MSE <= 1e-10) {
        return 0;
    }
    return 10.0*log10((255 * 255) / MSE);
}



double getMSSIM(const Mat& src1, const Mat& src2)
{
    // 參數由經驗公式取得
    // C1=(K1*L)^2, C2=(K2*L)^2, C3=C2/2, 一般地K1=0.01, K2=0.03, L=255( 是像素值的動态範圍,一般都取為255)
    const double C1 = 6.5025, C2 = 58.5225;
    const int TYPE = CV_32F;

    // 不能在單位元組類型上計算,範圍溢出,需要轉換
    Mat I1, I2;
    src1.convertTo(I1, TYPE);
    src2.convertTo(I2, TYPE);

    Mat I2_2 = I2.mul(I2);  // I2^2
    Mat I1_2 = I1.mul(I1);  // I1^2
    Mat I1_I2 = I1.mul(I2); // I1*I2

    // 高斯函數計算圖像的均值、方差以及協方差,而不是采用周遊像素點的方式,以換來更高的效率
    Mat mu1, mu2;
    GaussianBlur(I1, mu1, Size(11, 11), 1.5);
    GaussianBlur(I2, mu2, Size(11, 11), 1.5);
    Mat mu1_2 = mu1.mul(mu1);
    Mat mu2_2 = mu2.mul(mu2);
    Mat mu1_mu2 = mu1.mul(mu2);
    Mat sigma1_2, sigma2_2, sigma12;
    GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);
    sigma1_2 -= mu1_2;
    GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);
    sigma2_2 -= mu2_2;
    GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);
    sigma12 -= mu1_mu2;
    Mat t1, t2, t3;
    t1 = 2 * mu1_mu2 + C1;
    t2 = 2 * sigma12 + C2;
    t3 = t1.mul(t2);
    t1 = mu1_2 + mu2_2 + C1;
    t2 = sigma1_2 + sigma2_2 + C2;
    t1 = t1.mul(t2);
    Mat ssim_map;
    divide(t3, t1, ssim_map);
    Scalar SSIM = mean(ssim_map);
    // 傳回三個通道的SSIM的平均值,[0,1]之間
    return (SSIM.val[2] + SSIM.val[1] + SSIM.val[0]) / 3 ;
}