直方图均衡化

变换函数

一幅给定的图像的灰度级 r 分布在 [0,1] 范围内。可以对任一个 r 值进行如下变换:

s=T(r)       r[0,1]
使得每个原始图像的像素灰度值 r 都对应产生一个 s 值。

变换函数 T(r) 要求满足下列条件:

1. T(r) 单调递增;
2. 对于 r[0,1] ,有 T(r)[0,1]

反变换函数

当 T 严格单调时,从 s 到 r 的反变换可用式下表示

r=T1(s)       s[0,1]

可得反变换函数 T1(s) 满足下列条件:

1. T1(s) 单调递增;
2. 对于 s[0,1] ,有 T1(s)[0,1]


概率密度函数

一副图像的灰度级可被视为区间 [0,1] 随机变量
pr(r) ps(s) 分别代表随机变量 r 和 s 的概率密度函数

已知 pr(r) s=T(r) ,求 ps(s)
即求随机变量的函数的概率密度。

在概统里面的方法一般是:
1. 分布函数法。先求分布函数再求导。
2. 特别的,当函数 T 严格单调,有结论如下:

ps(s)=pr(r)|dT1(s)ds|=pr(r)|drds|     ()

具体的推导过程可以去翻翻概统书。
下面提供错误的推导

pr(r)=pr(T1(s))ps(s)
ps()=pr(T1())


直方图均衡化

直方图均衡化处理是以累积分布函数变换法为基础的直方图修正法。

连续随机变量

假定变换函数为:

s=T(r)=r0pr(w) dw
对 r 进行求导得:
dsdr=pr(r)
代入到 () 中,得到
ps(s)=1
该结果表明在假定的变换函数的作用下,变换后的变量 s 的概率密度是 均匀分布的。

因此,用 r 的分布函数作为变换函数,可产生一幅灰度级分布具有均匀概率密度的图像。其结果扩展了像素取值的动态范围。

离散随机变量

但该结果只对于连续变量而言。在实际中灰度是呈离散形式分布的,不能保证均匀分布。

当灰度级是离散值时,可用频数近似代替概率值,即

pr(rk)=nkn       rk[0,1],k=0,1,...,L1
变换函数为:
sk=T(rk)=j=0kpr(rj)

因为直方图是近似的概率密度函数,所以用离散灰度级作变换一般得不到完全平坦的结果。由于简并现象的存在,处理后的灰度级总是要减少的,这是像素灰度有限的必然结果。由于上述原因,数字图像的直方图均衡只是近似的。


代码实现

采用256灰阶的Lena图。

  1. 统计每个灰度的概率p
  2. 做累积分布s
  3. 将累积分布作为变换函数T
  4. 转换每个灰度值

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;
}


下图为均衡化后

并没有变好吃(¬︿̫̿¬☆)!

你可能感兴趣的:(图像处理)