一幅给定的图像的灰度级 r 分布在 [0,1] 范围内。可以对任一个 r 值进行如下变换:
变换函数 T(r) 要求满足下列条件:
1. T(r) 单调递增;
2. 对于 r∈[0,1] ,有 T(r)∈[0,1] 。
当 T 严格单调时,从 s 到 r 的反变换可用式下表示
可得反变换函数 T−1(s) 满足下列条件:
1. T−1(s) 单调递增;
2. 对于 s∈[0,1] ,有 T−1(s)∈[0,1] 。
一副图像的灰度级可被视为区间 [0,1] 的随机变量。
令 pr(r) 和 ps(s) 分别代表随机变量 r 和 s 的概率密度函数。
已知 pr(r) 和 s=T(r) ,求 ps(s) 。
即求随机变量的函数的概率密度。
在概统里面的方法一般是:
1. 分布函数法。先求分布函数再求导。
2. 特别的,当函数 T 严格单调,有结论如下:
具体的推导过程可以去翻翻概统书。
下面提供错误的推导
pr(r)=pr(T−1(s))≜ps(s)即ps(⋅)=pr(T−1(⋅))
直方图均衡化处理是以累积分布函数变换法为基础的直方图修正法。
假定变换函数为:
因此,用 r 的分布函数作为变换函数,可产生一幅灰度级分布具有均匀概率密度的图像。其结果扩展了像素取值的动态范围。
但该结果只对于连续变量而言。在实际中灰度是呈离散形式分布的,不能保证均匀分布。
当灰度级是离散值时,可用频数近似代替概率值,即
因为直方图是近似的概率密度函数,所以用离散灰度级作变换一般得不到完全平坦的结果。由于简并现象的存在,处理后的灰度级总是要减少的,这是像素灰度有限的必然结果。由于上述原因,数字图像的直方图均衡只是近似的。
采用256灰阶的Lena图。
github source code
Image HistogramEqualization(Image inImage, int width, int height) {
Image outImage(width, height);
int rn[256] = { 0 }, sum = width * height;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
Pixel p = inImage.getPixel(x, y);
rn[p.getR()]++; // 统计每个灰度的数量
}
}
double p[256], s[256];
int T[256];
for (int i = 0; i < 256; i++)
p[i] = 1.0 * rn[i] / sum; // 计算每个灰度的概率
s[0] = p[0];
for (int i = 1; i < 256; i++) {
s[i] = p[i] + s[i - 1]; // 做累积分布
T[i] = (int)(s[i] * 256); // 将累积分布作为变换函数T
}
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
Pixel p = inImage.getPixel(x, y);
const int r = T[p.getR()]; // 转换灰度值
p.set(r, r, r);
outImage.setPixel(x, y, p);
}
}
return outImage;
}
下面是均衡化后的图像
彩图则对rgb都均衡化处理
void HE(int *rn, int sum, int *rT) {
double rp[256], rs[256];
for (int i = 0; i < 256; i++)
rp[i] = 1.0 * rn[i] / sum;
rs[0] = rp[0];
for (int i = 1; i < 256; i++) {
rs[i] = rp[i] + rs[i - 1];
rT[i] = (int)(rs[i] * 256);
}
}
Image HistogramEqualization(Image inImage, int width, int height) {
Image outImage(width, height);
int rn[256] = { 0 }, sum = width * height;
int gn[256] = { 0 };
int bn[256] = { 0 };
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
Pixel p = inImage.getPixel(x, y);
rn[p.getR()]++;
gn[p.getR()]++;
bn[p.getR()]++;
}
}
// 三者都均衡化处理
int rT[256], gT[256], bT[256];
HE(rn, sum, rT);
HE(gn, sum, gT);
HE(bn, sum, bT);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
Pixel p = inImage.getPixel(x, y);
p.set(rT[p.getR()], gT[p.getG()], bT[p.getB()]);
outImage.setPixel(x, y, p);
}
}
return outImage;
}
下图为均衡化后
并没有变好吃(¬︿̫̿¬☆)!