Практическое руководство. Поворот цветов

Поворот в четырехмерном цветовом пространстве трудно визуализировать. Мы можем упростить визуализацию поворота, согласившись сохранять один из компонентов цвета фиксированным. Предположим, мы согласились сохранять альфа-компонент равным в 1 (полностью непрозрачным). После этого можно визуализировать трехмерное цветовое пространство с осями, соответствующими красному, зеленому и синему компонентам, как показано на рисунке ниже.

Illustration that shows rotation with red, green, and blue axes.

Цвет можно рассматривать как точку в трехмерном пространстве. Например, точка с координатами (1, 0, 0) в пространстве представляет красный цвет, а точка с координатами (0, 1, 0) — зеленый цвет.

На рисунке ниже показано, что означает поворот цвета (1, 0, 0) на 60 градусов в плоскости "красный-зеленый". Поворот в плоскости, параллельной плоскости "красный-зеленый", можно рассматривать как поворот вокруг оси синего компонента.

Illustration that shows rotation about the blue axis.

На рисунке ниже показано, как инициализировать цветовую матрицу для выполнения поворота вокруг каждой из трех осей координат (красный, зеленый, синий):

Initialize a color matrix to perform rotations about three axes.

Пример

В следующем примере берется изображение, состоящее полностью из одного цвета (1, 0, 0,6), и к нему применяется поворот на 60 градусов вокруг оси синего компонента. Угол поворота проходит по плоскости, параллельной плоскости "красный-зеленый".

На следующем рисунке показано исходное изображение слева и изображение с поворотом цвета справа:

Illustration that shows original image and color-rotated image.

На следующем рисунке показана визуализация поворота цвета, выполненного в приведенном ниже коде:

Illustration that shows the visualization of the color rotation.

private void RotateColors(PaintEventArgs e)
{
    Bitmap image = new Bitmap("RotationInput.bmp");
    ImageAttributes imageAttributes = new ImageAttributes();
    int width = image.Width;
    int height = image.Height;
    float degrees = 60f;
    double r = degrees * System.Math.PI / 180; // degrees to radians

    float[][] colorMatrixElements = {
        new float[] {(float)System.Math.Cos(r),  (float)System.Math.Sin(r),  0,  0, 0},
        new float[] {(float)-System.Math.Sin(r),  (float)-System.Math.Cos(r),  0,  0, 0},
        new float[] {0,  0,  2,  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);
}
Private Sub RotateColors(ByVal e As PaintEventArgs)
    Dim image As Bitmap = New Bitmap("RotationInput.bmp")
    Dim imageAttributes As New ImageAttributes()
    Dim width As Integer = image.Width
    Dim height As Integer = image.Height
    Dim degrees As Single = 60.0F
    Dim r As Double = degrees * System.Math.PI / 180 ' degrees to radians
    Dim colorMatrixElements As Single()() = { _
       New Single() {CSng(System.Math.Cos(r)), _
                     CSng(System.Math.Sin(r)), 0, 0, 0}, _
       New Single() {CSng(-System.Math.Sin(r)), _
                     CSng(-System.Math.Cos(r)), 0, 0, 0}, _
       New Single() {0, 0, 2, 0, 0}, _
       New Single() {0, 0, 0, 1, 0}, _
       New Single() {0, 0, 0, 0, 1}}

    Dim colorMatrix As New ColorMatrix(colorMatrixElements)

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

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

    ' Pass in the destination rectangle (2nd argument), the upper-left corner 
    ' (3rd and 4th arguments), width (5th argument),  and height (6th 
    ' argument) of the source rectangle.
    e.Graphics.DrawImage( _
       image, _
       New Rectangle(150, 10, width, height), _
       0, 0, _
       width, _
       height, _
       GraphicsUnit.Pixel, _
       imageAttributes)
End Sub

Компиляция кода

Предыдущий пример предназначен для работы с Windows Forms, и для него необходим объект PaintEventArgse, передаваемый в качестве параметра обработчику событий Paint. Замените RotationInput.bmp на имя файла с изображением, имеющегося в системе, и путь к нему.

См. также