熱線電話:0755-23712116
郵箱:contact@shuangyi-tech.com
地址:深圳市寶安區(qū)沙井街道后亭茅洲山工業(yè)園工業(yè)大廈全至科技創(chuàng)新園科創(chuàng)大廈2層2A
本文主要介紹了灰度直方圖相關(guān)的處理,包括以下幾個方面的內(nèi)容:
? 利用OpenCV計(jì)算圖像的灰度直方圖,并繪制直方圖曲線
? 直方圖均衡化的原理及實(shí)現(xiàn)
? 直方圖規(guī)定化(匹配)的原理及實(shí)現(xiàn)
圖像的灰度直方圖
一幅圖像由不同灰度值的像素組成,圖像中灰度的分布情況是該圖像的一個重要特征。圖像的灰度直方圖就描述了圖像中灰度分布情況,能夠很直觀的展示出圖像中各個灰度級所占的多少。
圖像的灰度直方圖是灰度級的函數(shù),描述的是圖像中具有該灰度級的像素的個數(shù):其中,橫坐標(biāo)是灰度級,縱坐標(biāo)是該灰度級出現(xiàn)的頻率。
不過通常會將縱坐標(biāo)歸一化到區(qū)間內(nèi),也就是將灰度級出現(xiàn)的頻率(像素個數(shù))除以圖像中像素的總數(shù)?;叶戎狈綀D的計(jì)算公式如下:
其中,是像素的灰度級,是具有灰度的像素的個數(shù),是圖像中總的像素個數(shù)。
OpenCV灰度直方圖的計(jì)算
直方圖的計(jì)算是很簡單的,無非是遍歷圖像的像素,統(tǒng)計(jì)每個灰度級的個數(shù)。在OpenCV中封裝了直方圖的計(jì)算函數(shù)calcHist,為了更為通用該函數(shù)的參數(shù)有些復(fù)雜,其聲明如下:
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 );
該函數(shù)能夠同時計(jì)算多個圖像,多個通道,不同灰度范圍的灰度直方圖.
其參數(shù)如下:
? images,輸入圖像的數(shù)組,這些圖像要有相同大大小,相同的深度(CV_8U CV_16U CV_32F).
? nimages ,輸入圖像的個數(shù)
? channels,要計(jì)算直方圖的通道個數(shù)。
? mask,可選的掩碼,不使用時可設(shè)為空。要和輸入圖像具有相同的大小,在進(jìn)行直方圖計(jì)算的時候,只會統(tǒng)計(jì)該掩碼不為0的對應(yīng)像素
? hist,輸出的直方圖
? dims,直方圖的維度
? histSize,直方圖每個維度的大小
? ranges,直方圖每個維度要統(tǒng)計(jì)的灰度級的范圍
? uniform,是否進(jìn)行歸一化,默認(rèn)為true
? accumulate,累積標(biāo)志,默認(rèn)值為false。
為了計(jì)算的靈活性和通用性,OpenCV的灰度直方圖提供了較多的參數(shù),但對于只是簡單的計(jì)算一幅灰度圖的直方圖的話,又顯得較為累贅。這里對calcHist進(jìn)行一次封裝,能夠方便的得到一幅灰度圖直方圖。
class Histogram1D
{
private:
int histSize[1]; // 項(xiàng)的數(shù)量
float hranges[2]; // 統(tǒng)計(jì)像素的最大值和最小值
const float* ranges[1];
int channels[1]; // 僅計(jì)算一個通道
public:
Histogram1D()
{
// 準(zhǔn)備1D直方圖的參數(shù)
histSize[0] = 256;
hranges[0] = 0.0f;
hranges[1] = 255.0f;
ranges[0] = hranges;
channels[0] = 0;
}
MatND getHistogram(const Mat &image)
{
MatND hist;
// 計(jì)算直方圖
calcHist(&image ,// 要計(jì)算圖像的
1, // 只計(jì)算一幅圖像的直方圖
channels, // 通道數(shù)量
Mat(), // 不使用掩碼
hist, // 存放直方圖
1, // 1D直方圖
histSize, // 統(tǒng)計(jì)的灰度的個數(shù)
ranges); // 灰度值的范圍
return hist;
}
Mat getHistogramImage(const Mat &image)
{
MatND hist = getHistogram(image);
// 最大值,最小值
double maxVal = 0.0f;
double minVal = 0.0f;
minMaxLoc(hist, &minVal, &maxVal);
//顯示直方圖的圖像
Mat histImg(histSize[0], histSize[0], CV_8U, Scalar(255));
// 設(shè)置最高點(diǎn)為nbins的90%
int hpt = static_cast<int>(0.9 * histSize[0]);
//每個條目繪制一條垂直線
for (int h = 0; h < histSize[0]; h++)
{
float binVal = hist.at<float>(h);
int intensity = static_cast<int>(binVal * hpt / maxVal);
// 兩點(diǎn)之間繪制一條直線
line(histImg, Point(h, histSize[0]), Point(h, histSize[0] - intensity), Scalar::all(0));
}
return histImg;
}
};
Histogram1D提供了兩個方法:getHistogram返回統(tǒng)計(jì)直方圖的數(shù)組,默認(rèn)計(jì)算的灰度范圍是[0,255];getHistogramImage將圖像的直方圖以線條的形式畫出來,并返回包含直方圖的圖像。測試代碼如下:
Histogram1D hist;
Mat histImg;
histImg = hist.getHistogramImage(image);
imshow("Image", image);
imshow("Histogram", histImg);
其結(jié)果如下:
直方圖均衡化 Histogram Equalization
假如圖像的灰度分布不均勻,其灰度分布集中在較窄的范圍內(nèi),使圖像的細(xì)節(jié)不夠清晰,對比度較低。通常采用直方圖均衡化及直方圖規(guī)定化兩種變換,使圖像的灰度范圍拉開或使灰度均勻分布,從而增大反差,使圖像細(xì)節(jié)清晰,以達(dá)到增強(qiáng)的目的。
直方圖均衡化,對圖像進(jìn)行非線性拉伸,重新分配圖像的灰度值,使一定范圍內(nèi)圖像的灰度值大致相等。這樣,原來直方圖中間的峰值部分對比度得到增強(qiáng),而兩側(cè)的谷底部分對比度降低,輸出圖像的直方圖是一個較為平坦的直方圖。
均衡化算法
直方圖的均衡化實(shí)際也是一種灰度的變換過程,將當(dāng)前的灰度分布通過一個變換函數(shù),變換為范圍更寬、灰度分布更均勻的圖像。也就是將原圖像的直方圖修改為在整個灰度區(qū)間內(nèi)大致均勻分布,因此擴(kuò)大了圖像的動態(tài)范圍,增強(qiáng)圖像的對比度。通常均衡化選擇的變換函數(shù)是灰度的累積概率,直方圖均衡化算法的步驟:
? 計(jì)算原圖像的灰度直方圖 ,其中為像素總數(shù),為灰度級的像素個數(shù)
? 計(jì)算原始圖像的累積直方圖
? ,其中 是目的圖像的像素,是源圖像灰度為i的累積分布,L是圖像中最大灰度級(灰度圖為255)
其代碼實(shí)現(xiàn)如下:
? 在上面中封裝了求灰度直方圖的類,這里直接應(yīng)用該方法得到圖像的灰度直方圖;
? 將灰度直方圖進(jìn)行歸一化,計(jì)算灰度的累積概率;
? 創(chuàng)建灰度變化的查找表
? 應(yīng)用查找表,將原圖像變換為灰度均衡的圖像
具體代碼如下:
void equalization_self(const Mat &src, Mat &dst)
{
Histogram1D hist1D;
MatND hist = hist1D.getHistogram(src);
hist /= (src.rows * src.cols); // 對得到的灰度直方圖進(jìn)行歸一化
float cdf[256] = { 0 }; // 灰度的累積概率
Mat lut(1, 256, CV_8U); // 灰度變換的查找表
for (int i = 0; i < 256; i++)
{
// 計(jì)算灰度級的累積概率
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]); // 創(chuàng)建灰度的查找表
}
LUT(src, lut, dst); // 應(yīng)用查找表,進(jìn)行灰度變化,得到均衡化后的圖像
}
上面代碼只是加深下對均衡化算法流程的理解,實(shí)際在OpenCV中也提供了灰度均衡化的函數(shù)equalizeHist,該函數(shù)的使用很簡單,只有兩個參數(shù):輸入圖像,輸出圖像。下圖為,上述代碼計(jì)算得到的均衡化結(jié)果和調(diào)用equalizeHist的結(jié)果對比
最左邊為原圖像,中間為OpenCV封裝函數(shù)的結(jié)果,右邊為上面代碼得到的結(jié)果。
直方圖規(guī)定化
從上面可以看出,直方圖的均衡化自動的確定了變換函數(shù),可以很方便的得到變換后的圖像,但是在有些應(yīng)用中這種自動的增強(qiáng)并不是最好的方法。有時候,需要圖像具有某一特定的直方圖形狀(也就是灰度分布),而不是均勻分布的直方圖,這時候可以使用直方圖規(guī)定化。
直方圖規(guī)定化,也叫做直方圖匹配,用于將圖像變換為某一特定的灰度分布,也就是其目的的灰度直方圖是已知的。這其實(shí)和均衡化很類似,均衡化后的灰度直方圖也是已知的,是一個均勻分布的直方圖;而規(guī)定化后的直方圖可以隨意的指定,也就是在執(zhí)行規(guī)定化操作時,首先要知道變換后的灰度直方圖,這樣才能確定變換函數(shù)。規(guī)定化操作能夠有目的的增強(qiáng)某個灰度區(qū)間,相比于,均衡化操作,規(guī)定化多了一個輸入,但是其變換后的結(jié)果也更靈活。
在理解了上述的均衡化過程后,直方圖的規(guī)定化也較為簡單??梢岳镁饣蟮闹狈綀D作為一個中間過程,然后求取規(guī)定化的變換函數(shù)。具體步驟如下:
? 將原始圖像的灰度直方圖進(jìn)行均衡化,得到一個變換函數(shù),其中s是均衡化后的像素,r是原始像素
? 對規(guī)定的直方圖進(jìn)行均衡化,得到一個變換函數(shù),其中v是均衡化后的像素,z是規(guī)定化的像素
? 上面都是對同一圖像的均衡化,其結(jié)果應(yīng)該是相等的,,且
通過,均衡化作為中間結(jié)果,將得到原始像素和規(guī)定化后像素之間的映射關(guān)系。
詳解規(guī)定化過程
對圖像進(jìn)行直方圖規(guī)定化操作,原始圖像的直方圖和以及規(guī)定化后的直方圖是已知的。假設(shè)表示原始圖像的灰度概率密度,表示規(guī)定化圖像的灰度概率密度(r和z分別是原始圖像的灰度級,規(guī)定化后圖像的灰度級)。
? 對原始圖像進(jìn)行均衡化操作,則有
? 對規(guī)定化的直方圖進(jìn)行均衡化操作,則
? 由于是對同一圖像的均衡化操作,所以有。
? 規(guī)定化操作的目的就是找到原始圖像的像素到規(guī)定化后圖像像素的之間的一個映射。有了上一步的等式后,可以得到,因此要想找到相對應(yīng)的只需要在進(jìn)行迭代,找到使式子的絕對值最小即可。
? 上述描述只是理論的推導(dǎo)過程,在實(shí)際的計(jì)算過程中,不需要做兩次的均衡化操作,具體的推導(dǎo)過程如下:$$
文章轉(zhuǎn)自Brook_icv https://www.cnblogs.com/wangguchangqing/p/7098213.html