byte Mittelwert aus 3 Werte.

  • VB.NET

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Um eine Bereichsüberschreitung zu vermeiden, solltest Du die Werte in Integer konvertieren.
    Außerdem empfiehlt es sich, Rundungseffekte durch Addition von 1 auszugleichen:

    VB.NET-Quellcode

    1. Dim a, b, c As Byte
    2. Dim Summe As Byte
    3. a = 123
    4. b = 254
    5. c = 38
    6. Summe = CByte((CInt(a) + CInt(b) + CInt(c) + 1) \ 3)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    ThuCommix schrieb:

    Und was soll da die +1 bringen? Benutz einfach Math.Round(Expression, 0)

    Math.Round() liefert Double, ist überflüssig.
    Mach Dir eine Tabelle:
    a, b, c - die Werte, M1 - mein Mittelwerrt (mit +1), M2 - Dein Mittelwert (ohne + 1)
    a b c M1 M2
    0 0 0 0 0 egal
    0 0 1 0 0 egal
    0 1 1 1 0 M1 ist besser als M2. Darum.
    usw.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hi
    Wenn du die Rechnung auf Integer-Division zurückführst, kommt es zu einem Genauigkeitsfehler:
    A\3 + B\3 + C\3 <> A/3 + B/3 + C/3
    Das kommt daher, dass bei einer Addition die Nachkommastellen zu einem +1 bzw. +2 führen können.
    Daher ist es besser, CByte((CShort(A)+CShort(B)+CShort(C))\3) zu rechnen. Bei einer Addition würde der Bereich eines Bytes überschritten (z.B. 255 + 255 + 255 als Extremfall). Das mit der +1 kannst du auch machen, damit sollten Rundungsfehler entfernt werden, da bei einer Integer-Division der Rest einfach abgeschnitten wird.

    Gruß
    ~blaze~
    @~blaze~:
    Was hast Du jetzt jejenüber meinem vorletzten Beitrag gekonnt?
    @Lightsource:
    (a / 3) ist Double-Division, da musst Du das Ergebnis von Double nach Byte konvertieren,
    (a \ 3) ist Integer-Division, da musst Du das Ergebnis von Integer nach nach Byte konvertieren.
    Ohne Konvertierung geht es nicht.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Eben genau das mit der Integer-Division... Außerdem genügen auch Shorts, was den Speicherbedarf etwas reduziert (nicht alle Prozessoren rechnen zwangsweise mit Integern). Außerdem habe ich LightSource erklärt, warum seine Methode nicht so effizient ist. Im übrigen sind die meisten Prozessoren auf Ganzzahl-Rechnungen optimiert. Die Zahl der Gleitkommaoperationen in einem bestimmten Zeitraum ist wesentlich geringer, als die von Ganzzahlen (gerade von Doubles).

    Gruß
    ~blaze~
    Danke Euch

    Ich hatte natürlich die Integer Division gemeint, aber das hatte ich alles auf meinem Handy geschrieben ;(

    Eigentlich geht es mir nicht um exakte Ergebnisse, da ich sowieso noch mit einem Threshold arbeiten muss.
    Ich bin dabei, ein Bild erst in Schwarz/Weiß zu wandeln, und dann für einen Etikettendrucker aufzubereiten.

    Ich muss die Farbwerte addieren R+G+B und den Mittelwert ermitteln.
    (In meinem Fall handelt es sich um Byte-Werte)

    Um nicht in den Überlauf zu geraten, teile ich jeweils die Bytewerte einzeln durch 3 und addiere sie anschließend.

    Bei mir kommt es auf Geschwindigkeitsoptimierung an. Wenn ich jeweils vor und zurück in andere Zahlenbereiche
    wandeln muss, so wird mir das doch bestimmt Zeit kosten. In Assembler würde ich mir da überhaupt keine
    Gedanken machen, da mich eine Ungenauigkeit bei der Division durch 3 nicht interessieren würde.

    Die Frage die allerdings noch bleibt, rechnet der Prozessor schneller mit Byte oder mit Integern?
    Da gab es doch diese Sache mit der Position der Bytes im Speicher etc.

    Bei einem 600*600Pixel Bild benötige ich immerhin schon 10sek (Trotz LockBits)

    Möglicherweise könnte ich die Berechnung in mehrere Threads aufteilen. Das habe ich in diesem Fall
    noch nicht versucht, weiß z.B. nicht, ob ich auf das Byte Array von verschiedenen Threads aus zugreifen
    könnte.

    Lightsource schrieb:

    Die Frage die allerdings noch bleibt, rechnet der Prozessor schneller mit Byte oder mit Integern?

    Das ist egal, die Werte werden zur Rechnung alle in Integer / Long (32 / 64 Bit) konvertiert.
    Echt schnell wirst Du, wenn Du mit LockBits arbeitest:

    VB.NET-Quellcode

    1. Dim bmpData As System.Drawing.Imaging.BitmapData
    2. bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat)
    3. Dim ptr As IntPtr = bmpData.Scan0
    4. ' ...
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Lightsource schrieb:

    Wenn ich jeweils vor und zurück in andere Zahlenbereiche
    wandeln muss, so wird mir das doch bestimmt Zeit kosten.

    Bei Ganzzahl eher nicht. Da wird nämlich nix "konvertiert".
    Kannste ja einfach mal mit ner Minifunktion testen und dein Projekt dann durch den ILDasm (ist bei jeder Installation von VS mit drin) hauen.

    BTW: Wenn du "schnell" haben willst, würde ich mir mal Framewave (oder OpenCV) runterladen. Bei "typischen" Bildaktionen ist das dann recht flott. Alternativ gleich AForge.Net.
    Das macht er bereits. Ist die Umrechnung so beabsichtigt? Die Helligkeit der Farbe ergibt sich nicht aus dem Mittelwert der Farbwerte. Schau dir dazu mal den HSB-Farbraum bei Wikipedia an. Ich empfehle, nicht über die Color-Klasse zu arbeiten, denn die enthält jede Menge unnötige Einträge und gibt außerdem Single-Werte zurück, die du ja vermeiden möchtest. Da berechnest du lieber die Farbkanäle durch Bitshifts und -masken. Am besten kopierst du dir die Pixel-Daten in ein Array, bevor du auf sie zugreifst (das hatten wir schon mal irgendwo).

    Gruß
    ~blaze~

    ~blaze~ schrieb:

    Die Helligkeit der Farbe ergibt sich nicht aus dem Mittelwert der Farbwerte.

    VB.NET-Quellcode

    1. Dim col As Color = EINE_FARBE
    2. Dim b As Integer = (col.R + col.G + col.B) \ 3 ' + 1
    3. Dim bw As Color = Color.FromArgb(255, b, b, b)
    wird überall so gemacht, bei mir auch.
    Hier ist keine Konvertierung in Byte erforderlich.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Lightsource schrieb:

    Ich bin dabei, ein Bild erst in Schwarz/Weiß zu wandeln, und dann für einen Etikettendrucker aufzubereiten.

    Also wenn du mehrere Filter hinternander ausführen musst - guggemol Convolution-Filter

    achguck: in dem PixelHelper ist sogar gleich eine GrauSkala-Konvertierung eingebaut
    - ColorMatrix ist dein Froind.

    Ob Integer oder Double ist übrigens nicht so gravierend - jdfs. findich das Convolution-Filter-Dings hinreichend Flott, obwohls an einer Stelle mit Doubles arbeitet.

    RodFromGermany schrieb:

    VB.NET-Quellcode

    1. Dim col As Color = EINE_FARBE
    2. Dim b As Integer = (col.R + col.G + col.B) \ 3 ' + 1
    3. Dim bw As Color = Color.FromArgb(255, b, b, b)
    Korrektur:
    Es muss doch konvertiert werden, die Summe 3er Bytes bleibt Byte. Erst die "\"-Division konvertiert zu Integer:

    VB.NET-Quellcode

    1. Dim b As Integer = (CInt(col.R) + CInt(col.G) + CInt(col.B)) \ 3 ' + 1
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Wenn zwei Farbkanäle 1 sind und einer 0, kommt 0,5 raus, wenn 1 Kanal 1 ist und beide anderen 0 kommt 0,5 raus.

    @ErfinderDesRades: Doubles brauchen sehr viel Rechenzeit, kannst du ja mal mit einer StopWatch nachverfolgen. "Hinreichend flott mit Doubles" heißt meistens "noch viel schneller bei Integern". Manchmal lassen sich Singles/Doubles nicht vermeiden, aber schneller sind definitiv die Integer-Rechnungen. Das gilt allerdings nur für die meisten CPUs. Farbmatrizen sind in diesem Fall eventuell ein Overkill, da, wenn man die Farbe als 4-er Vektor ansieht mindestens 28 Operationen pro Pixel ausgeführt werden müssen (wenn es sich um eine 4x4-Matrix handelt, ist es ein Vierervektor, 5x5-Matrizen werden dazu verwendet, um die Werte aus der 5. Komponente noch auf zu addieren). Da es sich aber um RGB-Werte handelt, können es auch nur 15 Operationen pro Pixel sein (3er Farbvektor, 3x3 Matrix).

    Gruß
    ~blaze~
    Aber dafür läuft mein Beispiel bereits, und ist recht gut strukturiert.
    Und - wie gesagt - ordentlich flott.
    Jederzeit kann man noch Optimierungen anbringen, wenns einem noch zu lahm ist.

    Aber ich denke, für einen Etikettendrucker wirds auch so langen - reichlich.

    Der TE wird eher vor der Herausforderung stehen, eine Rasterung zu implementieren, dassis nämlich nochmal ein annerer Filter. Und dafür ist Pixelhelper vlt. wie geschaffen, indem es die BildDaten als 2-dim-byte-Array verfügbar macht - zumal der Grau-Filter schon drinne ist.
    Als ich mit der Programmierung von diesem Projekt anfing, hatte ich noch nicht
    entdeckt, dass ich eventuell mit mehreren Farbtiefen rechnen muss.
    Das kommt dann also noch dazu. Bis jetzt funktioniert es mit ARGB von
    PNG und BMP. Alleine das blöde Alpha musste ich irgendwie noch mit
    einbeziehen. Da ich mit LockBits arbeite habe ich also ein Array von
    zur Zeit 4 Byte. Diese liegen damit ja auch tatsächlich als einzelne Byte
    vor. Müsste ich nicht durch 3 sondern durch 2 dividieren, wäre es ja viel
    einfacher.
    Das mit der Color Matrix hatte ich mir auch schon überlegt, aber wenn ihr
    meint, dass das noch langsamer ist, lasse ich es natürlich.
    Wenn es allerdings geeigneter wäre, um auch verschiedene Farbtiefen
    zu verarbeiten, dann wäre es natürlich schon sinnvoller.
    mit verschiedenen FarbTiefen macht Pixelhelper kurzen Prozess: Umkopieren nach 24bbRGB.

    das ist alles schnurz, von wegen Geschwindigkeit. erstmal was strukturiertes lauffähig machen, und gucken, ob ühaupt Optimierungsbedarf besteht.
    Und wenn du einen richtigen Filter-Algo einbauen mußt, dann wird jeder Farbwert jedes Pixels mindestens 9 mal angeguckt - wen interessiert da noch ein Kopiervorgang mit oder ohne Colormatrix?

    Und wenns wirklich so ist, dass die colormatix dich ausbremst, dann kann man die immer noch durch einen schnelleren Algo austauschen.

    Saubere Strukturierung ist halt die Vorraussetzung für Optimierung.