如何:使用颜色矩阵转换单个颜色

GDI+ 提供 ImageBitmap 类用于存储和处理图像。 ImageBitmap 对象将每个像素的颜色存储为 32 位数字:每个像素的红色、绿色、蓝色和 alpha 各有 8 位。 这四个组件中的每一个都是从 0 到 255 的数字,0 表示无强度,255 表示完全强度。 alpha 分量指定颜色的透明度:0 完全透明,255 完全不透明。

颜色矢量是形式(红色、绿色、蓝色、alpha)的 4 元组。 例如,颜色矢量(0,255,0,255)表示没有红色或蓝色的不透明颜色,但在完全强度下具有绿色。

另一个表示颜色的约定使用数字 1 表示完全强度。 使用该约定,上一段中描述的颜色将由向量(0、1、0、1)表示。 GDI+ 在执行颜色转换时使用 1 的约定作为全强度。

通过将颜色向量乘以 4×4 矩阵,可以将线性转换(旋转、缩放和类似)应用于颜色向量。 但是,不能使用 4×4 矩阵执行翻译(非线性)。 如果将虚拟第五个坐标(例如数字 1)添加到每个颜色矢量,则可以使用 5×5 矩阵来应用线性变换和平移的任意组合。 由线性变换和位移构成的变换称为仿射变换。

例如,假设要从颜色(0.2、0.0、0.4、1.0)开始,并应用以下转换:

  1. 将红色分量加倍

  2. 将 0.2 添加到红色、绿色和蓝色组件

以下矩阵乘法将按列出的顺序执行转换对。

转换乘法矩阵的屏幕截图。

颜色矩阵的元素按行和列编制索引(从零开始)。 例如,矩阵 M 第五行和第三列中的条目由 M[4][2]该条目表示。

5×5 单位矩阵(如下图所示)在对角线上有 1,其余位置有 0。 如果将颜色矢量乘以标识矩阵,则颜色矢量不会更改。 形成颜色转换矩阵的一种便捷方法是从单位矩阵开始,并进行微小的更改,以实现所需的转换。

用于颜色转换的 5x5 标识矩阵的屏幕截图。

有关矩阵和转换的更详细讨论,请参阅 坐标系和转换

示例:

以下示例采用所有一种颜色(0.2、0.0、0.4、1.0)的图像,并应用上述段落中所述的转换。

下图显示了左侧的原始图像和右侧的转换图像。

左侧的紫色正方形和右侧的紫红色正方形。

以下示例中的代码使用以下步骤执行重新着色:

  1. 初始化ColorMatrix对象。

  2. 创建对象ImageAttributes并将对象传递给ColorMatrixSetColorMatrix对象的方法ImageAttributes

  3. ImageAttributes 对象传递给 DrawImage 对象的 Graphics 方法。

Image image = new Bitmap("InputColor.bmp");
ImageAttributes imageAttributes = new ImageAttributes();
int width = image.Width;
int height = image.Height;

float[][] colorMatrixElements = {
   new float[] {2,  0,  0,  0, 0},        // red scaling factor of 2
   new float[] {0,  1,  0,  0, 0},        // green scaling factor of 1
   new float[] {0,  0,  1,  0, 0},        // blue scaling factor of 1
   new float[] {0,  0,  0,  1, 0},        // alpha scaling factor of 1
   new float[] {.2f, .2f, .2f, 0, 1}};    // three translations of 0.2

ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);

imageAttributes.SetColorMatrix(
   colorMatrix,
   ColorMatrixFlag.Default,
   ColorAdjustType.Bitmap);

e.Graphics.DrawImage(image, 10, 10);

e.Graphics.DrawImage(
   image,
   new Rectangle(120, 10, width, height),  // destination rectangle
   0, 0,        // upper-left corner of source rectangle
   width,       // width of source rectangle
   height,      // height of source rectangle
   GraphicsUnit.Pixel,
   imageAttributes);
Dim image As New Bitmap("InputColor.bmp")
Dim imageAttributes As New ImageAttributes()
Dim width As Integer = image.Width
Dim height As Integer = image.Height

' The following matrix consists of the following transformations:
' red scaling factor of 2
' green scaling factor of 1
' blue scaling factor of 1
' alpha scaling factor of 1
' three translations of 0.2
Dim colorMatrixElements As Single()() = { _
   New Single() {2, 0, 0, 0, 0}, _
   New Single() {0, 1, 0, 0, 0}, _
   New Single() {0, 0, 1, 0, 0}, _
   New Single() {0, 0, 0, 1, 0}, _
   New Single() {0.2F, 0.2F, 0.2F, 0, 1}}

Dim colorMatrix As New ColorMatrix(colorMatrixElements)

imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)

e.Graphics.DrawImage(image, 10, 10)

e.Graphics.DrawImage( _
   image, _
   New Rectangle(120, 10, width, height), _
   0, _
   0, _
   width, _
   height, _
   GraphicsUnit.Pixel, _
   imageAttributes)

编译代码

前面的示例设计用于 Windows 窗体,它需要 PaintEventArgse,这是 Paint 事件处理程序的参数。

另请参阅