Autor |
Beitrag |
C#
Beiträge: 561
Erhaltene Danke: 65
Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
|
Verfasst: Mi 02.03.16 22:07
Hey Leute,
ich versuche gerade sehr schnelle Farbstrukturen zu erstellen. Ich habe bisher drei eigene Color-Strukturen erstellt die alle schnellere Zugriffe erlauben als die System.Drawing.Color-Struktur.
Meine Performanceanalyse arbeitet wie folgt:
Je 10 Millionen Aufrufe:
1. Initialisiere die eine Variable des entsprechenden Typs mittles new ColorXY(r, g, b)
2. Überschreibe den roten Kanal
3. Überschreibe den grünen Kanal
4. Überschreibe den blauen Kanal
5. Lade den ARGB-Wert in einen lokale Integer Variable
6. Ändere die Integer Variable
7. Schreibe den geänderten Integerwert zurück in die Color-Struktur
Das erste Problem hier ist, dass ich die System.Drawing.Color-Struktur nicht verändern kann und daher in jeder Zeile der Analyse die Struktur komplett neu initialisieren muss...
Jedenfalls ergibt sich nach mehreren Durchläufen folgendes Ergebnis:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51:
| Performance analysis on Color structures
System.Drawing.Color Struct: 1029,169000ms Color1 Struct: 759,546800ms Color2 Struct: 486,970600ms Color3 Struct: 596,709200ms
System.Drawing.Color Struct: 954,173400ms Color1 Struct: 760,178700ms Color2 Struct: 483,463700ms Color3 Struct: 597,622000ms
System.Drawing.Color Struct: 953,712500ms Color1 Struct: 761,958900ms Color2 Struct: 485,843000ms Color3 Struct: 598,601800ms
System.Drawing.Color Struct: 953,704000ms Color1 Struct: 759,919700ms Color2 Struct: 482,397500ms Color3 Struct: 598,858800ms
System.Drawing.Color Struct: 951,736500ms Color1 Struct: 762,630900ms Color2 Struct: 483,027300ms Color3 Struct: 599,863700ms
System.Drawing.Color Struct: 954,577600ms Color1 Struct: 758,925000ms Color2 Struct: 484,936300ms Color3 Struct: 597,930200ms
System.Drawing.Color Struct: 951,582500ms Color1 Struct: 757,759900ms Color2 Struct: 482,331100ms Color3 Struct: 597,216700ms
System.Drawing.Color Struct: 954,226100ms Color1 Struct: 760,384100ms Color2 Struct: 485,471900ms Color3 Struct: 597,050100ms
System.Drawing.Color Struct: 951,759000ms Color1 Struct: 764,923800ms Color2 Struct: 480,794400ms Color3 Struct: 602,168100ms
System.Drawing.Color Struct: 954,407300ms Color1 Struct: 759,317700ms Color2 Struct: 488,296300ms Color3 Struct: 594,308500ms |
Color2 und Color3 sind unsafe Code (Quellcode steht am Ende).
Ich möchte jetzt noch eine weitere Methode testen, jedoch weiß ich nicht wie ich den Code dafür schreibe.
Color4 soll so ähnlich aussehen wie Color2, aber ich würde gerne eine öffentliche Integer Variable anlegen, die den ARGB-Wert hält. Die Felder A, R, G, B (also die einzelnen Farbkanäle) sollen dann Byte-Pointer auf das ARGB Feld sein. Ich kann jedoch keine Pointer außerhalb von fixed-Blöcken verwenden. Da durch das Memmory Management mein ARGB Feld im Speicher rumwandern kann, wäre ein Pointer auf die Addresse relativ sinnfrei.
Es gibt jedoch die Möglichkeit Arrays fest anzupinnen (auch als Klassenvariable) via
C#-Quelltext 1:
| private fixed byte data[4] |
Diese Syntax erinnert mich stark an C und weniger an C#.
Das Array müsste doch jetzt im Speicher angepinnt sein, sodass der Manager es nicht mehr verschiebt, richtig?
Aber wie zur Hölle verwende ich das Array? Ich kann in keiner Weise darauf zugreifen oder es ändern, geschweige denn Pointer darauf zeigen lassen. Egal in welchem Kontext ich das Array verwenden möchte, ich erhalte immer diese Fehlermeldung (auch in fixed-Blöcken):
Zitat: |
Fehler CS1666 Sie können keine Puffer fester Größe verwenden, die in nicht festen Ausdrücken enthalten sind. Verwenden Sie die fixed-Anweisung.
|
Weiß jemand wie ich dieses Problem lösen kann, bzw ob es überhaupt so funktionieren kann? Ich bin auch offen für andere Methoden die geringe Zugriffszeiten ermöglichen.
Das Ganze hat natürlich einen Grund. Ich steige gerade ins Gebiet der Bildverarbeitung (sprich -bearbeitung und -analyse) ein und möchte natürlich die Performance etwas hochschrauben. Das C# und Managed Code nicht die beste Lösung ist, ist mir klar. Aber ich möchte zuerst mal die Grundlagen verstehen und anwenden können, ohne mich mit einer "fremden" Programmiersprache rumzuschlagen. Ich möchte auch keine Bibliotheken (AForge & Co) verwenden, da es mir um die Funktionsweise der Algorithmen und Abläufen geht.
Vielen Dank für eure Hilfe.
Die wichtigsten Codeausschnitte:
Analyse-Kern:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++) { color2 = new Color2(100, 150, 200); color2.R = 0x10; color2.G = 0x20; color2.B = 0x30; int argb = color2.ARGB; argb &= 0x0FFFFFFF; color2.ARGB = argb; } watch.Stop(); |
Color1:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42:
| public struct RGBColor { public uint ARGB { get { return (uint)((A << 24) | (R << 16) | (G << 8) | B); } set { A = (byte) (value >> 24); R = (byte) ((value >> 16) & 0xFF); G = (byte) ((value >> 8) & 0xFF); B = (byte) (value & 0xFF); } }
public byte A { get; set; } public byte R { get; set; } public byte G { get; set; } public byte B { get; set; }
public RGBColor(byte a, byte r, byte g, byte b) { A = a; R = r; G = g; B = b; }
public RGBColor(byte r, byte g, byte b) : this(255, r, g, b) { }
public RGBColor(int argb) : this((uint) argb) {
}
public RGBColor(uint argb) : this((byte)(argb >> 24), (byte)((argb >> 16) & 0xFF), (byte)((argb >> 8) & 0xFF), (byte)(argb & 0xFF)) {
} } |
Color2
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70:
| unsafe struct Color2 { private byte[] argb;
public int ARGB { get { fixed (byte* ptr = &argb[0]) return *ptr; } set { fixed (byte* ptr = &argb[0]) { int* i = (int*) ptr; *i = value; } } }
public byte A { get { return argb[0]; } set { argb[0] = value; } }
public byte R { get { return argb[1]; } set { argb[1] = value; } }
public byte G { get { return argb[2]; } set { argb[2] = value; } }
public byte B { get { return argb[3]; } set { argb[3] = value; } }
public Color2(byte a, byte r, byte g, byte b) { argb = new[] {a, r, g, b}; } public Color2(byte r, byte g, byte b) : this(255, r, g, b) {
}
public Color2(int argb) : this((uint) argb) {
}
public Color2(uint argb) { this.argb = new byte[4];
unchecked { ARGB = (int)argb; } }
} |
Color3
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114:
| unsafe struct Color3 { public int ARGB; public byte A { get { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*) ptr; return *ptr2; } } set { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; *ptr2 = value; } } }
public byte R { get { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; return ptr2[1]; } } set { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; ptr2[1] = value; } } }
public byte G { get { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; return ptr2[2]; } } set { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; ptr2[2] = value; } } }
public byte B { get { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; return ptr2[3]; } } set { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; ptr2[3] = value; } } }
public Color3(byte a, byte r, byte g, byte b) { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*) ptr; *ptr2++ = a; *ptr2++ = r; *ptr2++ = g; *ptr2 = b; } }
public Color3(byte r, byte g, byte b) : this(255, r, g, b) {
}
public Color3(int argb) { ARGB = argb; }
public Color3(uint argb) { unchecked { ARGB = (int)argb; } } } |
_________________ Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
|
|
Ralf Jansen
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mi 02.03.16 23:33
Wenn ich die Beschreibung zum Compilerfehler in der MSDN richtig verstehe ist das Problem das sich die Instanz des struct noch verschieben könnte in dem sich das Array befindet. Also mußt du this auch fixen.
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
| unsafe struct Color4 { private fixed byte data[4];
public byte A { get { fixed (Color4* that = &this) { return that->data[0]; } } set { fixed (Color4* that = &this) { byte* ptr = &(that->data[0]); *ptr = value; } } }
} |
Zitat: | Aber ich möchte zuerst mal die Grundlagen |
Das hat wohl eher nix mit Grundlagen zu tun. Schon gar nicht mit Grundlagen bezüglich Bildverarbeitung. Du möchtest etwas gegen das System tun. So versteht man vielleicht mehr von Winforms und .Net aber eher weniger über allgemeine Bildverarbeitung.
Für diesen Beitrag haben gedankt: C#, FinnO
|
|
C#
Beiträge: 561
Erhaltene Danke: 65
Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
|
Verfasst: Do 03.03.16 19:14
Hey
Danke für die Antwort. Ich werde wohl leider nicht vor morgen abend zum testen kommen...
Was die Grundlagengeschichte angeht hast du schon recht. Dieses Problem hat nichts mit Bildverarbeitung zu tun aber ich kann dann auf dieser Grundlage die Algorithmen implementieren. Ich wollte nur vermeiden, dass irgendwelche Verweise auf Bibliotheken kommen.
Ich weiß ich sollte eigentlich einen neuen Thread aufmachen, aber wenn wir hier schon im Kontext Bildverarbeitung sind...
Hat jemand einen Tipp zu Literatur zum Thema? In digitaler Form oder als Buch ist egal. Etwas mit Code anstatt mathematischen Formeln wäre gut (und wenn es nur Pseudocode ist). Versteht mich nicht falsch, es können Formeln vorkommen aber bitte keine Formelsammlung.
_________________ Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
|
|
Christian S.
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Do 03.03.16 20:14
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
Th69
Beiträge: 4777
Erhaltene Danke: 1054
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Fr 04.03.16 04:20
Für diesen Beitrag haben gedankt: C#
|
|
C#
Beiträge: 561
Erhaltene Danke: 65
Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
|
Verfasst: Fr 04.03.16 22:20
Zitat: | Du dürftest mit einem separaten Thread die Chance auf Antworten deutlich erhöhen, weil Du dann z.B. auch alle Delphianer erreichst |
Haste schon recht
@Th69
Danke für den Link. Das Buch sieht gut aus. Ich habs mir mal bei Amazon bestellt (3. Auflage). Mal sehen was alles drin steht.
@Ralf
Ich werden wohl nicht vor Sonntag zum Testen kommen, aber ich melde mich nochmal sobald ich Resultate habe.
Danke euch!
_________________ Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
|
|
C#
Beiträge: 561
Erhaltene Danke: 65
Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
|
Verfasst: So 06.03.16 13:59
So jetzt habe ich die Tests endlich abgeschlossen.
@Ralf: Danke, dein Code hat wunderbar funktioniert.
Die neuen Resultate:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36:
| Performance analysis on Color structures
System.Drawing.Color Struct: 1086,931500m Color1 Struct: 762,224900ms Color2 Struct: 485,195900ms Color3 Struct: 596,397800ms Color4 Struct: 361,785300ms Color5 Struct: 547,800700ms
System.Drawing.Color Struct: 945,876900ms Color1 Struct: 761,275300ms Color2 Struct: 467,343900ms Color3 Struct: 591,542300ms Color4 Struct: 361,588300ms Color5 Struct: 531,071000ms
System.Drawing.Color Struct: 945,333500ms Color1 Struct: 759,083600ms Color2 Struct: 466,066400ms Color3 Struct: 591,142300ms Color4 Struct: 361,664100ms Color5 Struct: 516,349500ms
System.Drawing.Color Struct: 948,116900ms Color1 Struct: 758,749700ms Color2 Struct: 471,258100ms Color3 Struct: 588,317000ms Color4 Struct: 360,355900ms Color5 Struct: 528,673000ms
System.Drawing.Color Struct: 941,691000ms Color1 Struct: 758,734700ms Color2 Struct: 470,732800ms Color3 Struct: 592,614900ms Color4 Struct: 361,311200ms Color5 Struct: 519,254700ms |
Color4:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37:
| unsafe struct Color4 { private fixed byte data[4];
public byte* A, R, G, B;
public int* ARGB;
public Color4(byte a, byte r, byte g, byte b) { A = R = G = B = null;
fixed (Color4* c = &this) { byte* ptr = &(c->data[0]); ARGB = (int*) ptr;
*ptr = b; B = ptr++;
*ptr = g; G = ptr++;
*ptr = r; R = ptr++;
*ptr = a; A = ptr; } }
public Color4(byte r, byte g, byte b) : this(255, r, g, b) {
} } |
Color 5:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56:
| unsafe struct Color5 { private fixed byte data [4];
private readonly byte* aPtr; private readonly int* argbPtr;
public int ARGB { get { return *argbPtr; } set { *argbPtr = value; } }
public byte B { get { return *aPtr; } set { *aPtr = value; } }
public byte G { get { return *(aPtr + 1); } set { *(aPtr + 1) = value; } }
public byte R { get { return *(aPtr + 2); } set { *(aPtr + 2) = value; } }
public byte A { get { return *(aPtr + 3); } set { *(aPtr + 3) = value; } }
public Color5(byte a, byte r, byte g, byte b) { fixed (Color5* c = &this) { aPtr = &(c->data[0]); argbPtr = (int*) aPtr; A = a; R = r; G = g; B = b; } }
public Color5(byte r, byte g, byte b) : this(255, r, g, b) {
} } |
Da Color4 nur mit Pointer arbeitet und Color4 und Color5 nicht sicher sind gegen Verschiebungen im Speicher hat sich das mit den beiden erledigt und ich werde mal mehr mit Color2 arbeiten.
Danke für eure Hilfe.
_________________ Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
|
|
|