Pregunta

¿Cómo puedo girar el tono de una imagen utilizando GDI+'s ImageAttributes (y, presumiblemente, ColorMatrix)?

Tenga en cuenta que quiero girar el tono, no el matiz de la imagen.

EDITAR:Girando el tono, me refiero a que cada color de la imagen debe ser cambiado a un color diferente, como contraposición a hacer toda la imagen de una sombra de un color.

Por ejemplo,

Original:http://www.codeguru.com/img/legacy/gdi/Tinter03.jpg

Girar: http://www.codeguru.com/img/legacy/gdi/Tinter15.jpg o http://www.codeguru.com/img/legacy/gdi/Tinter17.jpg

¿Fue útil?

Solución 2

Terminé portar QColorMatrix a C # y el uso de su método RotateHue.

Otros consejos

Tiré esto juntos para este tema (archivo ZIP con C # proyecto vinculado en la parte inferior de la enviar). No utiliza ImageAttributes o ColorMatrix, pero gira el tono que usted ha descrito:

//rotate hue for a pixel
private Color CalculateHueChange(Color oldColor, float hue)
{
    HLSRGB color = new HLSRGB(
        Convert.ToByte(oldColor.R),
        Convert.ToByte(oldColor.G),
        Convert.ToByte(oldColor.B));

    float startHue = color.Hue;
    color.Hue = startHue + hue;
    return color.Color;
}

Ha visto este artículo en CodeProject?

A partir de una mirada rápida a la verdad es la página que parece que las matemáticas 4D. Puede adoptar un enfoque similar al contstructing matrices como si se tratara de las matemáticas en 2D o 3D.

Tome una serie de procedencia "puntos" - en este caso, necesitará 4 - y los "puntos" correspondientes de destino y generar una matriz. Esto entonces se puede aplicar a cualquier "punto".

Para hacer esto en 2D (de memoria así que podría haber hecho un aullador completa en este):

puntos de origen son (1, 0) y (0, 1). Los objetivos son (0, -1) y (1,0). La matriz que se necesita es:

(0, -1, 0)
(1,  0, 0)
(0,  0, 1)

Cuando la información adicional es para el valor "w" de la coordenada.

prorrogar este período {R, G, B, A, W} y que tendrá una matriz. Tome 4 colores rojo (1, 0, 0, 0, w), verde (0, 1, 0, 0, w), Azul (0, 0, 1, 0, w) y transparente (0, 0, 0, 1, w). Averiguar qué colores se asignan a en el nuevo esquema y acumular una matriz de la siguiente manera:

  

(R 1 , G 1 , B 1 , A 1 , 0)
  (R 2 , G 2 , B 2 , A 2 , 0)
  (R 3 , G 3 , B 3 , A 3 , 0)
  (R 4 , G 4 , B 4 , A 4 , 0)
  (0, 0, 0, 0, 1)

Nota: El orden lo haces mulitplication (vector * matriz o matriz * vector) determinarán si los puntos transformados van vertical u horizontalmente en esta matriz, como la multiplicación matriz es no conmutativo. Asumo vector * matriz.

Esta es una cuestión de edad, sino soluciones publicados son mucho más complicado que la simple respuesta que he encontrado.

simple:

  • ninguna dependencia externa
  • ningún cálculo complicado (sin averiguar un ángulo de rotación, sin la aplicación de una fórmula coseno)
  • realmente hace una rotación de colores!

Repetir el problema: ¿qué necesitamos

he preparado iconos teñidas de color rojo. Algunas áreas son transparentes, algunos son más o menos saturado, pero todos ellos tienen tonalidad roja. Creo que se adapte a su caso de uso muy bien. Las imágenes pueden tener otros colores, se acaba de girar.

¿Cómo representar el matiz de aplicar? La respuesta más simple es:. Suministrar una Color

Trabajando hacia una solución

ColorMatrix representan una transformación lineal.

Obviamente, cuando es de color rojo, la transformación debe ser la identidad. Cuando el color es verde, la transformación debe mapa rojo a verde, verde a azul, el azul al rojo.

A ColorMatrix que hace esto es:

0 1 0 0 0
0 0 1 0 0
1 0 0 0 0
0 0 0 1 0
0 0 0 0 1

solución matemática

El truco "Aha" es reconocer que la forma real de la matriz es

R G B 0 0
B R G 0 0
G B R 0 0
0 0 0 1 0
0 0 0 0 1

donde R, G y B son simplemente el componente del color tintado!

Código de ejemplo

Tomé código de ejemplo en https://code.msdn.microsoft.com / ColorMatrix-image-Filtros-f6ed20ae .

Me ajusté y, de hecho uso este en mi proyecto:

static class IconTinter
{
    internal static Bitmap TintedIcon(Image sourceImage, Color tintingColor)
    {
        // Following https://code.msdn.microsoft.com/ColorMatrix-Image-Filters-f6ed20ae
        Bitmap bmp32BppDest = new Bitmap(sourceImage.Width, sourceImage.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

        float cr = tintingColor.R / 255.0f;
        float cg = tintingColor.G / 255.0f;
        float cb = tintingColor.B / 255.0f;

        // See [Rotate Hue using ImageAttributes in C#](http://stackoverflow.com/a/26573948/1429390)
        ColorMatrix colorMatrix = new ColorMatrix(
            new float[][]
                       {new float[] { cr,  cg,  cb,  0,  0}, 
                        new float[] { cb,  cr,  cg,  0,  0}, 
                        new float[] { cg,  cb,  cr,  0,  0}, 
                        new float[] {  0,   0,   0,  1,  0}, 
                        new float[] {  0,   0,   0,  0,  1}
                       }
                       );

        using (Graphics graphics = Graphics.FromImage(bmp32BppDest))
        {
            ImageAttributes bmpAttributes = new ImageAttributes();
            bmpAttributes.SetColorMatrix(colorMatrix);

            graphics.DrawImage(sourceImage,
                new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
                0, 0,
                sourceImage.Width, sourceImage.Height,
                GraphicsUnit.Pixel, bmpAttributes);

        }

        return bmp32BppDest;
    }
}

Espero que esto ayude.

Limitación

  • Observe que la transformación puede saturar si utiliza colores demasiado brillantes. Para garantizar no saturación, tt es suficiente que R + G + B <= 1.
  • Usted puede normalizar la transformación dividiendo cr, cg, cb por cr + cg + cb pero manejar el caso donde el color es negro teñido o tendrá que dividir por cero.

El siguiente código crea una ColorMatrix para aplicar un tono cambio.

La visión que yo tenía era que a 60° cambio en el tono de espacio:

  • rojo --> verde
  • verde --> azul
  • azul --> rojo

es en realidad un 45° turno en el espacio RGB:

enter image description here

Así que usted puede convertir algunas fracción de 120° turno en algunas fracciones de 90° turno.

El HueShift el parámetro debe ser un valor entre -1..1.

Por ejemplo, para aplicar un 60° turno:

  • el cambio de rojo a amarillo,
  • cambio de amarillo a verde
  • el cambio de verde a cyan
  • el cambio de cian azul
  • el cambio de azul a magenta
  • cambiar a rojo magenta

llamar a:

var cm = GetHueShiftColorMatrix(60/360); //a value between 0..1

La aplicación:

function GetHueShiftColorMatrix(HueShift: Real): TColorMatrix;
var
    theta: Real;
    c, s: Real;
const
    wedge = 120/360;
begin
    if HueShift > 1 then
        HueShift := 0
    else if HueShift < -1 then
        HueShift := 0
    else if Hueshift < 0 then
        HueShift := 1-HueShift;

    if (HueShift >= 0) and (HueShift <= wedge) then
    begin
        //Red..Green
        theta := HueShift / wedge*(pi/2);
        c := cos(theta);
        s := sin(theta);

        cm[0, 0] :=  c; cm[0, 1] :=  0; cm[0, 2] :=  s; cm[0, 3] :=  0; cm[0, 4] := 0;
        cm[1, 0] :=  s; cm[1, 1] :=  c; cm[1, 2] :=  0; cm[1, 3] :=  0; cm[1, 4] := 0;
        cm[2, 0] :=  0; cm[2, 1] :=  s; cm[2, 2] :=  c; cm[2, 3] :=  0; cm[2, 4] := 0;
        cm[3, 0] :=  0; cm[3, 1] :=  0; cm[3, 2] :=  0; cm[3, 3] :=  1; cm[3, 4] := 0;
        cm[4, 0] :=  0; cm[4, 1] :=  0; cm[4, 2] :=  0; cm[4, 3] :=  0; cm[4, 4] := 1;
    end
    else if (HueShift >= wedge) and (HueShift <= (2*wedge)) then
    begin
        //Green..Blue
        theta := (HueShift-wedge) / wedge*(pi/2);
        c := cos(theta);
        s := sin(theta);

        cm[0, 0] :=  0; cm[0, 1] :=  s; cm[0, 2] :=  c; cm[0, 3] :=  0; cm[0, 4] := 0;
        cm[1, 0] :=  c; cm[1, 1] :=  0; cm[1, 2] :=  s; cm[1, 3] :=  0; cm[1, 4] := 0;
        cm[2, 0] :=  s; cm[2, 1] :=  c; cm[2, 2] :=  0; cm[2, 3] :=  0; cm[2, 4] := 0;
        cm[3, 0] :=  0; cm[3, 1] :=  0; cm[3, 2] :=  0; cm[3, 3] :=  1; cm[3, 4] := 0;
        cm[4, 0] :=  0; cm[4, 1] :=  0; cm[4, 2] :=  0; cm[4, 3] :=  0; cm[4, 4] := 1;
    end
    else
    begin
        //Blue..Red
        theta := (HueShift-2*wedge) / wedge*(pi/2);
        c := cos(theta);
        s := sin(theta);

        cm[0, 0] :=  s; cm[0, 1] :=  c; cm[0, 2] :=  0; cm[0, 3] :=  0; cm[0, 4] := 0;
        cm[1, 0] :=  0; cm[1, 1] :=  s; cm[1, 2] :=  c; cm[1, 3] :=  0; cm[1, 4] := 0;
        cm[2, 0] :=  c; cm[2, 1] :=  0; cm[2, 2] :=  s; cm[2, 3] :=  0; cm[2, 4] := 0;
        cm[3, 0] :=  0; cm[3, 1] :=  0; cm[3, 2] :=  0; cm[3, 3] :=  1; cm[3, 4] := 0;
        cm[4, 0] :=  0; cm[4, 1] :=  0; cm[4, 2] :=  0; cm[4, 3] :=  0; cm[4, 4] := 1;
    end;

    Result := cm;
end;

Nota:Cualquier código es de dominio público.No atribución requerida.

www.aforgenet.com podría ayudar

construyo un método que implementar código @IanBoid en lenguaje C #.

    public void setHueRotate(Bitmap bmpElement, float value) {

        const float wedge = 120f / 360;

        var hueDegree = -value % 1;
        if (hueDegree < 0) hueDegree += 1;

        var matrix = new float[5][];

        if (hueDegree <= wedge)
        {
            //Red..Green
            var theta = hueDegree / wedge * (Math.PI / 2);
            var c = (float)Math.Cos(theta);
            var s = (float)Math.Sin(theta);

            matrix[0] = new float[] { c, 0, s, 0, 0 };
            matrix[1] = new float[] { s, c, 0, 0, 0 };
            matrix[2] = new float[] { 0, s, c, 0, 0 };
            matrix[3] = new float[] { 0, 0, 0, 1, 0 };
            matrix[4] = new float[] { 0, 0, 0, 0, 1 };

        } else if (hueDegree <= wedge * 2)
        {
            //Green..Blue
            var theta = (hueDegree - wedge) / wedge * (Math.PI / 2);
            var c = (float) Math.Cos(theta);
            var s = (float) Math.Sin(theta);

            matrix[0] = new float[] {0, s, c, 0, 0};
            matrix[1] = new float[] {c, 0, s, 0, 0};
            matrix[2] = new float[] {s, c, 0, 0, 0};
            matrix[3] = new float[] {0, 0, 0, 1, 0};
            matrix[4] = new float[] {0, 0, 0, 0, 1};

        }
        else
        {
            //Blue..Red
            var theta = (hueDegree - 2 * wedge) / wedge * (Math.PI / 2);
            var c = (float)Math.Cos(theta);
            var s = (float)Math.Sin(theta);

            matrix[0] = new float[] {s, c, 0, 0, 0};
            matrix[1] = new float[] {0, s, c, 0, 0};
            matrix[2] = new float[] {c, 0, s, 0, 0};
            matrix[3] = new float[] {0, 0, 0, 1, 0};
            matrix[4] = new float[] {0, 0, 0, 0, 1};
        }

        Bitmap originalImage = bmpElement;

        var imageAttributes = new ImageAttributes();
        imageAttributes.ClearColorMatrix();
        imageAttributes.SetColorMatrix(new ColorMatrix(matrix), ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

        grpElement.DrawImage(
            originalImage, elementArea,
            0, 0, originalImage.Width, originalImage.Height,
            GraphicsUnit.Pixel, imageAttributes
            );
    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top