熱線(xian)電話:0755-23712116
郵箱:contact@legoupos.cn
地址(zhi):深圳市寶安區沙(sha)井街道后(hou)亭茅洲山工業(ye)園工業(ye)大(da)廈全至科(ke)技創新園科(ke)創大(da)廈2層2A
本文主(zhu)要介紹了灰度直(zhi)方圖相關的處理(li),包括以下(xia)幾個方面的內容:
? 利(li)用OpenCV計(ji)算圖(tu)(tu)像的灰度(du)直方圖(tu)(tu),并繪(hui)制直方圖(tu)(tu)曲線
? 直方圖均(jun)衡化的原(yuan)理及實現
? 直方(fang)圖規定化(匹配)的原理及實現
圖像的灰度直方圖
一幅圖像由不同灰度值的像素組成,圖像中灰度的分布情況是該圖像的一個重要特征。圖像的灰度直方圖就描述了圖像中灰度分布情況,能夠很直觀的展示出圖像中各個灰度級所占的多少。
圖像的灰度直方圖是灰度級的函數,描述的是圖像中具有該灰度級的像素的個數:其中,橫坐標是灰度級,縱坐標是該灰度級出現的頻率。
不過通常會將縱坐標歸一化到區間內,也就是(shi)將灰度級出現(xian)的頻率(像(xiang)素個(ge)數)除以圖像(xiang)中像(xiang)素的總數。灰度直方圖的計算公式如(ru)下(xia):
其中,是像素的灰度級,
是具有灰度
的像素的個數,
是圖像中總的像素個數。
OpenCV灰度直方圖的計算
直方(fang)圖(tu)的(de)計(ji)算(suan)是(shi)很簡單(dan)的(de),無(wu)非是(shi)遍(bian)歷圖(tu)像(xiang)的(de)像(xiang)素,統(tong)計(ji)每個(ge)灰度級的(de)個(ge)數。在OpenCV中封裝(zhuang)了直方(fang)圖(tu)的(de)計(ji)算(suan)函(han)數calcHist,為(wei)(wei)了更為(wei)(wei)通用該(gai)函(han)數的(de)參數有些復雜(za),其(qi)聲明如(ru)下:
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,輸入圖(tu)像的數組,這些圖(tu)像要有相同大大小(xiao),相同的深度(CV_8U CV_16U CV_32F).
? nimages ,輸(shu)入圖像的個數
? channels,要計(ji)算直(zhi)方圖的通道個數。
? mask,可選的掩(yan)碼,不使(shi)用時(shi)可設(she)為(wei)(wei)空(kong)。要(yao)和輸入圖像具有相同的大小(xiao),在進行直方圖計算的時(shi)候,只會統計該掩(yan)碼不為(wei)(wei)0的對應(ying)像素
? hist,輸出的直(zhi)方圖
? dims,直方圖的(de)維度
? histSize,直方圖每個維度的(de)大小
? ranges,直方圖(tu)每個維度要(yao)統(tong)計的灰(hui)度級的范(fan)圍(wei)
? uniform,是否進行歸一(yi)化,默認(ren)為true
? accumulate,累(lei)積標志(zhi),默(mo)認值為false。
為(wei)了計算(suan)的(de)靈活性和通(tong)用性,OpenCV的(de)灰度(du)直方圖(tu)(tu)(tu)(tu)提供了較(jiao)多(duo)的(de)參數,但(dan)對于(yu)只是簡單的(de)計算(suan)一(yi)幅(fu)灰度(du)圖(tu)(tu)(tu)(tu)的(de)直方圖(tu)(tu)(tu)(tu)的(de)話,又(you)顯(xian)得較(jiao)為(wei)累贅。這里對calcHist進行一(yi)次(ci)封裝(zhuang),能(neng)夠方便的(de)得到一(yi)幅(fu)灰度(du)圖(tu)(tu)(tu)(tu)直方圖(tu)(tu)(tu)(tu)。
class Histogram1D
{
private:
int histSize[1]; // 項的(de)數(shu)量
float hranges[2]; // 統計像素(su)的(de)最大值和最小值
const float* ranges[1];
int channels[1]; // 僅計算一(yi)個通道
public:
Histogram1D()
{
// 準備1D直方圖的參(can)數
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, // 只計算一幅圖(tu)像的直(zhi)方圖(tu)
channels, // 通道數量
Mat(), // 不使用掩(yan)碼
hist, // 存放直方(fang)圖
1, // 1D直方(fang)圖(tu)
histSize, // 統(tong)計的灰度的個數
ranges); // 灰度值的范(fan)圍
return hist;
}
Mat getHistogramImage(const Mat &image)
{
MatND hist = getHistogram(image);
// 最大值,最小(xiao)值
double maxVal = 0.0f;
double minVal = 0.0f;
minMaxLoc(hist, &minVal, &maxVal);
//顯示(shi)直方(fang)圖(tu)的(de)圖(tu)像(xiang)
Mat histImg(histSize[0], histSize[0], CV_8U, Scalar(255));
// 設(she)置最高(gao)點(dian)為nbins的90%
int hpt = static_cast<int>(0.9 * histSize[0]);
//每個(ge)條目(mu)繪制一條垂直線
for (int h = 0; h < histSize[0]; h++)
{
float binVal = hist.at<float>(h);
int intensity = static_cast<int>(binVal * hpt / maxVal);
// 兩(liang)點之間繪制一條(tiao)直線(xian)
line(histImg, Point(h, histSize[0]), Point(h, histSize[0] - intensity), Scalar::all(0));
}
return histImg;
}
};
Histogram1D提供(gong)了兩個方(fang)(fang)法:getHistogram返回統計直(zhi)方(fang)(fang)圖的數組,默認(ren)計算(suan)的灰度范圍是[0,255];getHistogramImage將圖像的直(zhi)方(fang)(fang)圖以線條的形式(shi)畫出來,并返回包含(han)直(zhi)方(fang)(fang)圖的圖像。測試代碼如下(xia):
Histogram1D hist;
Mat histImg;
histImg = hist.getHistogramImage(image);
imshow("Image", image);
imshow("Histogram", histImg);
其結果如下:
直方圖均衡化 Histogram Equalization
假如圖像的灰度分布不均勻,其灰度分布集中在較窄的范圍內,使圖像的細節不夠清晰,對比度較低。通常采用直方圖均衡化及直方圖規定化兩種變換,使圖像的灰度范圍拉開或使灰度均勻分布,從而增大反差,使圖像細節清晰,以達到增強的目的。
直(zhi)方(fang)圖(tu)(tu)(tu)(tu)(tu)均衡化(hua),對(dui)圖(tu)(tu)(tu)(tu)(tu)像(xiang)進(jin)行非線性拉伸,重(zhong)新(xin)分配圖(tu)(tu)(tu)(tu)(tu)像(xiang)的(de)灰度(du)值(zhi),使一(yi)定(ding)范圍內圖(tu)(tu)(tu)(tu)(tu)像(xiang)的(de)灰度(du)值(zhi)大致相等。這樣,原來直(zhi)方(fang)圖(tu)(tu)(tu)(tu)(tu)中(zhong)間的(de)峰值(zhi)部分對(dui)比度(du)得到增強,而兩側的(de)谷底部分對(dui)比度(du)降低,輸出圖(tu)(tu)(tu)(tu)(tu)像(xiang)的(de)直(zhi)方(fang)圖(tu)(tu)(tu)(tu)(tu)是一(yi)個較為平(ping)坦的(de)直(zhi)方(fang)圖(tu)(tu)(tu)(tu)(tu)。
均衡化算法
直方圖的均衡化實際也是一種灰度的變換過程,將當前的灰度分布通過一個變換函數,變換為范圍更寬、灰度分布更均勻的圖像。也就是將原圖像的直方圖修改為在整個灰度區間內大致均勻分布,因此擴大了圖像的動態范圍,增強圖像的對比度。通常均衡化選擇的變換函數是灰度的累積概率,直方(fang)圖(tu)均衡化(hua)算法的步驟:
? 計算原圖像的灰度直方圖 ,其中
為像素總數,
為灰度級
的像素個數
? 計算原始圖像的累積直方圖
? ,其中
是目的圖像的像素,
是源圖(tu)像灰度(du)為(wei)i的累(lei)積分布,L是圖(tu)像中最大(da)灰度(du)級(ji)(灰度(du)圖(tu)為(wei)255)
其代碼實現如下:
? 在上面中封裝了求灰(hui)度直(zhi)方圖(tu)(tu)的(de)類(lei),這里直(zhi)接應用該方法得到圖(tu)(tu)像(xiang)的(de)灰(hui)度直(zhi)方圖(tu)(tu);
? 將灰度直方圖進(jin)行歸一化,計算灰度的累積概率;
? 創建灰度變化的查(cha)找(zhao)表
? 應(ying)用查找表,將(jiang)原圖像(xiang)變換(huan)為(wei)灰度均衡的圖像(xiang)
具體代碼如下:
void equalization_self(const Mat &src, Mat &dst)
{
Histogram1D hist1D;
MatND hist = hist1D.getHistogram(src);
hist /= (src.rows * src.cols); // 對得到(dao)的灰度直方圖進行歸(gui)一化
float cdf[256] = { 0 }; // 灰(hui)度的(de)累(lei)積概(gai)率
Mat lut(1, 256, CV_8U); // 灰度變(bian)換的查找(zhao)表
for (int i = 0; i < 256; i++)
{
// 計算灰(hui)度級的累積概率
if (i == 0)
cdf[i] = hist.at<float>(i);
else
cdf[i] = cdf[i - 1] + hist.at<float>(i);
lut.at(i) = static_cast(255 * cdf[i]); // 創建灰度的查找表
}
LUT(src, lut, dst); // 應用查找表,進行灰度(du)變化,得(de)到(dao)均衡(heng)化后的圖像
}
上面代碼只是加深下對均衡化算法流程的理解,實際在OpenCV中也提供了灰度均衡化的函數equalizeHist,該函數的使用很簡單,只有兩個參數:輸入圖像,輸出圖像。下圖為,上述代碼計算得到的均衡化結果和調用equalizeHist的結果對比
最左邊(bian)為(wei)(wei)原圖像,中間為(wei)(wei)OpenCV封裝函數的(de)結果,右邊(bian)為(wei)(wei)上面代碼得(de)到(dao)的(de)結果。
直方圖規定化
從上面可以看出,直方圖的均衡化自動的確定了變換函數,可以很方便的得到變換后的圖像,但是在有些應用中這種自動的增強并不是最好的方法。有時候,需要圖像具有某一特定的直方圖形狀(也就是灰度分布),而不是均勻分布的直方圖,這時候可以使用直方圖規定化。
直(zhi)方(fang)圖(tu)規(gui)定(ding)化(hua),也(ye)(ye)叫做直(zhi)方(fang)圖(tu)匹配(pei),用于將圖(tu)像變換(huan)(huan)為某一特定(ding)的(de)(de)(de)灰(hui)度(du)分布,也(ye)(ye)就是(shi)(shi)其(qi)目(mu)的(de)(de)(de)的(de)(de)(de)灰(hui)度(du)直(zhi)方(fang)圖(tu)是(shi)(shi)已(yi)知的(de)(de)(de)。這其(qi)實和均衡(heng)化(hua)很類似,均衡(heng)化(hua)后的(de)(de)(de)灰(hui)度(du)直(zhi)方(fang)圖(tu)也(ye)(ye)是(shi)(shi)已(yi)知的(de)(de)(de),是(shi)(shi)一個(ge)均勻分布的(de)(de)(de)直(zhi)方(fang)圖(tu);而(er)規(gui)定(ding)化(hua)后的(de)(de)(de)直(zhi)方(fang)圖(tu)可以隨意的(de)(de)(de)指定(ding),也(ye)(ye)就是(shi)(shi)在執行規(gui)定(ding)化(hua)操作時,首先要(yao)知道(dao)變換(huan)(huan)后的(de)(de)(de)灰(hui)度(du)直(zhi)方(fang)圖(tu),這樣才(cai)能確定(ding)變換(huan)(huan)函數。規(gui)定(ding)化(hua)操作能夠有目(mu)的(de)(de)(de)的(de)(de)(de)增強某個(ge)灰(hui)度(du)區間,相比于,均衡(heng)化(hua)操作,規(gui)定(ding)化(hua)多了一個(ge)輸(shu)入,但是(shi)(shi)其(qi)變換(huan)(huan)后的(de)(de)(de)結果也(ye)(ye)更靈活。
在理解了上(shang)述的(de)(de)均衡(heng)化(hua)(hua)(hua)過程(cheng)后(hou),直方圖的(de)(de)規定(ding)化(hua)(hua)(hua)也較為(wei)簡(jian)單(dan)。可(ke)以利用均衡(heng)化(hua)(hua)(hua)后(hou)的(de)(de)直方圖作(zuo)為(wei)一(yi)個中間過程(cheng),然后(hou)求取規定(ding)化(hua)(hua)(hua)的(de)(de)變換函數。具體步驟如下:
? 將原始圖像的灰度直方圖進行均衡化,得到一個變換函數,其中s是(shi)(shi)均衡化后的像素(su),r是(shi)(shi)原始像素(su)
? 對規定的直方圖進行均衡化,得到一個變換函數,其中v是(shi)均衡化后(hou)的像素,z是(shi)規定化的像素
? 上面都是對同一圖像的均衡化,其結果應該是相等的,,且
通過,均衡化作為中間結果,將得到原始像素和
規定化后像素之間的映射(she)關系。
詳解規定化過程
對圖像進行直方圖規定化操作,原始圖像的直方圖和以及規定化后的直方圖是已知的。假設表示原始圖像的灰度概率密度,
表示規(gui)定化圖(tu)(tu)像的灰(hui)度(du)(du)概率密度(du)(du)(r和z分別是原(yuan)始圖(tu)(tu)像的灰(hui)度(du)(du)級(ji),規(gui)定化后(hou)圖(tu)(tu)像的灰(hui)度(du)(du)級(ji))。
? 對原始圖像進行均衡化操作,則有
? 對規定化的直方圖進行均衡化操作,則
? 由于是對同一圖像的均衡化操作,所以有。
? 規定化操作的目的就是找到原始圖像的像素到規定化后圖像像素的
之間的一個映射。有了上一步的等式后,可以得到
,因此要想找到
相對應的
只需要在
進行迭代,找到使式子
的絕對值最小即可。
? 上述描述只是理論的推導過程,在實際的計算過程中,不需要做兩次的均衡化操作,具體的推導過程如下:$$
文章轉自Brook_icv //www.cnblogs.com/wangguchangqing/p/7098213.html