天天看點

matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

本文主要介紹了灰階直方圖相關的處理,包括以下幾個方面的内容:

  • 利用OpenCV計算圖像的灰階直方圖,并繪制直方圖曲線
  • 直方圖均衡化的原理及實作
  • 直方圖規定化(比對)的原理及實作

圖像的灰階直方圖

一幅圖像由不同灰階值的像素組成,圖像中灰階的分布情況是該圖像的一個重要特征。圖像的灰階直方圖就描述了圖像中灰階分布情況,能夠很直覺的展示出圖像中各個灰階級所占的多少。

圖像的灰階直方圖是灰階級的函數,描述的是圖像中具有該灰階級的像素的個數:其中,橫坐标是灰階級,縱坐标是該灰階級出現的頻率。

matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

不過通常會将縱坐标歸一化到[0,1]區間内,也就是将灰階級出現的頻率(像素個數)除以圖像中像素的總數。灰階直方圖的計算公式如下:

matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

其中,rk是像素的灰階級,nk是具有灰階rk的像素的個數,MN是圖像中總的像素個數。

OpenCV灰階直方圖的計算

直方圖的計算是很簡單的,無非是周遊圖像的像素,統計每個灰階級的個數。在OpenCV中封裝了直方圖的計算函數calcHist,為了更為通用該函數的參數有些複雜,其聲明如下:

void calcHist( const Mat* images, int nimages,                          const int* channels, InputArray mask,                          OutputArray hist, int dims, const int* histSize,                          const float** ranges, bool uniform = true, bool accumulate = false );
           

該函數能夠同時計算多個圖像,多個通道,不同灰階範圍的灰階直方圖. 其參數如下

  • images,輸入圖像的數組,這些圖像要有相同大大小,相同的深度(CV_8U CV_16U CV_32F).
  • nimages ,輸入圖像的個數
  • mask,可選的掩碼,不使用時可設為空。要和輸入圖像具有相同的大小,在進行直方圖計算的時候,隻會統計該掩碼不為0的對應像素
  • hist,輸出的直方圖
  • dims,直方圖的次元
  • histSize,直方圖每個次元的大小
  • ranges,直方圖每個次元要統計的灰階級的範圍
  • uniform,是否進行歸一化,預設為true
  • accumulate,累積标志,預設值為false。

為了計算的靈活性和通用性,OpenCV的灰階直方圖提供了較多的參數,但對于隻是簡單的計算一幅灰階圖的直方圖的話,又顯得較為累贅。這裡對calcHist進行一次封裝,能夠友善的得到一幅灰階圖直方圖。

class Histogram1D{private:    int histSize[1]; // 項的數量    float hranges[2]; // 統計像素的最大值和最小值    const float* ranges[1];    int channels[1]; // 僅計算一個通道public:    Histogram1D()    {        // 準備1D直方圖的參數        histSize[0] = 256;        hranges[0] = 0.0f;        hranges[1] = 255.0f;        ranges[0] = hranges;        channels[0] = 0;    }    MatND getHistogram(const Mat &image)    {        MatND hist;        // 計算直方圖        calcHist(&image ,// 要計算圖像的            1,                // 隻計算一幅圖像的直方圖            channels,        // 通道數量            Mat(),            // 不使用掩碼            hist,            // 存放直方圖            1,                // 1D直方圖            histSize,        // 統計的灰階的個數            ranges);        // 灰階值的範圍        return hist;    }    Mat getHistogramImage(const Mat &image)    {        MatND hist = getHistogram(image);        // 最大值,最小值        double maxVal = 0.0f;        double minVal = 0.0f;        minMaxLoc(hist, &minVal, &maxVal);        //顯示直方圖的圖像        Mat histImg(histSize[0], histSize[0], CV_8U, Scalar(255));        // 設定最高點為nbins的90%        int hpt = static_cast(0.9 * histSize[0]);        //每個條目繪制一條垂直線        for (int h = 0; h < histSize[0]; h++)        {            float binVal = hist.at(h);            int intensity = static_cast(binVal * hpt / maxVal);            // 兩點之間繪制一條直線            line(histImg, Point(h, histSize[0]), Point(h, histSize[0] - intensity), Scalar::all(0));        }        return histImg;    }};
           

Histogram1D提供了兩個方法:getHistogram傳回統計直方圖的數組,預設計算的灰階範圍是[0,255];getHistogramImage将圖像的直方圖以線條的形式畫出來,并傳回包含直方圖的圖像。測試代碼如下:

Histogram1D hist;    Mat histImg;    histImg = hist.getHistogramImage(image);    imshow("Image", image);    imshow("Histogram", histImg);
           
matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

直方圖均衡化 Histogram Equalization

假如圖像的灰階分布不均勻,其灰階分布集中在較窄的範圍内,使圖像的細節不夠清晰,對比度較低。通常采用直方圖均衡化及直方圖規定化兩種變換,使圖像的灰階範圍拉開或使灰階均勻分布,進而增大反差,使圖像細節清晰,以達到增強的目的。

直方圖均衡化,對圖像進行非線性拉伸,重新配置設定圖像的灰階值,使一定範圍内圖像的灰階值大緻相等。這樣,原來直方圖中間的峰值部分對比度得到增強,而兩側的谷底部分對比度降低,輸出圖像的直方圖是一個較為平坦的直方圖。

均衡化算法

直方圖的均衡化實際也是一種灰階的變換過程,将目前的灰階分布通過一個變換函數,變換為範圍更寬、灰階分布更均勻的圖像。也就是将原圖像的直方圖修改為在整個灰階區間内大緻均勻分布,是以擴大了圖像的動态範圍,增強圖像的對比度。通常均衡化選擇的變換函數是灰階的累積機率,直方圖均衡化算法的步驟:

