本文的算法并不是我自己提出的,而是一些论文中提出的,详见 :
1、基于图像分析的偏色检测及颜色校正方法 徐晓昭 , 蔡轶珩 , 刘长江 , 贾克斌 , 沈兰荪
为方便大家理解,这里还是从这些论文里摘取些具体的过程予以描述。
RGB颜色空间是最简单的一种颜色空间,但是RGB颜色空间最大的局限性在于当用欧氏距离来刻画两种颜色之间的差异时,所计算出的两种颜色之间的距无法正确表征人们实际所感知到的这两种颜色之间的真实差异。采用CIE Lab颜色空间,此空间所计算出来的颜色之间的距离与实际感知上的差别基本一致。其直方图可以客观的反映图像色偏程度,在CIE Lab下进行偏色图像的自动检测更为合理。
经过对正常图像和偏色图像的分析发现,如果在ab色度坐标平面上的直方图中,色度分布基本上为单峰值,或者分布较为集中,而色度平均值D又较大时,一般都存在色偏,而且色度平均值越大,色偏越严重。然而,如果在ab色度坐标平面上的直方图中色度分布存在明显的多峰值,而且较为分散时,图像色偏程度将大大减轻,甚至没有色偏。
如上图所示,第一个美女图明显就偏色,其[a,b]直方图明显有只有一个波峰,而第二个美女图则很协调,[a,b]直方图也分布的很均匀。
因此引入等效圆的概念 ,采用图像平均色度 D和色度中心距 M的比值 ,即偏色因子 K来衡量图像的偏色程度。其计算方法如下式
式中 ,M、 N分别为图像的宽和高,以像素为单位。在 a - b色度平面上,等效圆的中心坐标为 ( da , db ) ,半径为 M 。等效圆的中心到 a - b色度平面中性轴原点为 ( a = 0, b = 0)的距离 D 。由等效圆在 a - b色度平面上的具体位置,来判断图像整体的偏色。da > 0,偏红,否则偏绿。db > 0,偏黄,否则偏蓝。引入偏色因子 K, K值越大 ,偏色越严重。
按照上述细路编制的代码如下:
//***************************************************************************************** //** 开发日期 : 2013-12-20 //** 作 者 : laviewpbt //** 联系方式: 33184777 //** 修改日期 : 2013-7-15 //** 版 本 : Version 1.0.0 //** 转载请不要删除以上信息 //** 皮肤检测技术的研究及改进 重庆大学硕士论文 魏菁 //***************************************************************************************** public static double GetColorCastFactor(Bitmap Bmp) { if (Bmp.PixelFormat != PixelFormat.Format24bppRgb) throw new ArgumentException("Only Support PixelFormat24RGB format Image."); Bitmap Lab = new Bitmap(Bmp.Width, Bmp.Height, PixelFormat.Format24bppRgb); int X, Y; int Width, Height, Stride; BitmapData BmpData, LabData; byte* Pointer; int SumA = 0, SumB = 0; double MsqA = 0, MsqB = 0, AvgA, AvgB; int A, B; int[] HistA = new int[256]; int[] HistB = new int[256]; BmpData = Bmp.LockBits(new Rectangle(0, 0, Bmp.Width, Bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); LabData = Lab.LockBits(new Rectangle(0, 0, Lab.Width, Lab.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); Width = Bmp.Width; Height = Bmp.Height; Stride = BmpData.Stride; for (Y = 0; Y < Height; Y++) ColorSpace.RGBLAB.ToLAB((byte*)BmpData.Scan0 + Y * Stride, (byte*)LabData.Scan0 + Y * Stride, Bmp.Width); for (Y = 0; Y < Height; Y++) { Pointer = (byte*)LabData.Scan0 + Y * Stride; for (X = 0; X < Width; X++) { A = *(Pointer + 1); B = *(Pointer + 2); SumA += A; SumB += B; HistA[A]++; HistB[B]++; Pointer += 3; } } AvgA = (double)SumA / (Width * Height) - 128; // 必须归一化到[-128,,127]范围内 AvgB = (double)SumB / (Width * Height) - 128; for (Y = 0; Y < 256; Y++) { MsqA += (double)(Math.Abs(Y - AvgA - 128) * HistA[Y]) / (Width * Height); // 用方差的方式结果有问题 MsqB += (double)(Math.Abs(Y - AvgB - 128) * HistB[Y]) / (Width * Height); } Bmp.UnlockBits(BmpData); Lab.UnlockBits(LabData); Lab.Dispose(); return Math.Sqrt(AvgA * AvgA + AvgB * AvgB) / Math.Sqrt(MsqA * MsqA + MsqB * MsqB); }
其中的RGB到LAB空间转换部分代码及其优化可参考:颜色空间系列2: RGB和CIELAB颜色空间的转换及优化算法
代码很简答吧,朋友们可以先按照公式自己编写下,然后再和我的最比下。看看那些地方的优化值得学习吧。
按照上述我们做一些测试:
cast = 3.297788 cast=0.37389 cast=0.5028 cast=1.82749 cast=1.699
我们在测试一些明显偏色的图像。
cast =3.52449 cast =5.74808 cast=2.50289 cast =4.08616
上述四幅图的偏色明显比较验证,偏色因子的值也较大。
在看看一些比较正常的照片吧.
cast=0.43784 cast =0.90216 cast=0.51927 cast =1.216
综合来说,cast值不大于1.5我们可以认为其整体图像偏色的可能性不大,当然这个值取多少可能还是需要和实际情况结合的。
xiaotie在其博客里也晒出了它的一种检测偏色的结果,我这里的计算复杂度可能没他哪里的复杂,不过也可以借鉴参考的。
完整的代码见:http://files.cnblogs.com/Imageshop/ColorCast.rar
博客园的网站分类里居然没有图像处理一栏,只有计算机图形学一项,其实搞这一行的都知道,这两个是完全不同的行业。希望博客园考虑增加图像处理一栏。
*****************************基本上我不提供源代码,但是我会尽量用文字把对应的算法描述清楚或提供参考文档**************************
*******************************因为靠自己的努力和实践写出来的效果才真正是自己的东西,人一定要靠自己****************************
***************************作者: laviewpbt 时间: 2013.4.07 联系QQ: 33184777 转载请保留本行信息*************************