Domanda

Come posso ruotare la tonalità di un'immagine utilizzando GDI+ ImageAttributes (e presumibilmente ColorMatrix)?

Tieni presente che desidero ruotare la tonalità, non colorare l'immagine.

MODIFICARE:Ruotando la tonalità, intendo che ogni colore dell'immagine dovrebbe essere spostato su un colore diverso, invece di rendere l'intera immagine una sfumatura di un colore.

Per esempio,

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

Ruotato: http://www.codeguru.com/img/legacy/gdi/Tinter15.jpg O http://www.codeguru.com/img/legacy/gdi/Tinter17.jpg

È stato utile?

Soluzione 2

Ho finito il porting QColorMatrix per C # e utilizzando il suo metodo RotateHue.

Altri suggerimenti

ho buttato questo insieme per questa domanda (file ZIP con il progetto C # collegato alla parte inferiore della inviare). Non usa ImageAttributes o ColorMatrix, ma ruota la tonalità come hai descritto:

//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;
}

Hai visto questo articolo su CodeProject?

Da uno sguardo certamente veloce alla pagina sembra che la matematica 4D. È possibile adottare un approccio simile a contstructing matrici come si farebbe per la matematica 2D o 3D.

Prendere una serie di sorgenti "punti" - in questo caso avrete bisogno di 4 - e le corrispondenti "punti" di destinazione e generare una matrice. Questo può essere applicato a qualsiasi "punto".

Per fare questo in 2D (a memoria così ho potuto fare uno svarione completa in questo):

i punti di origine sono (1, 0) e (0, 1). Gli obiettivi sono (0, -1) e (1,0). La matrice di cui hai bisogno è:

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

Se le informazioni in più è per il valore "w" del punto.

Estendere questo fino a {R, G, B, A, w} e avrai una matrice. Prendere 4 colori Rosso (1, 0, 0, 0, w), Verde (0, 1, 0, 0, w), Blu (0, 0, 1, 0, w) e trasparente (0, 0, 0, 1, w). Capire che cosa i colori che mappano nel nuovo schema e costruire la vostra matrice come segue:

  

(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: L'ordine ti mulitplication (vettore * matrice o matrice * vettoriale) determinerà se i punti trasformati vanno verticalmente o orizzontalmente in questa matrice, come matrice moltiplicazione è non-commutativo. Sto assumendo matrice vettore *.

Questa è una vecchia questione, ma le soluzioni postate sono molto più complicata di quanto la semplice risposta che ho trovato.

Semplice:

  • nessuna dipendenza esterna
  • nessun calcolo complicato (senza capire un angolo di rotazione, senza applicazione di una formula cosinus)
  • realmente fa una rotazione di colori!

Riaffermando il problema: cosa abbiamo bisogno

Ho preparato icone colorate di rosso. Alcune aree sono trasparenti, alcuni sono più o meno saturo, ma tutti hanno colore rosso. Penso che corrisponde al tuo caso d'uso molto bene. Le immagini possono avere altri colori, saranno solo essere ruotati.

Come rappresentare la tinta da applicare? La risposta più semplice è:. Fornire un Color

Lavorare per una soluzione

ColorMatrix rappresentano una trasformazione lineare.

Ovviamente quando Il colore è rosso, la trasformazione deve essere l'identità. Quando il colore è verde, la trasformazione dovrebbe mappa rosso a verde, verde al blu, blu al rosso.

Un ColorMatrix che fa questo è:

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

soluzione matematica

Il trucco "aha" è riconoscere che la forma effettiva della matrice è

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

dove R, G e B sono semplicemente il componente del colore di tinta!

Codice di esempio

Ho preso esempio di codice su https://code.msdn.microsoft.com / ColorMatrix-image-Filtri-f6ed20ae .

Ho modificato e in realtà uso questo nel mio progetto:

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;
    }
}

Spero che questo aiuti.

Limitazione

  • Si noti che la trasformazione può saturare se si utilizzano i colori troppo brillanti. Per garantire, saturazione, tt è sufficiente che R + G + B <= 1.
  • È possibile normalizzare la trasformazione dividendo cr, CG, CB da CR + cg + cb ma gestire il caso in cui il colore colorazione è nero o ti dividere per zero.

Il codice seguente costruisce a ColorMatrix per applicare uno spostamento di tonalità.

L'intuizione che ho avuto è stata che con uno spostamento di 60° nello spazio della tonalità:

  • rosso --> verde
  • verde --> blu
  • blu --> rosso

è in realtà uno spostamento di 45° nello spazio RGB:

enter image description here

Quindi puoi trasformare una frazione di uno spostamento di 120° in una frazione di uno spostamento di 90°.

IL HueShift il parametro deve essere un valore compreso tra -1..1.

Ad esempio, per applicare uno spostamento di 60°:

  • cambiando il rosso in giallo,
  • cambiando il giallo in verde
  • cambiando il verde in ciano
  • cambiando il ciano in blu
  • cambiando il blu in magenta
  • cambiando il magenta in rosso

chiami:

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

Implementazione:

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:Qualsiasi codice viene rilasciato nel pubblico dominio.Nessuna attribuzione richiesta.

www.aforgenet.com potrebbe aiutare

I costruire un metodo che implementa il codice @IanBoid in linguaggio 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
            );
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top