Histogram-灰度直方圖

前言

什么是直方圖?

直方圖是對(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ù)

創(chuàng)建直方圖類(lèi)

那我說(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)單

直方圖均衡化

那么效果怎樣呢?

均衡化和沒(méi)有均衡化直方圖

基本邏輯:將一張圖像均衡化,然后輸出顯示。

圖像均衡化

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).

說(shuō)是給了四張圖,correlation = 0.816

??解釋一下吧

卡爾·皮爾遜 相關(guān)性

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次?

??解釋一下吧:

一維卡方檢測(cè)

我覺(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)這里

計(jì)算方法

HISTCMP_HELLINGER

在概率論和統(tǒng)計(jì)理論中,Hellinger距離被用來(lái)度量?jī)蓚€(gè)概率分布的相似度。它是f散度的一種(f散度——度量?jī)蓚€(gè)概率分布相似度的指標(biāo))

我現(xiàn)在都不敢解釋這些算法了??

總之,這些屬性都是來(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ì)比度。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容