1. 程式人生 > >直方圖均衡化 原理及其C++程式碼實現

直方圖均衡化 原理及其C++程式碼實現

演算法原理

直方圖均衡化,是對影象進行非線性拉伸,使得一定範圍內畫素值的數量的大致相同。這樣原來直方圖中的封頂部分對比度得到了增強,而兩側波谷的對比度降低,輸出的直方圖是一個較為平坦的分段直方圖。具體來講可以表現為下面這個圖:
在這裡插入圖片描述
通過這種方法可以按照需要對影象的亮度進行調整,並且,這種方法是可逆的,也就是說知道了均衡化函式,就可以恢復原始的直方圖。接下來對原理進行說明:設變數 r r 代表影象中畫素灰度級。對灰度級進行歸一化處理,即 0

< = r < = 1 0<=r<=1 ,其中 r
= 0 r=0
表示黑, r = 1 r=1 表示白。對於一幅給定的圖片來說,每個畫素在 [
0 , 1 ] [0,1]
的灰度級是隨機的,用概率密度 p r ( r ) p_r(r) 來表示影象灰度級的分佈。為了有利於數字影象處理,引入離散形式。在離散形式下,用 r k r^k 代表離散灰度級,用 p r ( r k ) p_r(r^k) 代表 p r ( r ) p_r(r) ,並且下式子成立: P r ( r k ) = n k n P_r(r^k)=\frac{nk}{n} ,其中 0 < = r k < = 1 , k = 0 , 1 , 2 , , n 1 0<=r^k<=1,k=0,1,2,''',n-1 。式子中 n k n^k 代表影象中出現 r k r^k 這種灰度的畫素個數, n n 是影象的總畫素個數,影象進行直方圖均衡化的函式表示式為:
S i = T ( r i ) = i = 0 k 1 n i n S_i=T(r_i)=\sum_{i=0}^{k-1}\frac{n_i}{n} ,式子中,k為灰度級數。相應的反變換為 r i = T 1 ( S i ) r^i=T^{-1}(S_i)

程式碼實現

//直方圖均衡化
Mat Histogramequalization(Mat src) {
    int R[256] = {0};
    int G[256] = {0};
    int B[256] = {0};
    int rows = src.rows;
    int cols = src.cols;
    int sum = rows * cols;
    //統計直方圖的RGB分佈
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            B[src.at<Vec3b>(i, j)[0]]++;
            G[src.at<Vec3b>(i, j)[1]]++;
            R[src.at<Vec3b>(i, j)[2]]++;
        }
    }
    //構建直方圖的累計分佈方程,用於直方圖均衡化
    double val[3] = {0};
    for (int i = 0; i < 256; i++) {
        val[0] += B[i];
        val[1] += G[i];
        val[2] += R[i];
        B[i] = val[0] * 255 / sum;
        G[i] = val[1] * 255 / sum;
        R[i] = val[2] * 255 / sum;
    }
    //歸一化直方圖
    Mat dst(rows, cols, CV_8UC3);
    for(int i = 0; i < rows; i++){
        for(int j = 0; j < cols; j++){
            dst.at<Vec3b>(i, j)[0] = B[src.at<Vec3b>(i, j)[0]];
            dst.at<Vec3b>(i, j)[1] = B[src.at<Vec3b>(i, j)[1]];
            dst.at<Vec3b>(i, j)[2] = B[src.at<Vec3b>(i, j)[2]];
        }
    }
    return dst;
}

效果

在這裡插入圖片描述原圖
在這裡插入圖片描述直方圖均衡化後的圖