Autor Beitrag
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: 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:
ausblenden volle Höhe 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:
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
ausblenden 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:
ausblenden 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(100150200);
                    color2.R = 0x10;
                    color2.G = 0x20;
                    color2.B = 0x30;
                    int argb = color2.ARGB;
                    argb &= 0x0FFFFFFF;
                    color2.ARGB = argb;
                }
                watch.Stop();

Color1:
ausblenden volle Höhe 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:
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
ausblenden volle Höhe 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:
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
ausblenden volle Höhe 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:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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.

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

    // u.s.w.
}



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# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: 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.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Do 03.03.16 20:14 
user profile iconC# hat folgendes geschrieben Zum zitierten Posting springen:
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.
Du dürftest mit einem separaten Thread die Chance auf Antworten deutlich erhöhen, weil Du dann z.B. auch alle Delphianer erreichst ;-)

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 04.03.16 04:20 

Für diesen Beitrag haben gedankt: C#
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: 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# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: So 06.03.16 13:59 
So jetzt habe ich die Tests endlich abgeschlossen.

@Ralf: Danke, dein Code hat wunderbar funktioniert.

Die neuen Resultate:
ausblenden volle Höhe 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:
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:
ausblenden volle Höhe 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:
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:
ausblenden volle Höhe 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:
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