http://www.dotblogs.com.tw/v6610688/archive/2013/12/21/emgucv_calculate_histogram_by_densehistogram.aspx
前言
在前篇,提到了我們在做影像處理時會需要擁有影像的直方圖色彩分布資料,來做一些運算,例如:反投影來比對兩張圖象的色彩分布相似度,並且過濾掉不太可能相似的圖像等
在這篇,我們會使用到EmguCV所提供的專門處理直方圖相關工作的DenseHistogram類別
直方圖介紹
直方圖說穿了其實就是資料的統計圖而已,而在影像上常被用來做色彩分布的統計用。
縱軸我們稱它為樣本數量,橫軸則是樣本的屬性值(例如要計算的屬性是抵達的分鐘),縱軸則代表可能抵達的次數)
而在色彩分布上,橫軸是像素點的數值(從0 – 255 ),縱軸則是像素值在這張影像上各有多少一樣的像素點的總值
或許有人會好奇「直方圖」與「長條圖」的差異在哪裡,其中直方圖的的資料是「是連續的」,所以橫軸的數值會是連續的,有一個順序姓
長條圖則是不連續的(又稱類別資料),橫軸的類別只有相同或不同的關聯,沒有順序性(如下是各國國家的類別)
使用EmguCV的DenseHistorgam計算直方圖
這邊我們程式中使用到的loadImg變數是前一個文章所定義EmguCV保存圖片的資料結構
以下這段程式碼
01 | private DenseHistogram CalHistBlue() |
05 | RangeF BRange = new RangeF(0,255); |
06 | DenseHistogram blueHist = new DenseHistogram(Bbin, BRange); |
08 | blueHist.Calculate( new IImage[] { loadImg.Split()[0] }, false , null ); |
在這邊我們計算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)
1 | blueHist.Calculate( new IImage[] { loadImg.Split()[0] }, false , null ); |
最後使用內建直方圖繪製工具,就會出現如下的圖片
直方圖的多通道計算或不同色彩空間
1.多通道
除了計算單的通道外,也可同時計算多通道直方圖
如下是我們計算Blue與Green的程式
01 | private DenseHistogram CalHistBlueGreenHist() { |
03 | int [] BGbins = { 16, 16 }; |
04 | RangeF[] BGRanges = new RangeF[] { new RangeF(0, 255), new RangeF(0, 255) }; |
05 | DenseHistogram bgHist = new DenseHistogram(BGbins, BGRanges); |
07 | bgHist.Calculate( new IImage[] { loadImg.Split()[0], loadImg.Split()[1] }, false , null ); |
因為多了一個Green通道,所以也要去多考慮Green通道的Bin與Range
然後在
1 | bgHist.Calculate( new IImage[] { loadImg.Split()[0], loadImg.Split()[1] }, false , null ); |
我們也要多切割出Green的通道影像資料來計算
2.不同色彩空間計算-HSV色彩空間
HSV色彩空間和RGB的空間分布顏色圖如下
RGB色彩空間: HSV色彩空間:
其中你會看到RGB的色彩分布是混再一起的,單個通道不畫足夠表現出完整的色彩
而HSV(Hue – Saturation - Value)則是把顏色與飽和度還有明暗度分離,所以Hue除了無法表達黑->灰->白以外,其餘的各大色彩足夠表示
借用Wiki的解說
Hue:色相(H)是色彩的基本屬性,就是平常所說的顏色名稱,如紅色、黃色等。(顏色也就是可見光:紅橙黃綠青藍紫)
Saturation :飽和度(S)是指色彩的純度,越高色彩越純,低則逐漸變灰,取0-100%的數值。
Value:明度(V),亮度(L),取0-100%。
所以通常如果你的色彩辨識不希望考慮到明暗度的話,就可以使用HSV空間,並只去辨識一張影像中Hue的色彩分布相似度
以下是HSV色彩空間中的Hue直方圖計算
01 | private DenseHistogram CalHistHueHist() |
05 | RangeF[] HueRanges = new RangeF[] { new RangeF(0, 180) }; |
06 | DenseHistogram hsHist = new DenseHistogram(Huebins, HueRanges); |
08 | 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的色彩空間在做計算
1 | hsHist.Calculate( new IImage[] { loadImg.Convert< Hsv, byte >().Split()[0] }, false , null ); |
然後如下圖會看到色彩分布的圖形不一樣
用有自己繪製的直方圖來看一下會是這樣(和上面的Hue分布很像):
HSV色彩空間中的HS直方圖計算:
01 | private DenseHistogram CalHistHSHist() { |
03 | int [] HSbins = { 8, 16 }; |
04 | RangeF[] HSRanges = new RangeF[] { new RangeF(0, 180), new RangeF(0, 255) }; |
05 | DenseHistogram hsHist = new DenseHistogram(HSbins, HSRanges); |
07 | hsHist.Calculate( new IImage[] { loadImg.Convert< Hsv, byte >().Split()[0], loadImg.Convert< Hsv, byte >().Split()[1] }, false , null ); |
不過....使用DenseHistogram的資料結構如果是多通道的話,無法在HistogramViewer與HistogramBox顯示(試過行不通),所以這邊我用自己會的結果來看
這邊會看到主要色彩分成八大塊,然後每一塊的顏色會有亮度條(共16條)即是飽和度的Bin數量
HelloHistogramForm_calHistogramByDenseHistogram.zip
結論
希望透過這篇文章讓想要使用、計算直方圖的朋友可以更加瞭解,也希望以後可以不要忘了直方圖這基本的影像應用
下一篇會介紹如何使用CvInvoke(直接調用openCV的函式)來計算直方圖
PS:以上文章圖片如果沒有包含本部落格的簽名,皆是取自網路