[EmguCV|C#]使用EmguCV的DenseHistogram類別計算與紀錄圖像直方圖-直方圖(Histogram)系列(2)

  • 17177
  • 0
  • C#
  • 2013-12-22

在前篇,提到了我們在做影像處理時會需要擁有影像的直方圖色彩分布資料,來做一些運算,例如:反投影來比對兩張圖象的色彩分布相似度,並且過濾掉不太可能相似的圖像等

在這篇,我們會使用到EmguCV所提供的專門處理直方圖相關工作的DenseHistogram類別

前言

 


 

前篇,提到了我們在做影像處理時會需要擁有影像的直方圖色彩分布資料,來做一些運算,例如:反投影來比對兩張圖象的色彩分布相似度,並且過濾掉不太可能相似的圖像等

在這篇,我們會使用到EmguCV所提供的專門處理直方圖相關工作的DenseHistogram類別

 

直方圖介紹

 


 

直方圖說穿了其實就是資料的統計圖而已,而在影像上常被用來做色彩分布的統計用。

Histogram_of_arrivals_per_minute.svg

縱軸我們稱它為樣本數量,橫軸則是樣本的屬性值(例如要計算的屬性是抵達的分鐘),縱軸則代表可能抵達的次數)

而在色彩分布上,橫軸是像素點的數值(從0 – 255 ),縱軸則是像素值在這張影像上各有多少一樣的像素點的總值

 

或許有人會好奇「直方圖」與「長條圖」的差異在哪裡,其中直方圖的的資料是「是連續的」,所以橫軸的數值會是連續的,有一個順序姓

長條圖則是不連續的(又稱類別資料),橫軸的類別只有相同或不同的關聯,沒有順序性(如下是各國國家的類別)

Incarceration_Rates_Worldwide_ZP.svg

 

 

使用EmguCV的DenseHistorgam計算直方圖

 


 

這邊我們程式中使用到的loadImg變數是前一個文章所定義EmguCV保存圖片的資料結構

以下這段程式碼

private DenseHistogram CalHistBlue()
        {
            //計算Blue單通道
            int Bbin = 8; //切割量化的數量
            RangeF BRange = new RangeF(0,255);
            DenseHistogram blueHist = new DenseHistogram(Bbin, BRange);
            //參數一是要計算的顏色資料,這邊分割通道並取得Blue通道的顏色;依序[1]:Green->[2]:Red
            blueHist.Calculate(new IImage[] { loadImg.Split()[0] }, false, null);
            return blueHist;
        }

在這邊我們計算Blue通道的色彩分布,其中你會看到我們初始化DenseHistogram會需要輸入兩個參數,先看第二個BRange其實就是橫軸的起始數值到最大數值,而0-255剛好就是顏色的像素值範圍,所以我們要統計Blue通道的像素值分布狀況

再來是第一個參數,Bbin-是用來量化的數量,也就是我們可以把直方圖的區間切割出來,這邊設定8,換句話說就是約0-32,33-64,64-96等等這樣切出8個區間,最後只要是像素值在0-32中間的就會落到這個區塊,或像是像素值68會落在64-96這個區間,這樣的目的就是看你的色彩分布要記錄的多細緻,如果我只想要知道大概區塊的色彩,Bbin就可以切小一點

 

而這行則是透過index拿出Blue通道的影像(EmguCV通常使用的順序是Bgr所以index = 0 表示Blue)

blueHist.Calculate(new IImage[] { loadImg.Split()[0] }, false, null);

 

最後使用內建直方圖繪製工具,就會出現如下的圖片

show 8 bin blue channel histogram

 

直方圖的多通道計算或不同色彩空間

 


 

1.多通道

除了計算單的通道外,也可同時計算多通道直方圖

如下是我們計算Blue與Green的程式

private DenseHistogram CalHistBlueGreenHist() {
    //計算Blue-Green單通道
    int[] BGbins = { 16, 16 }; //切割量化的數量
    RangeF[] BGRanges = new RangeF[] { new RangeF(0, 255), new RangeF(0, 255) };
    DenseHistogram bgHist = new DenseHistogram(BGbins, BGRanges);
    //填入Blue-Green通道的顏色圖像
    bgHist.Calculate(new IImage[] { loadImg.Split()[0], loadImg.Split()[1] }, false, null);

    return bgHist;
}

因為多了一個Green通道,所以也要去多考慮Green通道的Bin與Range

然後在

bgHist.Calculate(new IImage[] { loadImg.Split()[0], loadImg.Split()[1] }, false, null);

我們也要多切割出Green的通道影像資料來計算

 

 

2.不同色彩空間計算-HSV色彩空間

HSV色彩空間和RGB的空間分布顏色圖如下

RGB色彩空間:                                                                 HSV色彩空間:

