Farbton mithilfe von ImageAttributes in C# drehen
-
22-08-2019 - |
Frage
Wie kann ich den Farbton eines Bildes mithilfe von GDI+ drehen? ImageAttributes
(und vermutlich ColorMatrix
)?
Beachten Sie, dass ich den Farbton drehen und nicht das Bild tönen möchte.
BEARBEITEN:Mit dem Drehen des Farbtons meine ich, dass jede Farbe im Bild in eine andere Farbe verschoben werden sollte, anstatt das gesamte Bild in einen Farbton einer Farbe zu verwandeln.
Zum Beispiel,
Original:http://www.codeguru.com/img/legacy/gdi/Tinter03.jpg
Gedreht: http://www.codeguru.com/img/legacy/gdi/Tinter15.jpg oder http://www.codeguru.com/img/legacy/gdi/Tinter17.jpg
Lösung 2
Ich landete Portierung QColorMatrix C # und mit seiner RotateHue
Methode.
Andere Tipps
Ich warf zusammen diese für diese Frage (ZIP-Datei mit Projekt c # an der Unterseite der verlinkten Post). Es verwendet nicht ImageAttributes
oder ColorMatrix
, aber es dreht sich um den Farbton wie Sie beschrieben haben:
//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;
}
Haben Sie gesehen diesem Artikel auf Codeproject?
Von einem zugegebenermaßen kurzen Blick auf der Seite sieht es aus wie 4D Mathematik. Sie können einen ähnlichen Ansatz verfolgen zu contstructing Matrizen wie für 2D- oder 3D-Mathematik.
Nehmen Sie eine Reihe von Quelle „Punkte“ - in diesem Fall werden Sie 4 müssen - und die entsprechenden Ziel „Punkte“ und eine Matrix erzeugen. Dies kann dann zu jedem „Punkt“ angewandt werden.
diese in 2D zu tun (aus dem Gedächtnis, so konnte ich einen kompletten Heuler in diesen gemacht habe):
Quellpunkte (1, 0) und (0, 1). Die Ziele sind (0, -1) und (1,0). Die Matrix Sie brauchen, ist:
(0, -1, 0)
(1, 0, 0)
(0, 0, 1)
Wenn die zusätzlichen Informationen für den „w“ Wert der Koordinate.
Erweitern Sie diese bis zu {R, G, B, A, w} und Sie werden eine Matrix haben. Nehmen Sie 4 Farben Rot (1, 0, 0, 0, w), Grün (0, 1, 0, 0, w), Blau (0, 0, 1, 0, w) und Transparent (0, 0, 0, 1, w). Trainieren Sie, welche Farben die in der Umgebung in das neue System und bauen Sie Ihre Matrix wie folgt:
(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)
Hinweis: Die Reihenfolge Sie tun Sie mulitplication (Vektor * Matrix oder eine Matrix * Vektor) wird geprüft, ob die transformierten Punkte gehen vertikal oder horizontal in diese Matrix als Matrixmultiplikation nichtkommutative ist. Ich gehe davon aus Vektor * Matrix.
Dies ist eine alte Frage, aber Lösungen geschrieben sind viel komplizierter als die einfache Antwort, die ich gefunden.
Ganz einfach:
- keine externe Abhängigkeit
- keine komplizierte Berechnung (keine Bezifferung einen Drehwinkel aus, keine etwas Cosinus Formel Anwendung)
- tatsächlich tut, eine Drehung von Farben!
Neuformulierung des Problems: Was brauchen wir
I vorbereitet Icons rot gefärbt. Einige Bereiche sind transparent, einige sind mehr oder weniger gesättigt, aber sie haben alle roten Farbton. Ich glaube, es entspricht Ihren sehr gut Anwendungsfall. Die Bilder können auch andere Farben haben, werden sie nur gedreht werden.
Wie die Tönung darstellen bewerben? Die einfachste Antwort ist: a. Color
liefern
Arbeiten an einer Lösung
ColorMatrix
eine lineare Transformation.
Natürlich, wenn Farbe rot ist, sollte die Transformation Identität sein. Wenn Farbe grün ist, sollte die Transformation rote Karte zu grün, grün zu blau, blau bis rot.
Ein Colormatrix, das tut dies:
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
Mathematische Lösung
Der "Aha" Trick besteht darin, zu erkennen, dass die tatsächliche Form der Matrix
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
, wobei R, G und B ist einfach die Komponente der Abtönfarbe!
Beispielcode
Ich habe Beispiel-Code auf https://code.msdn.microsoft.com / Colormatrix-Bild-Filter-f6ed20ae .
ich es eingestellt und das ist eigentlich in meinem Projekt verwenden:
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;
}
}
Hope, das hilft.
Begrenzung
- Beachten Sie, dass die Transformation sättigen kann, wenn man zu helle Farben verwenden. Um keine Sättigung zu gewährleisten, tt ist ausreichend, dass R + G + B <= 1.
- Sie können die Transformation normalisieren, indem man cr, cg, cb von Cr + cg + cb aber den Fall behandeln, in denen Tönungsfarbe schwarz ist, oder Sie werden durch Null teilen.
Der folgende Code erstellt a ColorMatrix
zum Anwenden einer Farbtonverschiebung.
Die Erkenntnis, die ich hatte, war, dass bei einer 60°-Verschiebung im Farbtonraum:
- rot -> grün
- grün -> blau
- blau -> rot
ist eigentlich eine 45°-Verschiebung im RGB-Raum:
Sie können also einen Bruchteil einer 120°-Verschiebung in einen Bruchteil einer 90°-Verschiebung umwandeln.
Der HueShift
Parameter muss ein Wert zwischen sein -1..1
.
Um beispielsweise eine 60°-Verschiebung anzuwenden:
- rot zu gelb wechseln,
- wechselt von gelb nach grün
- wechselt von Grün zu Cyan
- Cyan in Blau ändern
- Blau in Magenta ändern
- Magenta in Rot ändern
Du rufst an:
var cm = GetHueShiftColorMatrix(60/360); //a value between 0..1
Implementierung:
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;
Notiz:Jeder Code wird öffentlich zugänglich gemacht.Keine Quellenangabe erforderlich.
Ich nehme an, dass www.aforgenet.com helfen könnte
Ich baue eine Methode, die @IanBoid Code in C # implementieren.
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
);
}