前言
什么是直方圖?
直方圖是對(duì)數(shù)據(jù)的集合做統(tǒng)計(jì),并將統(tǒng)計(jì)結(jié)果分布于一系列預(yù)定義的bins中。
例如:?
如果我按照某種方式去統(tǒng)計(jì)通道中的這些數(shù)字,會(huì)發(fā)生什么情況呢?既然以知數(shù)字的范圍是包含256個(gè)色值(這里是8bit無(wú)符號(hào)四通道圖像 2^8 = 256),我們可以將這個(gè)范圍分割成子區(qū)域(稱(chēng)作 bins), 如:
[0, 255] = { [0, 15] U [16, 31]U ....U[240,255] }?
range = { bin_{1} U bin_{2} U ....U bin_{n = 15} }
然后在統(tǒng)計(jì)掉入每個(gè)bin中的像素?cái)?shù)目。采用這一方法來(lái)統(tǒng)計(jì)上面的數(shù)字矩陣,我們可以得到下圖:(x軸表示bin,y軸表示各個(gè)bin中的像素個(gè)數(shù))。
以上只是一個(gè)說(shuō)明直方圖如何工作以及它的用處的簡(jiǎn)單示例。直方圖可以統(tǒng)計(jì)的不僅僅是顏色灰度, 它可以統(tǒng)計(jì)任何圖像特征 (如 梯度, 方向等等)。
讓我們?cè)賮?lái)搞清楚直方圖的一些具體細(xì)節(jié):
dims: 需要統(tǒng)計(jì)的特征的數(shù)目, 在上例中, dims = 1 因?yàn)槲覀儍H僅統(tǒng)計(jì)了灰度值(灰度圖像)。
bins: 每個(gè)特征空間 子區(qū)段 的數(shù)目,在上例中, bins = 16
range: 每個(gè)特征空間的取值范圍,在上例中, range = [0,255]
怎樣去統(tǒng)計(jì)兩個(gè)特征呢? 在這種情況下, 直方圖就是3維的了,x軸和y軸分別代表一個(gè)特征, z軸是掉入 (bin_{x}, bin_{y}) 組合中的樣本數(shù)目。 同樣的方法適用于更高維的情形 (當(dāng)然會(huì)變得很復(fù)雜。
OpenCV的直方圖計(jì)算
OpenCV提供了一個(gè)簡(jiǎn)單的計(jì)算數(shù)組集(通常是圖像或分割后的通道)的直方圖函數(shù) calcHist 。 支持高達(dá) 32 維的直方圖。下面的代碼演示了如何使用該函數(shù)計(jì)算直方圖!
基本的邏輯就是將一張圖像通道化,計(jì)算各通道圖像的直方圖并返回顯示。
首先將UIImage對(duì)象轉(zhuǎn)成OpenCV Mat 數(shù)據(jù)結(jié)構(gòu):
Mat img = [FaceDetection CVMatFromUIImage:image];//這段代碼OpenCV已經(jīng)寫(xiě)好了
然后我們需要將Mat圖像數(shù)據(jù)通道化:
cv::split(img, img_channels);
CV_EXPORTS void split(const Mat& src, Mat* mvbegin);
@param src input multi-channel array.
@param mvbegin output array; the number of arrays must match src.channels(); the arrays themselves arereallocated, if needed.
意思就是傳一個(gè)多通道圖像,傳出一個(gè)裝載各通道的數(shù)組。
接著就需要通過(guò)直方圖CvHistogram類(lèi)來(lái)處理每一個(gè)通道數(shù)據(jù)。
CVAPI(CvHistogram*)? cvCreateHist( int dims, int* sizes, int type,float** ranges CV_DEFAULT(NULL),int uniform CV_DEFAULT(1));API是有這個(gè)函數(shù)??
@param dims Number of histogram dimensions.這參數(shù)前言中已經(jīng)提到過(guò)。
@param sizes Array of the histogram dimension sizes. 就相當(dāng)于 bins?
@param type Histogram representation format. CV_HIST_ARRAY means that the histogram data is?represented as a multi-dimensional dense array CvMatND. CV_HIST_SPARSE means that histogram data?is represented as a multi-dimensional sparse array CvSparseMat.直方圖疏密程度
@param ranges Array of ranges for the histogram bins. Its meaning depends on the uniform parameter?value. The ranges are used when the histogram is calculated or backprojected to determine which .
@param uniform.....這里看都不用看了??因?yàn)橥ㄟ^(guò)我的實(shí)驗(yàn)OpenCV 3.2里只有下邊這個(gè)函數(shù)
那我說(shuō)如果我?guī)拙托枰肦ange uniform這些呢?
CVAPI(void)? cvSetHistBinRanges( CvHistogram* hist, float** ranges,int uniform CV_DEFAULT(1));
cvSetHistBinRanges(CvHistogram *hist, float **ranges)
又騙我???。我感覺(jué)它這些函數(shù)有規(guī)律的,只要有CV_DEFAULT的這些參數(shù)的,就不需要填,它知道你也填DEFAULT,就幫你填好了,當(dāng)然你填了就調(diào)用的你填的參數(shù),很強(qiáng)!
接下來(lái)就需要調(diào)用Histogram類(lèi)的計(jì)算直方圖方法:
CVAPI(void)? cvCalcArrHist( CvArr** arr, CvHistogram* hist,int accumulate CV_DEFAULT(0),const CvArr* mask CV_DEFAULT(NULL) );/** @overload */
CV_INLINE? void? cvCalcHist( IplImage** image, CvHistogram* histint accumulate CV_DEFAULT(0),const CvArr* mask CV_DEFAULT(NULL) ){
cvCalcArrHist( (CvArr**)image, hist, accumulate, mask );
}
給了一個(gè)重載方法。我們用重載函數(shù)就好了。需要說(shuō)的是 CvArr,IplImage,CvMat,其實(shí)是一個(gè)東西,它自己沒(méi)說(shuō),但確實(shí)有人說(shuō)了??:
§ CvArr -This is the "metatype" used only as a function parameter.
It denotes that the function accepts arrays of multiple types, such as IplImage*, CvMat* or even CvSeq* sometimes. The particular array type is determined at runtime by analyzing the first 4 bytes of the header. In C++ interface the role of CvArr is played by InputArray and OutputArray.
我們就可以這樣想:到這里channel里的圖像數(shù)據(jù)已經(jīng)被Histogram做好Collection了,現(xiàn)在需要做的就是拿出bins繪制圖像。需要注意的是,在IplImage結(jié)構(gòu)體中有這樣一個(gè)屬性int origin.
int? origin;? ? ? ? ? ? /**< 0 - top-left origin,1 - bottom-left origin (Windows bitmaps style).? */我是這樣理解的:你給我的圖片有可能是從下邊開(kāi)始計(jì)算的,不一定所有的IplImage都是從左上角開(kāi)始計(jì)算的。
然后就比如我現(xiàn)在創(chuàng)建一個(gè)畫(huà)布:
IplImage *image = cvCreateImage(cvSize(256, 80), 8, 1);cvSetZero(image);
獲取bins開(kāi)始繪圖。
float histValue? ? = cvGetReal1D(hist->bins, i);
float histNextVable = cvGetReal1D(hist->bins, i+1);
這個(gè)畫(huà)出來(lái)的圖像如果使用cvFillConvexPoly填充的時(shí)候就是藍(lán)色線條上半部分。
cvFillConvexPoly(image, points, numPts, cvScalar(255));
那畫(huà)下半部分就很簡(jiǎn)單了,將得到第i個(gè)點(diǎn) 使用size Max y - i.bins 就是相反的圖像么。???
OpenCV的直方圖均衡化
直方圖均衡化處理的“中心思想”是把原始圖像的灰度直方圖從比較集中的某個(gè)灰度區(qū)間變成在全部灰度范圍內(nèi)的均勻分布。
使用起來(lái)很簡(jiǎn)單
那么效果怎樣呢?
基本邏輯:將一張圖像均衡化,然后輸出顯示。
po:我突然發(fā)現(xiàn),只要代碼思路清晰,寫(xiě)起代碼很舒服??。
OpenCV的直方圖對(duì)比
其實(shí)對(duì)于直方圖對(duì)比,就是按照enum cv::HistCompMethods標(biāo)準(zhǔn)取相似度。拿出待比對(duì)的bins與基準(zhǔn)圖像的bins求交集嘛??。
就單單兩張相同的圖片,如果調(diào)整一下亮度,相似度就下來(lái)了。
需要注意的是相關(guān)性不能證明因果關(guān)系,盡管它可能符合因果關(guān)系。下面就介紹一下這幾個(gè)Methods??。
HISTCMP_CORREL
Correlation (co-relation) refers to the degree of relationship (or dependency) between two variables.
Linear correlation refers to straight-line relationships between two variables.
A correlation can range between -1 (perfect negative relationship) and +1 (perfect positive relationship), with 0 indicating no straight-line relationship. -出處?學(xué)術(shù)文檔看起來(lái)總是很清晰。
相關(guān)系數(shù)是用以反映變量之間相關(guān)關(guān)系密切程度的統(tǒng)計(jì)指標(biāo).
??解釋一下吧:
HISTCMP_CHISQR
A Pearson's chi-square test can be used as an inferential test of the independence of two nominal variables.出處 這個(gè)屌,尤其是對(duì)例子的解析??。
用來(lái)監(jiān)測(cè)實(shí)際觀測(cè)值與理論推斷值之間的偏離程度。其根本思想就是在于比較理論頻數(shù)和實(shí)際頻數(shù)的吻合程度或擬合優(yōu)度問(wèn)題。
If you wanted to test a die to see whether it’s a fair die, what would you do?
Class Answers: Roll it over and over and see what kind of distribution you get
此處很經(jīng)典,我叫我王牌翻譯來(lái)翻譯一下:
王牌翻譯說(shuō):如果你想要測(cè)試一個(gè)死之人是否害怕死亡你會(huì)怎么做???一遍一遍去實(shí)驗(yàn)。
我覺(jué)得我得把文檔中的這個(gè)example用我的語(yǔ)言Roll一次。
如果你要推測(cè)一場(chǎng)死亡屬于正常死亡,你會(huì)怎么做?讓他再活一次?
假設(shè)我們使他復(fù)活了60次,那你會(huì)用什么樣的理由去接受其中的一次死亡屬于正常死亡?對(duì)數(shù)據(jù)分組 1/6 ?取其中的10次?很顯然這個(gè)方法很愚蠢。本來(lái)60次就不怎么可靠,然后你再去隨機(jī)取其中的10次?
??解釋一下吧:
我覺(jué)得我解釋明白了,如果你還沒(méi)有看明白,點(diǎn)這里吧。
HISTCMP_INTERSECT
這個(gè)就不用說(shuō)了,單單就這個(gè)英文單詞就能解釋?zhuān)航患础?/p>
HISTCMP_BHATTACHARYYA
在統(tǒng)計(jì)中,Bhattacharyya距離測(cè)量?jī)蓚€(gè)離散或連續(xù)概率分布的相似性。它與衡量?jī)蓚€(gè)統(tǒng)計(jì)樣品或種群之間的重疊量的Bhattacharyya系數(shù)密切相關(guān)。原文點(diǎn)這里
HISTCMP_HELLINGER
在概率論和統(tǒng)計(jì)理論中,Hellinger距離被用來(lái)度量?jī)蓚€(gè)概率分布的相似度。它是f散度的一種(f散度——度量?jī)蓚€(gè)概率分布相似度的指標(biāo))
總之,這些屬性都是來(lái)判斷兩組數(shù)據(jù)的相關(guān)性。
總結(jié)
那么圖像直方圖有什么用?其實(shí)我也是百度了好多的文章,說(shuō)的意思很多。
對(duì)圖像進(jìn)行分析、觀察,形成一個(gè)有效的處理方法
就我的理解:
1.對(duì)于純色圖像來(lái)說(shuō),在直方圖中只顯示一條柱狀,一個(gè)bins。
2.對(duì)于圖像來(lái)說(shuō),如果圖像的峰值偏左,bins 集合會(huì)偏向0;相反,如果圖像的峰值偏右,圖像bins集合偏向255;
3.直方圖具有二峰性,這表明這個(gè)圖像有較亮和較暗的區(qū)域。
最重要的一點(diǎn)是這個(gè)可以做特征提取。
我感覺(jué)檢測(cè)某個(gè)圖像中: 是真實(shí)的人臉、還是照片中的人臉,判斷背景區(qū)域的直方圖就好了。如果拿著照片去充當(dāng)人臉,那么直方圖中會(huì)出現(xiàn)多個(gè)峰值。
對(duì)于前景圖像和背景圖像比較接近的圖像可以使用直方圖均衡化,修改對(duì)比度。