RGB_color_solid_cube      330px-HSV_cone

 

 

其中你會看到RGB的色彩分布是混再一起的,單個通道不畫足夠表現出完整的色彩

而HSV(Hue – Saturation - Value)則是把顏色與飽和度還有明暗度分離,所以Hue除了無法表達黑->灰->白以外,其餘的各大色彩足夠表示

借用Wiki的解說

Hue:色相(H)是色彩的基本屬性,就是平常所說的顏色名稱,如紅色黃色等。(顏色也就是可見光:紅橙黃綠青藍紫)

Saturation :飽和度(S)是指色彩的純度,越高色彩越純,低則逐漸變灰,取0-100%的數值。

Value:明度(V),亮度(L),取0-100%。

 

所以通常如果你的色彩辨識不希望考慮到明暗度的話,就可以使用HSV空間,並只去辨識一張影像中Hue的色彩分布相似度

 

 

以下是HSV色彩空間中的Hue直方圖計算

private DenseHistogram CalHistHueHist()
{
          //計算Hsv的H-S
          int[] Huebins = { 8}; //切割量化的數量{HBin,SBin}
          RangeF[] HueRanges = new RangeF[] { new RangeF(0, 180) }; //H
          DenseHistogram hsHist = new DenseHistogram(Huebins, HueRanges);
          //填入H-S通道的顏色圖像
          hsHist.Calculate(new IImage[] { loadImg.Convert< Hsv, byte >().Split()[0] }, false, null);

}

這邊會看到一個有趣的事情是,色相Hue明明是在0~360度,為何會給他180呢?

因為當我們把色彩空間做轉換後,放到的資料結構預設是8bit,而為了符合在這個大小下,會把Hue/2 => 180度的Range

 

而飽和度Saturation 與明度Value原本的百分比是以(0-1)表示法也會變成0-255

如下是OpenCV中的CvtColor解釋(EmguCV是從新包裝OpenCV,所以核心要看OpenCV):

hsv range in data type

 

另外,以下此行是先轉換到HSV的色彩空間在做計算

hsHist.Calculate(new IImage[] { loadImg.Convert< Hsv, byte >().Split()[0] }, false, null);

 

然後如下圖會看到色彩分布的圖形不一樣

show_hue_blue color

 

用有自己繪製的直方圖來看一下會是這樣(和上面的Hue分布很像):

hsv_h_histogram

 

 

HSV色彩空間中的HS直方圖計算:

private DenseHistogram CalHistHSHist() {
            //計算Hsv的H-S
            int[] HSbins = { 8, 16 }; //切割量化的數量{HBin,SBin}
            RangeF[] HSRanges = new RangeF[] { new RangeF(0, 180), new RangeF(0, 255) }; //H,S
            DenseHistogram hsHist = new DenseHistogram(HSbins, HSRanges);
            //填入H-S通道的顏色圖像
            hsHist.Calculate(new IImage[] { loadImg.Convert< Hsv, byte >().Split()[0], loadImg.Convert< Hsv, byte >().Split()[1] }, false, null);

            return hsHist;
}

不過....使用DenseHistogram的資料結構如果是多通道的話,無法在HistogramViewer與HistogramBox顯示(試過行不通),所以這邊我用自己會的結果來看

這邊會看到主要色彩分成八大塊,然後每一塊的顏色會有亮度條(共16條)即是飽和度的Bin數量

hsv_hs_histogram

 

HelloHistogramForm_calHistogramByDenseHistogram.zip

 

結論

 


 

希望透過這篇文章讓想要使用、計算直方圖的朋友可以更加瞭解,也希望以後可以不要忘了直方圖這基本的影像應用

下一篇會介紹如何使用CvInvoke(直接調用openCV的函式)來計算直方圖

 

PS:以上文章圖片如果沒有包含本部落格的簽名,皆是取自網路

 

 

 

參考資料

http://en.wikipedia.org/wiki/Histogram

http://zh.wikipedia.org/wiki/%E6%9D%A1%E5%BD%A2%E7%BB%9F%E8%AE%A1%E5%9B%BE

http://www.945enet.com.tw/main/elementaryschool.asp?U_BC=MATH&U_CCG=A&U_CC=01&FILE_ID=852

http://zh.wikipedia.org/wiki/File:RGB_color_solid_cube.png

http://zh.wikipedia.org/wiki/HSL%E5%92%8CHSV%E8%89%B2%E5%BD%A9%E7%A9%BA%E9%97%B4

http://zh.wikipedia.org/wiki/%E9%A2%9C%E8%89%B2

http://en.wikipedia.org/wiki/Hue

 


 

文章中的敘述如有觀念不正確錯誤的部分,歡迎告知指正 謝謝 =)

另外要轉載請附上出處 感謝