• 【短道速滑二】古老的基于亮度平均值的自动Gamma校正算法。


      在github上搜索代码Auto Gamma Correction,找到一个比较古老的代码,详见:https://github.com/PedramBabakhani/Automatic-Gamma-Correction,配套的代码使用VHDL语言写的,看了半天一个for循环没有,是在看不懂,幸好里面有篇算法对应的论文下载,论文名字叫《ASIC implementation of automatic gamma correction based on average of brightness 》,下载看了下,大概搞明白了他的大概意思。

      文章的核心思想很简单,就是他假定一幅合理的图像应该所有像素的平均值应该是0.5左右(归一化后的),所以那么自动伽马校正的伽马值就要使得目标图像向这个目标前进。

      假定X是图像的平均值,那么自动伽马需符合下述要求:

          

       一步一步的往下推导,有:

            -----》       --------》

       就是这么简单哪,如果写个代码也就是几分钟的事情。

    int IM_AutoGammaCorrection(unsigned char *Src, unsigned char *Dest, int Width, int Height, int Stride)
    {
        int Channel = Stride / Width;
        if ((Src == NULL) || (Dest == NULL))                    return IM_STATUS_NULLREFRENCE;
        if ((Width <= 0) || (Height <= 0))                        return IM_STATUS_INVALIDPARAMETER;
        if ((Channel != 1) && (Channel != 3) && (Channel != 4))    return IM_STATUS_NOTSUPPORTED;
        int AvgB, AvgG, AvgR, AvgA;
        int Status = IM_GetAverageValue(Src, Width, Height, Stride, AvgB, AvgG, AvgR, AvgA);
        if (Status != IM_STATUS_OK)    return Status;
        if (Channel == 1)
        {
            float Gamma = -0.3 / (log10(AvgB / 256.0f));
            unsigned char Table[256];
            for (int Y = 0; Y < 256; Y++)        //    另外一种方式是:pow(Y / 255.0, 1.0 / Gamma)
            {
                Table[Y] = IM_ClampToByte((int)(pow(Y / 255.0f, Gamma) * 255.0f));
            }
            return IM_Curve(Src, Dest, Width, Height, Stride, Table, Table, Table);
        }
        else
        {
            float GammaB = -0.3 / (log10(AvgB / 256.0f));
            float GammaG = -0.3 / (log10(AvgG / 256.0f));
            float GammaR = -0.3 / (log10(AvgR / 256.0f));
    
            unsigned char TableB[256], TableG[256], TableR[256];
            for (int Y = 0; Y < 256; Y++)        //    另外一种方式是:pow(Y / 255.0, 1.0 / Gamma)
            {
                TableB[Y] = IM_ClampToByte((int)(pow(Y / 255.0f, GammaB) * 255.0f));
                TableG[Y] = IM_ClampToByte((int)(pow(Y / 255.0f, GammaG) * 255.0f));
                TableR[Y] = IM_ClampToByte((int)(pow(Y / 255.0f, GammaR) * 255.0f));
            }
            return IM_Curve(Src, Dest, Width, Height, Stride, TableB, TableG, TableR);
        }
    }

      效果似乎还是很不错的。 

           

      对于正常的图像,基本上没有啥变化,这也是必须要有的特性。

              

      论文里提出了另外一种更适合于硬件实现的方式。

      他把图像分成很多个16*16的小块,比如N*M个(文章中固定死了,也是16*16个),然后对16*16的小块,每次提取对应位置的一个像素,共计N*M个像素,计算这N*M像素的平均值,然后依据这个平均值计算出伽马值,这样就能计算出16*16个Gamma值,这些Gamma值肯定不会是完全相同的,文章中也统计了他们的差异大小,最后用这个256个gamma的平均值作为最后的正副图像的平均值。

       

      这代码写的有点狗屎 ......

      注意上面的取样是全部平均取样,不是某一个块集中取样。

      这样写的结果和全图取平均还是有一定区别的,不过效果基本上差不多。

      整个过程就这么简单,不过对于彩色图像,如果直接分通道实现,似乎会出现一定的偏色现象,我想这个不应该是Gamma调整该出现的作用,应该予以消除,如下所示:

           

      解决方法有把三通道求得的Gamma值再求平均值,作为每个通道的Gamma值,也可以对亮度通道做Gamma,然后在返回到RGB空间等等。

           

      如上所示,基本没有这个现象。

      当然,这种全局的Gamma校正还是有很多问题,比如容易出现块状,容易增强噪音等等,需要和某些局部算法结合在一起来实现更好的结果。

           本文Demo下载地址:  http://files.cnblogs.com/files/Imageshop/SSE_Optimization_Demo.rar,见其中的Adjust-> Auto Gamma Correction菜单。

  • 相关阅读:
    RAW和JPEG的区别_ZT
    用户自定义基元UDP_ZT
    UDP用户自定义原语
    SR锁存器
    Matlab实现Butterworth滤波器 分类: 图像处理 2014-06-02 00:05 527人阅读 评论(0) 收藏
    egrep命令的实现 分类: 编译原理 2014-06-01 23:41 329人阅读 评论(0) 收藏
    随机L系统分形树 分类: 计算机图形学 2014-06-01 23:27 376人阅读 评论(0) 收藏
    matlab实现算术编解码 分类: 图像处理 2014-06-01 23:01 357人阅读 评论(0) 收藏
    命名管道实现进程间通信--石头、剪刀、布游戏 分类: linux 2014-06-01 22:50 467人阅读 评论(0) 收藏
    互斥锁与条件变量应用 2014-06-01 22:20 328人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/Imageshop/p/13380028.html
Copyright © 2020-2023  润新知