关闭

图像处理(3)_灰度分布均衡化

标签: 图像处理bytec#算法c
3632人阅读 评论(2) 收藏 举报

灰度分布均衡化又称直方图均衡化。

其理论原理见:http://zh.wikipedia.org/wiki/%E7%9B%B4%E6%96%B9%E5%9B%BE%E5%9D%87%E8%A1%A1%E5%8C%96

其实维基百科是一个很不错的东西。大家有问题的话可以去维基百科逛逛。大笑 我比较懒,理论的话全引自其他网页。

好了开始进入正题。

来看一个灰度图像,让n_i表示灰度i出现的次数,这样图像中灰度为i 的像素的出现概率是

p_x(i) = \frac{n_i}{n}, i\in {0,..., L - 1}

L 是图像中所有的灰度数,n 是图像中所有的像素数,p 实际上是图像的直方图,归一化到0..1

c 作为对应于p 的累计概率函数, 定义为:

 c(i) = \sum_{j=0}^i p_x(j)

c 是图像的累计归一化直方图。

我们创建一个形式为 y = T(x) 的变化,对于原始图像中的每个值它就产生一个y,这样y 的累计概率函数就可以在所有值范围内进行线性化,转换公式定义为:

y_i = T(x_i) = c(i)

注意 T 将不同的等级映射到 {0..1} 域,为了将这些值映射回它们最初的域,需要在结果上应用下面的简单变换:

y_i' = y_i \cdot(max - min) + min

上面描述了灰度图像上使用直方图均衡化的方法,但是通过将这种方法分别用于图像RGB颜色值的红色、绿色和蓝色分量,从而也可以对彩色图像进行处理。

 

上述是维基百科对直方图均衡化的原理解释,转化为算法描述则是:
(1)获取目标图像的直方图。

(2)从获取直方图图中获取灰度密度分布。【就是每个灰度级 像素个数/ 灰度直方图中像素的总个数】

(3)对密度直方图进行累加,每个灰度级密度是前面所有灰度级的密度总和。

(4)对原图像进行遍历然,每个像素值为累加后的概率密度索引值  并乘上255 对图像进行还原。

 

代码:

       public static Bitmap GrayBalanceChange(Bitmap tp)
       {
           int w = tp.Width;
           int h = tp.Height;
           int i, j,T,sum;
           byte[] ky = new byte[w * h];
           byte[] hist = new byte[256];  // 用于记录灰度分布
           double[] phist = new double[256]; // 用于记录灰度分布的概率分布

           ky = ChangeByte(tp);     // 获取图像一维数组
           hist = GetGrayHist(tp);  // 获取直方图
           sum = 0;
           for (i = 0; i < 256; i++)
           {
               sum += hist[i];     // 求直方图总像素个数
           }
            // 获取灰度分布的概率分布
            for (i = 0; i < 256; i++)
            {
                phist[i] = (double)(hist[i]) / (sum);
            }
           // 对灰度概率累加求和
           for (i = 1; i < 255; i++)   // 对第一个和最后一个灰度级不处理
           {
               phist[i] = phist[i] + phist[i - 1];
           }

           for (i = 0; i < 256; i++)  // 累加后还原成直方图
           {
               phist[i] = 255 * phist[i];
           }

           for (i = 0; i < h; i++)
           {
               for (j = 0; j < w; j++)
               {
                   T = ky[i * w + j];     // 原图像的灰度级
                   ky[i * w + j] = (byte)(phist[T]);  // 将原图灰度级作为索引赋给原图像素
               }
           }

           tp = ChangeBitmap(ky, tp); // 将一维数组转换为bitmap
           return tp;
       }


下面是一维数组转换为bitmap

        public static byte[] ChangeByte(Bitmap tp)
        {
            int w = tp.Width;   // 图像实际宽度 
            int h = tp.Height;  // 图像实际高度

            BitmapData srcdata = tp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly,
              PixelFormat.Format24bppRgb);     // 将图像锁入内存,只读,图像格式为rgb格式

            byte[] pixeData = new byte[h * w]; // 声明一个与图像等大的数组,因为每个像素点的(灰度)值
                                               // 范围为 0 - 255  所以使用byte数组
            int sride = srcdata.Stride;    // 获取图像的系统宽度

            unsafe    // C#使用指针时需要在unsafe中使用,
            {    // C#默认不支持unsafe,使用时在项目 -》选项  -》生成中设置
                byte* temp = (byte*)srcdata.Scan0.ToPointer(); // 获取图像锁入内存的首地址

                for (int i = 0; i < h; i++)
                {
                    for (int j = 0; j < w; j++)
                    {
                        pixeData[i * w + j] = temp[0];  // 我们只获取第一个色彩的值,对于灰度图像
                                                        // red blue green 像素值相等
                        temp += 3;                      // 跳过其余两色
                    }
                    temp += sride - w * 3;              // 加上系统对齐的宽度 
                }
            }

            tp.UnlockBits(srcdata);                     // 解锁
            return pixeData;

        }


效果:

               

                        原图                                                                           处理后图像

OK  处理完毕。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:59366次
    • 积分:809
    • 等级:
    • 排名:千里之外
    • 原创:19篇
    • 转载:22篇
    • 译文:0篇
    • 评论:8条
    文章分类
    最新评论