直方图均衡化是通过对原图像在像素个数多的灰度级进行展宽,对像素个数少的灰度级进行缩减,使原图像的灰度直方图修正为均匀分布的直方图。
步骤
由原图像得灰度直方图
计每一个像素值的点的个数。
例如:原图像
1 |
3 |
9 |
9 |
8 |
2 |
1 |
3 |
7 |
3 |
3 |
6 |
0 |
6 |
4 |
6 |
8 |
2 |
0 |
5 |
2 |
9 |
2 |
6 |
0 |
灰度直方图
灰度级 |
像素点个数H |
0 |
3 |
1 |
2 |
2 |
4 |
3 |
4 |
4 |
1 |
5 |
1 |
6 |
4 |
7 |
1 |
8 |
2 |
9 |
3 |
由灰度直方图得灰度级像素百分比
灰度直方图中的像素点个数 / 总像素点个数
灰度级 |
灰度级像素百分比HR |
0 |
0.12 |
1 |
0.08 |
2 |
0.16 |
3 |
0.16 |
4 |
0.04 |
5 |
0.04 |
6 |
0.16 |
7 |
0.04 |
8 |
0.08 |
9 |
0.12 |
计算各灰度级的累积分布
灰度级 |
累积分布HS |
0 |
0.12 |
1 |
0.20 |
2 |
0.36 |
3 |
0.52 |
4 |
0.56 |
5 |
0.60 |
6 |
0.76 |
7 |
0.80 |
8 |
0.88 |
9 |
1.00 |
求出新图像的灰度值
即乘以灰度级个数后再四舍五入。
C++实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv;
void histogram_equalization(Mat &img, Mat &result) { int H[256] = {0}; for (int i = 0; i <= 255; i++) { H[i] = 0; }
for (int nrow = 0; nrow < img.rows; nrow++) { for (int ncol = 0; ncol < img.cols; ncol++) { int h = img.ptr<uchar>(nrow)[ncol]; H[h] ++; } }
int NR = img.rows * img.cols; double HR[256] = {0}; for (int i = 0; i <= 255; i++) { HR[i] = 0.0; } for (int i = 0; i <= 255; i++) { HR[i] = double(H[i])/double(NR); }
double HS[256] = {0}; for (int i = 0; i <= 255; i++) { HS[i] = 0.0; } for (int i = 1; i <= 255; i++) { for (int j = 0; j <= i; j++) { HS[i] += HR[j]; } H[i] = round(HS[i] * 255); }
for (int nrow = 0; nrow < img.rows; nrow++) { for (int ncol = 0; ncol < img.cols; ncol++) { int h = img.ptr<uchar>(nrow)[ncol]; result.ptr<uchar>(nrow)[ncol] = H[h]; } } }
int main() { Mat img = imread("Unequalized.jpg", IMREAD_GRAYSCALE); Mat result = img.clone(); histogram_equalization(img, result); imshow("img",img); imshow("Histogram Equalization",result); imwrite("result.jpg", result); waitKey(); return 0; }
|
原图像:
经直方图均衡化后的图像: