无论是用何种语言,只要使用过Windows的GDI+的人对ColorMatrix都不陌生,我的BLOG文章中也多次提到过,并在《GDI+ for VCL基础 -- 颜色调整矩阵ColorMatrix详解》一文中对其功能作了较为详细的讲解,虽然自认对ColorMatrix使用已经相当熟练,但对其原理也是知其然而不知其所以然。直到前几天有位朋友就ColorMatrix实现图像去反功能不正常而问我(见http://topic.csdn.net/u/20080830/20/070c83de-d45b-441f-996e-3c68892855cd.html),我认为不大可能!众所周知,用RGB主对角线-1矩阵实现图像求反是ColorMatrix重要功能之一,可是我试验了多次,那张图片确实不能正常去反。我这人对自己自认熟悉的东西产生怀疑后,就有种不搞明白不罢休的冲动,为此,本人对ColorMatrix的原理作了透彻的解剖,不仅搞清楚了图像去反不正常的原因,还用代码完整地实现了ColorMatrix功能!
本文主要揭秘GDI+ ColorMatrix调整原理,实现代码另文介绍(可参见《Delphi图像处理 -- 图像颜色矩阵调整》)。
虽然我的BLOG中已有2篇文章引用了那段经典的关于ColorMatrix功能介绍的文字,但这里还是再引用一次,作为原理揭秘的开始:
GDI+ 提供用于存储和操作图像的 Image 和 Bitmap 类。Image 和 Bitmap 对象将每个像素的颜色都存储为 32 位的数:红色、绿色、蓝色和 alpha 各占 8 位。这四个分量的值都是 0 到 255,其中 0 表示没有亮度,255 表示最大亮度。alpha 分量指定颜色的透明度:0 表示完全透明,255 表示完全不透明。
颜色矢量采用 4 元组形式(红色、绿色、蓝色、alpha)。例如,颜色矢量 (0, 255, 0, 255) 表示一种没有红色和蓝色但绿色达到最大亮度的不透明颜色。
表示颜色的另一种惯例是用数字 1 表示亮度达到最大。使用这种惯例,上一段中描述的颜色将用 (0, 1, 0, 1) 表示。GDI+ 在进行颜色变换时使用以 1 表示最大亮度的惯例。
可通过用 4×4 矩阵乘以这些颜色矢量将线性变换(旋转和缩放等)应用到颜色矢量中。但是,您不能使用 4×4 矩阵进行平移(非线性)。如果在每个颜色矢量中再添加一个虚拟的第 5 坐标(例如,数字 1),则可使用 5×5 矩阵应用任何组合形式的线性变换和平移。由线性变换组成的后跟平移的变换称为仿射变换。
说实话,不仅是刚开始接触ColorMatrix的时候,就是现在的我看到这段文字,都觉得有点玄,前3段很好理解,特别是后面那段,更是使那些初识GDI+的人觉得ColorMatrix深奥无比:ColorMatrix是怎样实现颜色的缩放、旋转、剪切及平移的?靠这些功能能实现图像的哪些效果?或者说,某种效果能用ColorMatrix实现吗?
下面,就让我们一步步揭开ColorMatrix的神秘面纱,我相信,当你看完这篇文章后,一定会说:哦,原来如此,这么简单!其实,这就是所谓“江湖一张纸,戳破不值一分钱”!很多看起来技术含量很高的东西,被人千方百计保密,申请专利,搞的神秘无比,其实一旦公开,就那么回事!
要揭秘ColorMatrix,就要解析它的缩放、旋转、剪切及平移功能是怎么实现的,为了方便叙述,我画了个ColorMatrix矩阵图贴在上面,在下面的表述中,大写ARGB表示颜色各分量现有的值,而小写argb表示运算后得到的新值。
1、颜色缩放:颜色缩放很简单,就是按照给定的比例值,在图像像素现有A、R、G、B各分量数值基础上计算出新的分量值。这个比例值就是ColorMatrix主对角线除m55外的其它4个值。比如某像素的RGBA值现在分别为255、128、64和255,而主对角线m11 - m44的值分别为0.8、0.5、-1及0.5,那么该像素新的rgba值应该是:
r = R * m11 = 255 * 0.8 = 204;
g = G * m22 = 128 * 0.5 = 64;
b = B * m33 = 64 * -1 = 192;
a = A * m44 = 255 * 0.5 = 128;
是否很简单?!可能有初学者说我上面b值计算错了,64 * -1应该等于-64。没错,64用32位数表示为0xFFFFFFC0,无符号字节饱和取整,取最后8位0xC0,等于192。关于负值运算的问题,后面还要详细讲到的。
2、颜色剪切:一般说来,图像像素R、G、B各分量按照与另一种颜色分量成比例的量来增加或减少颜色分量就是剪切。其实这种表述并不完全,像素的A分量也是参与其中的!
以红色分量R举例,如果要按绿色分量G进行剪切,那么m21就是剪切比例值,m21 * G就得到了G对R的剪切量。同理,m31 * B、m41 * A可分别得到B和A对R的剪切量,将这些剪切量加起来,就是R总的剪切量。用公式表示为:
r = G * m21 + B * m31 + A * m41;
g = R * m12 + B * m32 + A * m42;
b = R * m13 + G * m23 + A * m43;
a = R * m14 + G * m24 + B * m34;
3、颜色旋转:颜色旋转的描述比较复杂,就是在图像像素中,用其中的2个分量按照一定的角度围绕另外1个分量作运算的结果,就是颜色的旋转。以红色分量R和绿色分量G围绕蓝色分量G旋转60度为例:
m11 = cos(60) = 0.5, m12 = sin(60) = 0.866,m21 = -sin(60) = -0.866, m22 = cos(60) = 0.5,那么,R和G 所得到的旋转量分别为:
r = R * m11(0.5) + G * m21(-0.866);
g = R * m12(0.866) + G * m22(0.5);
从上面的公式看,所谓的颜色旋转量,其实就是旋转的2个分量自身的缩放量加上与对方的剪切量而已!就运算角度看,同其它分量没有任何关系。
4、颜色平移:上面的缩放、剪切和旋转属于颜色的线性变换(都是乘法运算的累积和),而平移是颜色的非线性变换,就是对颜色各分量做一个加法而已:图像像素各分量的平移量用所谓的虚拟位,即第5行的各个值来表示,各分量加上所在列的虚拟行的值就是颜色平移,其实质就是非线性地调整了该分量的亮度值。用公式表示各分量的平移量:
r = R + m51 * 255;
g = G + m52 * 255;
b = B + m53 * 255;
a = A + m54 * 255;
综合以上颜色的缩放、旋转、剪切及平移公式,对于颜色的每个分量R、G、B、A来说,运用ColorMatrix后所得到的实际值r、g、b、a,用公式表示为:
r = R * m11 + G * m21 + B * m31 + A * m41 + m51 * 255;
g = R * m12 + G * m22 + B * m32 + A * m42 + m52 * 255;
b = R * m13 + G * m23 + B * m33 + A * m43 + m53 * 255;
a = R * m14 + G * m24 + B * m34 + A * m44 + m54 * 255;
从技术层面上讲,这个公式的含义就是颜色每个分量的新值,等于这个分量在ColorMatrix中对应列的前4行的值与R、G、A、B当前值的乘积之和加上第5行的值与常数255的乘积,而虚拟列(第5列)不起任何作用。
关于ColorMatrix功能的实现原理就这些,最后说说前面所提到的负值运算问题:ColorMatrix的负值运算无论是从原理上还是纯技术实现上都很有些麻烦:
a)、在前面缩放举例中,也就是只有主对角线有值的情况下,b的负值运算为 b = B * m33 = 64 * -1 = 192,这是正确的,但是,如果加上一个剪切量或者平移量,这个值就发生了一些变化。比如在缩放基础上加上0.1的平移量,这似乎是很简单的问题,直接用0.1 * 255加上去不就得了!可是,这个看是简单的问题,却有2个方案:是在缩放后的192基础上加平移量0.1 * 255等于218?还是应该做连续运算: b = B * m33 = 64 * -1 + 255 * 0.1= -38(饱和处理后为0)呢?如果是前者,运算法则上似乎说不过去;如果是后者,感官上难以接受,本来b=192使颜色值“蓝蓝”的,本想让它再“蓝”一点,而加个平移(亮度)量,可即使这个平移量相当小,例如只平移0.001,却让b值变成了0,不仅没有变的更“蓝”,反而使颜色失去了蓝色分量!可ColorMatrix偏偏用了使你感官难以接受的方案。其实也难怪设计者,只要顺其自然去实现代码,最后自然就成了这个结果。能够造成这个结果的,不仅仅是平移量,只要矩阵中主对角线以外的任何一个值不为0,包括不起作用的第5列,都会使主对角线中,具有负值所对应的RGBA分量发生这种变化。具体请看本文中篇的代码实现。
b)、前面也提到了有朋友用-1矩阵对图像求反不合要求的问题。通过上面的缩放公式计算一下,不难发现,用-1矩阵所得到的图像取反图只是近似的!为什么这么说呢?所谓取反,就是可逆,如果用255减去R(GB)取反后,再用255去减就可还原;用255异和R(GB),不用说也是可逆的,而-1 * R(GB)却是不完全可逆的:1 * -1饱和取整后为255,2 * -1为254 ......等等;反过来还原:结果是255 * -1 = 1、254 * -1 = 2......等等,从1 - 255都是可还原的,虽然这个还原于原本意义上的去反还原有1的误差,但从人的感官上,这点误差还是能接受的,只有“0”这个值是不可逆的,:0 * -1饱和取整还是0,无论是取反,还是还原,“0”依然是“0”,从而破坏了取反图的协调,使人的感官完全无法接受,例如原来纯红色的像素、取反后应该为青色,可是这里却变成了黑色,你能接受吗?所以只要图像像素RGB任何一个分量为0,那么这幅图的取反效果就会出问题!有人可能说,我们都是这么做的,除了极少数图片,大部分取反图看上去还是正常的,难道这些正常图里面就没有RGB分量为0的像素?其实,一幅图中间歇的分布几个RGB分量为0的像素,取反后,看上去是不那么明显的,所以我们认为这是成功的,只有那些“0”分量集中的部分,才严重破坏了图的协调。
关于ColorMatrix原理上的揭秘就到此,由于我的文化理论水平有限,只能从技术角度来揭秘ColorMatrix的实现原理,说得不好,请原谅!
通过上面对ColorMatrix详尽的技术解剖,我们推出了它的运算公式,有了这些,用程序代码实现ColorMatrix功能,应该很容易了,本文中篇将介绍ColorMatrix功能的具体实现,相信各位高手应该比我更在行。
如有不同看法和疑问,可写在文章评论中,本人将尽可能予以解答。欢迎指导和建议,来信邮箱:maozefa@hotmail.com
分享到:
相关推荐
ColorMatrix是GDI+中的一个核心概念,它是一个5x5的矩阵,用于对图像的颜色(包括Alpha通道)进行几何变换。通过理解并巧妙地应用ColorMatrix,开发者可以实现各种图像变形和色彩效果,创造出丰富多彩的视觉体验。 ...
GDI+(Graphics Device Interface Plus)是Windows操作系统中用于图形绘制和图像处理的一个扩展库,它是GDI(Graphics Device Interface)的升级版本。GDI+提供了丰富的绘图功能,包括矢量图形、位图操作、颜色管理...
Color类提供了创建和管理颜色的方式,而ColorMatrix类则允许你对颜色应用复杂的矩阵运算,实现色彩的精细控制。 在编程实践中,GDI+通常与.NET Framework一起使用,尤其是在C#和VB.NET中。开发者可以通过.NET ...
在本文中,我们将深入探讨如何使用GDI+在VC++环境中实现图片的透明度变化,即淡入淡出效果。GDI+是Windows图形设备接口的一个扩展,它提供了丰富的绘图功能,包括处理图片的透明度。我们将主要关注`AlphaBlend`函数...
反色操作在图像处理中是一项基础功能,GDI+通过调用`ColorMatrix`和`ImageAttributes`类的相关方法可以实现。通过设置特定的色彩矩阵,我们可以反转图像中的颜色,达到黑白、负片的效果。 此外,GDI+的文本渲染能力...
GDI+(Graphics Device Interface Plus)是Windows操作系统中用于图形绘制和图像处理的一个强大的API,它是GDI(Graphics Device Interface)的升级版本,增加了许多现代图形处理的功能。在这个"vc中GDI+的关于数字...
在VB(Visual Basic)编程环境中,GDI+(Graphics Device Interface Plus)是一个强大的图形处理库,用于绘制图形、处理图像以及进行复杂的可视化操作。标题"GBI.rar_gdi+取屏幕反色_vb gdi+"指出,这个压缩包包含了...
- **使用颜色矩阵对单色进行变换**:通过`ColorMatrix`类可以实现对图像的颜色调整。 - **转换图像颜色**:使用颜色矩阵可以改变图像的整体色调。 - **缩放颜色**:通过修改颜色矩阵来改变图像的颜色饱和度。 - **...
GDI+通过`ColorMatrix`类和`ImageAttributes`类实现了图像的色彩调整。`ColorMatrix`是一个5x5的矩阵,用于表示颜色转换,其中第5行用于设置alpha通道(透明度)。我们可以创建一个带有透明度系数的`ColorMatrix`,...
首先,通过设置`ColorMatrix`和`ImageAttributes`对象,我们可以创建一个透明度效果。然后,将带有透明度的`ImageAttributes`传递给`DrawImage`方法,以在图像上绘制半透明的水印图片。对于文字水印,`DrawString`...
- **颜色矩阵**:使用ColorMatrix类和ImageAttributes对象,可以对图像应用复杂的色彩效果。 6. **性能优化** - **缓存绘图结果**:使用Bitmap对象创建内存图,先在内存中完成复杂绘图,再一次性绘制到屏幕,提高...
GDI+(Graphics Device Interface Plus)是Windows操作系统中一个强大的图形处理库,它扩展了传统的GDI(Graphics Device Interface)功能,提供了更多的图形绘制和图像处理能力。GDI+不仅支持2D图形,还引入了对...
ColorMatrix colorMatrix = new ColorMatrix(); colorMatrix.Matrix33 = opacity; ImageAttributes imageAttr = new ImageAttributes(); imageAttr.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ...
Alpha通道决定了像素的透明度,其值范围通常为0(完全透明)到255(完全不透明)。 实现叠加显示的步骤主要包括以下几个方面: 1. **创建Graphics对象**:首先,我们需要一个Graphics对象来绘制图像。这个对象可以...
GDI+提供了一系列的颜色转换函数,如`ColorMatrix`和`ImageAttributes`,可以方便地实现这些操作。 在MFC中,通常会使用`CDC`(Device Context)类来与GDI+交互,通过`CGdiPlusObject`类的封装,可以将GDI+的对象(如...
GDI+ for VCL 版本可以与 VCL 完全集成,开发者可以使用 GDI+ for VCL 进行图形处理和图像处理。 GDI+ for VCL 是一个功能强大且实用的图形处理库,提供了许多实用的图形处理函数和类库,帮助开发者快速开发图形...
8. 图像效果:GDI+提供了一些图像效果函数,如AlphaBlend(透明混合)、ColorMatrix(颜色矩阵)等,可用于实现模糊、反色、灰度转换等特效。 在使用GDI+进行开发时,通常会经历以下几个步骤: 1. 创建Graphics...
`ColorMatrix`类可以用于复杂的颜色变换,如亮度调整、饱和度改变或色调旋转。 此外,GDI+还支持图像处理,例如加载、显示和保存图像,以及进行裁剪、缩放、旋转等操作。`Image`类表示图像对象,`Bitmap`类则用于...
GDI+(Graphics Device Interface Plus)是Windows操作系统中用于图形绘制和图像处理的一套API,它是GDI(Graphics Device Interface)的升级版本,增加了许多现代图形处理的功能。GDI+提供了一个面向对象的编程接口...
在GDI+中,我们可以利用Graphics类的DrawImage方法,通过设置ImageAttributes对象的ColorMatrix属性,来处理图片的Alpha通道,实现透明效果。 接下来,我们来看如何在窗体上加载和显示PNG图片。在VB.NET中,你可以...