矩阵如何:修剪颜色

剪切是指按照与另一种颜色分量成比例的量来增加或减少颜色分量。 例如,考虑这样一种变换,将红色分量增加蓝色分量值的一半。 在这样的变换下,(0.2, 0.5, 1) 颜色将变成 (0.7, 0.5, 1)。 新的颜色分量是 0.2 + (1/2)(1) = 0.7。

示例

下面的示例从文件 ColorBars4.bmp 构造一个 Image 对象。 然后,该代码将上一段中描述的剪切变换应用到图像中的每个像素。

下面的插图在左侧显示原来的图像,在右侧显示剪切后的图像。

下表列出在剪切变换前后,四栏的颜色矢量。

Original剪切后
(0, 0, 1, 1)(0.5, 0, 1, 1)
(0.5, 1, 0.5, 1)(0.75, 1, 0.5, 1)
(1, 1, 0, 1)(1, 1, 0, 1)
(0.4, 0.4, 0.4, 1)(0.6, 0.4, 0.4, 1)

VB

Image image = new Bitmap(“ColorBars.bmp”);
ImageAttributes imageAttributes = new ImageAttributes();
int width = image.Width;
int height = image.Height;

float[][] colorMatrixElements = {
        new float[] {1,  0,  0,  0, 0},
        new float[] {0,  1,  0,  0, 0},
        new float[] {0.5f,  0,  1,  0, 0},
        new float[] {0,  0,  0,  1, 0},
        new float[] {0, 0, 0, 0, 1}};

ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);

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

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

e.Graphics.DrawImage(
   image,
   new Rectangle(150, 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);

编译代码

前面的示例是为使用 Windows 窗体而设计的,它需要 Paint 事件处理程序的参数 PaintEventArgse。 用系统上有效的图像名称和路径替换 ColorBars.bmp

矩阵全局变换和局部变换

全局变换是应用于由给定的 Graphics 对象绘制的每个项目的变换。 与此相反,局部变换则是应用于要绘制的特定项目的变换。

全局变换

若要创建全局变换,请构造 Graphics 对象,再操作其 Transform 属性。 Transform 属性是 Matrix 对象,因此,它能够保存仿射变换的任何序列。 存储在 Transform 属性中的变换被称为世界变换。 Graphics 类提供了几个构建复合世界变换的方法:MultiplyTransformRotateTransformScaleTransformTranslateTransform。 下面的示例绘制了两次椭圆:一次在创建世界变换之前,一次在创建世界变换之后。 变换首先在 y 方向上缩放 0.5 倍,再在 x 方向平移 50 个单位,然后旋转 30 度。

C#

VB

myGraphics.DrawEllipse(myPen, 0, 0, 100, 50);
myGraphics.ScaleTransform(1, 0.5f);
myGraphics.TranslateTransform(50, 0, MatrixOrder.Append);
myGraphics.RotateTransform(30, MatrixOrder.Append);
myGraphics.DrawEllipse(myPen, 0, 0, 100, 50);

下图显示了变换中涉及的矩阵。

System_CAPS_note 注意
在前面的示例中,椭圆围绕坐标系的原点旋转。原点位于工作区的左上角。 与椭圆围绕其自身中心旋转相比,这样会产生不同的结果。

局部变换

局部变换应用于要绘制的特定项目。 例如,GraphicsPath 对象具有 Transform 方法,可用来对该路径的数据点进行变换。 下面的示例绘制了一个没有变换的矩形以及一个有旋转变换的路径。 (假定没有世界变换)。

C#

VB

Matrix myMatrix = new Matrix();
myMatrix.Rotate(45);
myGraphicsPath.Transform(myMatrix);
myGraphics.DrawRectangle(myPen, 10, 10, 100, 50);
myGraphics.DrawPath(myPen, myGraphicsPath);

世界变换可与局部变换合并,以得到多种结果。 例如,世界变换可用于修正坐标系统,而局部变换可用于旋转和缩放在新坐标系统上绘制的对象。

假定您需要原点距工作区左边缘 200 像素、距工作区顶部 150 像素的坐标系统。 此外,假定您需要的度量单位是像素,且 x 轴指向右方,y 轴指向上方。 默认的坐标系统是 y 轴指向下方,因此您需要执行绕水平坐标轴的反射。 下图显示了这样的矩阵反射。

下一步,假定您需要执行一个向右 200 个单位、向下 150 个单位的平移。

下面的示例通过设置 Graphics 对象的世界变换,建立前面刚刚描述过的坐标系统。

C#

VB

Matrix myMatrix = new Matrix(1, 0, 0, -1, 0, 0);
myGraphics.Transform = myMatrix;
myGraphics.TranslateTransform(200, 150, MatrixOrder.Append);

下面的代码(置于前面示例的结尾处)创建了由一个单独矩形组成的路径,该矩形的左下角在新坐标系统的原点。 矩形经过两次填充:一次不使用局部变换,一次使用局部变换。 局部变换包括在水平方向上缩放 2 倍,然后再旋转 30 度。

C#

VB

// Create the path.
GraphicsPath myGraphicsPath = new GraphicsPath();
Rectangle myRectangle = new Rectangle(0, 0, 60, 60);
myGraphicsPath.AddRectangle(myRectangle);

// Fill the path on the new coordinate system.
// No local transformation
myGraphics.FillPath(mySolidBrush1, myGraphicsPath);

// Set the local transformation of the GraphicsPath object.
Matrix myPathMatrix = new Matrix();
myPathMatrix.Scale(2, 1);
myPathMatrix.Rotate(30, MatrixOrder.Append);
myGraphicsPath.Transform(myPathMatrix);

// Fill the transformed path on the new coordinate system.
myGraphics.FillPath(mySolidBrush2, myGraphicsPath);

下图显示了新的坐标系统和两个矩形。