直方圖均衡
一、目的與原理
(1)目的:增加圖像的全局對比度
(2)原理:直方圖均衡化處理的“中心思想”是把原始圖像的灰度直方圖從比較集中的某個灰度區間變成在全部灰度范圍內的均勻分布。直方圖均衡化就是對圖像進行非線性拉伸,重新分配圖像像素值,使一定灰度范圍內的像素數量大致相同,實際上就是使得圖片的亮暗程度增加使比較密集的灰度向兩側擴散。
公式①:
(L-1)是灰度范圍,T(rk)是累積分布函數,Pr(rj)是概率密度
二、步驟
(1)得到原始圖片的灰度直方圖
(2)得到各個灰度級對應的概率密度函數
(3)通過概率密度函數得到累積分布函數
(4)累計分布函數乘以255,得到每一個灰度級對應的新的灰度
(5)通過第4步的結果,將舊灰度映射得到新的灰度,即更新整張圖片的灰度
三、特點
直方圖均衡化的缺點
如果一幅圖像整體偏暗或者偏亮,那么直方圖均衡化的方法很適用。但直方圖均衡化是一種全局處理方式,它對處理的數據不加選擇,可能會增加背景干擾信息的對比度並且降低有用信號的對比度(如果圖像某些區域對比度很好,而另一些區域對比度不好,那采用直方圖均衡化就不一定適用)。此外,均衡化后圖像的灰度級減少,某些細節將會消失;某些圖像(如直方圖有高峰),經過均衡化后對比度不自然的過分增強。針對直方圖均衡化的缺點,已經有局部的直方圖均衡化方法出現。
四、源碼
//直方圖均衡化
Mat Histogramequalization(Mat src) {
int R[256] = { 0 };
int G[256] = { 0 };
int B[256] = { 0 };
int rows = src.rows;
int cols = src.cols;
int sum = rows * cols; //分辨率
//統計直方圖的RGB分布
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
B[src.at<Vec3b>(i, j)[0]]++;
G[src.at<Vec3b>(i, j)[1]]++;
R[src.at<Vec3b>(i, j)[2]]++;
}
}
//構建直方圖的累計分布方程,用於直方圖均衡化
double val[3] = { 0 };
for (int i = 0; i < 256; i++) {
val[0] += B[i]; //val[0]是紅色出現的累積頻率
val[1] += G[i]; //val[1]是紅色出現的累積頻率
val[2] += R[i]; //val[2]是紅色出現的累積頻率
B[i] = val[0] * 255 / sum; //B[0~255]
G[i] = val[1] * 255 / sum;
R[i] = val[2] * 255 / sum;
}
//歸一化直方圖
Mat dst(rows, cols, CV_8UC3);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
dst.at<Vec3b>(i, j)[0] = B[src.at<Vec3b>(i, j)[0]];
dst.at<Vec3b>(i, j)[1] = G[src.at<Vec3b>(i, j)[1]];
dst.at<Vec3b>(i, j)[2] = R[src.at<Vec3b>(i, j)[2]];
}
}
return dst;
}
Mat Histogramequal(Mat src) {
int arr[256] = { 0 };
int rows = src.rows;
int cols = src.cols;
int sum = rows * cols;
//統計直方圖的RGB分布
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
arr[src.at<uchar>(i, j)]++;
}
}
//構建直方圖的累計分布方程,用於直方圖均衡化
double val[3] = { 0 };
for (int i = 0; i < 256; i++) {
val[0] += arr[i];
arr[i] = val[0] * 255 / sum;
}
//歸一化直方圖
Mat dst(rows, cols, CV_8UC1);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
dst.at<uchar>(i, j) = arr[src.at<uchar>(i, j)];
}
}
return dst;
}
五、結果圖