  • 計算原圖像的灰階直方圖
matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

,其中n為像素總數,Nk為灰階級Sk的像素個數

  • 計算原始圖像的累積直方圖
matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結
matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

其中Dj為目的圖像的像素,

matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

是源圖像灰階為i的累積分布,L是圖像中最大灰階級(灰階圖為255)

其代碼實作如下:

  • 在上面中封裝了求灰階直方圖的類,這裡直接應用該方法得到圖像的灰階直方圖;
  • 将灰階直方圖進行歸一化,計算灰階的累積機率;
  • 建立灰階變化的查找表
  • 應用查找表,将原圖像變換為灰階均衡的圖像

具體代碼如下:

void equalization_self(const Mat &src, Mat &dst){    Histogram1D hist1D;    MatND hist = hist1D.getHistogram(src);    hist /= (src.rows * src.cols); // 對得到的灰階直方圖進行歸一化    float cdf[256] = { 0 }; // 灰階的累積機率    Mat lut(1, 256, CV_8U); // 灰階變換的查找表    for (int i = 0; i < 256; i++)    {        // 計算灰階級的累積機率        if (i == 0)            cdf[i] = hist.at(i);        else            cdf[i] = cdf[i - 1] + hist.at(i);        lut.at(i) = static_cast(255 * cdf[i]); // 建立灰階的查找表    }    LUT(src, lut, dst); // 應用查找表,進行灰階變化,得到均衡化後的圖像}
           

上面代碼隻是加深下對均衡化算法流程的了解,實際在OpenCV中也提供了灰階均衡化的函數equalizeHist,該函數的使用很簡單,隻有兩個參數:輸入圖像,輸出圖像。下圖為,上述代碼計算得到的均衡化結果和調用equalizeHist的結果對比

matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

最左邊為原圖像,中間為OpenCV封裝函數的結果,右邊為上面代碼得到的結果。

直方圖規定化

從上面可以看出,直方圖的均衡化自動的确定了變換函數,可以很友善的得到變換後的圖像,但是在有些應用中這種自動的增強并不是最好的方法。有時候,需要圖像具有某一特定的直方圖形狀(也就是灰階分布),而不是均勻分布的直方圖,這時候可以使用直方圖規定化。

直方圖規定化,也叫做直方圖比對,用于将圖像變換為某一特定的灰階分布,也就是其目的的灰階直方圖是已知的。這其實和均衡化很類似,均衡化後的灰階直方圖也是已知的,是一個均勻分布的直方圖;而規定化後的直方圖可以随意的指定,也就是在執行規定化操作時,首先要知道變換後的灰階直方圖,這樣才能确定變換函數。規定化操作能夠有目的的增強某個灰階區間,相比于,均衡化操作,規定化多了一個輸入,但是其變換後的結果也更靈活。

  • 将原始圖像的灰階直方圖進行均衡化,得到一個變換函數

s = T(r)

其中s是均衡化後的像素,r是原始像素

  • 對規定的直方圖進行均衡化,得到一個變換函數

v = G(z)

其中v是均衡化後的像素,z是規定化的像素

  • 上面都是對同一圖像的均衡化,其結果應該是相等的,
matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

詳解規定化過程

對圖像進行直方圖規定化操作,原始圖像的直方圖和以及規定化後的直方圖是已知的。假設

Pr(r)

表示原始圖像的灰階機率密度,Pz(z)表示規定化圖像的灰階機率密度,(r和z分别是原始圖像的灰階級,規定化後圖像的灰階級)。

  • 對原始圖像進行均衡化操作,則有
matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結
  • 對規定化的直方圖進行均衡化操作,則
matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結
  • 由于是對同一圖像的均衡化操作,是以有
matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結
  • 規定化操作的目的就是找到原始圖像的像素sk sk 到規定化後圖像像素的zk之間的一個映射。有了上一步的等式後,可以得到sk=G(zk),是以要想找到sk想對應的zk隻需要在z進行疊代,找到使式子G(zm)−sk的絕對值最小即可。
  • 上述描述隻是理論的推導過程,在實際的計算過程中,不需要做兩次的均衡化操作,具體的推導過程如下:
matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

上面公式表示,假如$s_k$ 規定化後的對應灰階是$z_m$的話,需要滿足的條件是$s_k$的累積機率和$z_m$的累積機率是最接近的。 下面是一個具體計算的例子:

matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

首先得到原直方圖的各個灰階級的累積機率$V_s$以及規定化後直方圖的各個灰階級的累積機率$V_z$,那麼确定$s_k$到$z_m$之間映射關系的條件就是:$$mid V_s - V_z mid$$的值最小。 以$k = 2$為例,其原始直方圖的累積機率是:0.65,在規定化後的直方圖的累積機率中和0.65最接近(相等)的是灰階值為5的累積機率密度,則可以得到原始圖像中的灰階級2,在規定化後的圖像中的灰階級是5。

直方圖規定化的實作

直方圖規定化的實作可以分為一下三步:

  • 計算原圖像的累積直方圖
  • 計算規定直方圖的累積直方圖
  • 計算兩累積直方圖的內插補點的絕對值
  • 根據累積直方圖內插補點建立灰階級的映射

具體代碼實作如下:

void hist_specify(const Mat &src, const Mat &dst,Mat &result){    Histogram1D hist1D;    MatND src_hist = hist1D.getHistogram(src);    MatND dst_hist = hist1D.getHistogram(dst);    float src_cdf[256] = { 0 };    float dst_cdf[256] = { 0 };    // 源圖像和目标圖像的大小不一樣,要将得到的直方圖進行歸一化處理    src_hist /= (src.rows * src.cols);    dst_hist /= (dst.rows * dst.cols);    // 計算原始直方圖和規定直方圖的累積機率    for (int i = 0; i < 256; i++)    {        if (i == 0)        {            src_cdf[i] = src_hist.at(i);            dst_cdf[i] = dst_hist.at(i);        }        else        {            src_cdf[i] = src_cdf[i - 1] + src_hist.at(i);            dst_cdf[i] = dst_cdf[i - 1] + dst_hist.at(i);        }    }    // 累積機率的內插補點    float diff_cdf[256][256];    for (int i = 0; i < 256; i++)        for (int j = 0; j < 256; j++)            diff_cdf[i][j] = fabs(src_cdf[i] - dst_cdf[j]);    // 建構灰階級映射表    Mat lut(1, 256, CV_8U);    for (int i = 0; i < 256; i++)    {        // 查找源灰階級為i的映射灰階        // 和i的累積機率內插補點最小的規定化灰階        float min = diff_cdf[i][0];        int index = 0;        for (int j = 1; j < 256; j++)        {            if (min > diff_cdf[i][j])            {                min = diff_cdf[i][j];                index = j;            }        }        lut.at(i) = static_cast(index);    }    // 應用查找表,做直方圖規定化    LUT(src, lut, result);}
           

上面函數的第二個參數的直方圖就是規定化的直方圖。代碼比較簡單,這裡就不一一解釋了。其結果如下:

matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

左邊是原圖像,右邊是規定化的圖像,也就是上面函數的第一個和第二個輸入參數。原圖像規定化的結果如下:

matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

原圖像規定化後的直方圖和規定化的圖像的直方圖的形狀比較類似, 并且原圖像規定化後整幅圖像的特征和規定化的圖像也比較類似,例如:原圖像床上的被子,明顯帶有規定化圖像中水的波紋特征。

直方圖規定化過程中,在做灰階映射的時候,有兩種常用的方法:

  • 單映射 Single Mapping Law,SML,這種方法也是上面使用的方法,根據累積直方圖的內插補點,從原圖像中找到其在規定化圖像中的映射。
  • 組映射 Group Mapping Law,GML 這種方法較上述方法複雜不少,但是處理效果較好。

對于GML的映射方法,一直沒有很好的了解,但是根據其算法描述實作了該方法,代碼這裡先不放出,其處理結果如下:

matlab灰階直方圖均衡化_圖像的灰階直方圖、直方圖均衡化、直方圖規定化(比對)圖像的灰階直方圖OpenCV灰階直方圖的計算直方圖均衡化 Histogram Equalization均衡化算法直方圖規定化詳解規定化過程直方圖規定化的實作總結

其結果較SML來說更為亮一些,床上的波浪特征也更為明顯,但是其直方圖形狀,和規定化的直方圖對比,第一個峰不是很明顯。

總結

  • 圖像的灰階直方圖能夠很直覺的展示圖像中灰階級的整體分布情況,對圖像的後續處理有很好的指導作用。
  • 直方圖的均衡化的是将一幅圖像的直方圖變平,使各個灰階級的趨于均勻分布,這樣能夠很好的增強圖像對比度。直方圖均衡化是一種自動化的變換,僅需要輸入圖像,就能夠确定圖像的變換函數。但是直方圖的均衡化操作也有一定的确定,在均衡化的過程中對圖像中的資料不加選擇,這樣有可能會增強圖像的背景;變換後圖像的灰階級減少,有可能造成某些細節的消失;會壓縮圖像直方圖中的高峰,造成處理後圖像對比度的不自然等。
  • 直方圖規定化,也稱為直方圖比對,經過規定化處理将原圖像的直方圖變換為特定形狀的直方圖(上面中的示例,就是将圖像的直方圖變換為另一幅圖像的直方圖)。它可以按照預先設定的它可以按照預先設定的某個形狀來調整圖像的直方圖,運用均衡化原理的基礎上,通過建立原始圖像和期望圖像