- Unterschied zwischen der standardmäßigen Methode mit Division durch 255 und der alternativen Methode mit 0,5-Bias und Division durch 256, wenn 8-Bit-Ganzzahlfarben in Fließkommazahlen umgewandelt werden
- Die 255-Methode bildet Ganzzahl 0 auf 0.0 und 255 auf 1.0 ab, sodass sich Schwarz und Weiß direkt behandeln lassen, und sie entspricht auch der UNORM-zu-Float-Konvertierung der GPU
- Die 256-Methode platziert mit
(img + 0.5) / 256.0jeden Wert in der Mitte seines Intervalls, was bei Aufgaben wie Dithering die Behandlung von Randfällen vereinfachen kann, aber 0 nicht auf 0.0 abbildet und die Verarbeitungslogik damit an 8-Bit-Eingaben bindet - Bei der 255-Methode sind die Intervalle an beiden Enden nur halb so breit; rundet man gleichverteilte Zufallswerte aus
[0, 1]zurück auf 8 Bit, treten 0 und 255 deshalb nur halb so häufig auf wie andere Werte, doch echte Bild-Roundtrips funktionieren trotzdem verlustfrei - Wenn man Bilder anderer verarbeitet, ist Normalisierung durch 255 die richtige Wahl; die 256-Methode ist nur dann erwägenswert, wenn man Speichern und Laden vollständig kontrolliert
Problemstellung
- In einem Programm, das ein Bild einliest, in Fließkommazahlen umwandelt, verarbeitet und anschließend wieder als 8-Bit-Farben speichert, ist die Methode zur Integer-Float-Konvertierung der Streitpunkt
- Es gibt zwei Ansätze
- Standardmethode (durch 255 teilen):
pixels = img / 255.0→ verarbeiten →output = np.trunc(result * 255 + 0.5) - Alternative Methode (durch 256 teilen):
pixels = (img + 0.5) / 256.0→ verarbeiten →output = np.trunc(result * 256) - In beiden Fällen wird der Wert vor der finalen Typumwandlung auf 0 bis 255 begrenzt:
output.clip(0, 255).astype(np.uint8)
- Standardmethode (durch 255 teilen):
- Die Standardmethode bildet Ganzzahl 0 auf 0.0 und 255 auf 1.0 ab und entspricht der UNORM-zu-Float-Konvertierung der GPU
- Die alternative Methode fügt einen 0,5-Bias hinzu, sodass Ganzzahl 0 auf
0.5/256 = 0.001953125abgebildet wird- Dadurch lassen sich schwarze Pixel nicht erkennen, wenn man diese Konstante nicht kennt
- Selbst bei Fließkommaberechnungen bleibt die Logik damit an 8-Bit-Eingaben gekoppelt
- Bei der Standardmethode kann man Schwarz immer als 0.0 annehmen
Einwände gegen 255.0
- Zeichnet man die Standardmethode auf der Zahlengeraden ein, wirkt sie etwas seltsam
-
Kleinere Bins an beiden Enden
- Die End-Bins der Standardformel ragen über den Bereich [0,1] hinaus; der Bereich ist also „gestreckt“
- Beim Zurückwandeln von Fließkomma in Integer sind die End-Bins nur halb so breit wie die anderen
- Für einen Algorithmus wird es dadurch „schwieriger“, Extremwerte auszugeben
- Erzeugt man gleichverteiltes Rauschen in [0,1] und rundet es mit der Standardformel, treten 0 und 255 nur halb so häufig auf wie andere Ganzzahlen
- Ein Histogramm von einer Million gleichverteilten Zufallszahlen zeigt, dass die Bins für 0 und 255 nur halb so hoch sind wie die übrigen
- Allerdings ist schwer vorstellbar, wann dieser Bias zur Vermeidung von Extremwerten in der Praxis wirklich problematisch ist
- Das Originalbild kann weiterhin verlustfrei hin- und zurückgewandelt werden (
uint8 → float → uint8) - Ergebnisse, die leicht unter 0.0 oder über 1.0 liegen, werden dennoch korrekt in den richtigen Bin gerundet, wodurch die Ausgabeverteilung wieder gleichmäßiger wird
- Beispiel: Wenn im Verarbeitungsschritt 0.005 vom Farbwert abgezogen wird, fällt Schwarz bei der Standardmethode unter 0, bei der alternativen Methode bleibt es positiv, aber beide Methoden liefern am Ende Integer 0
- Das Originalbild kann weiterhin verlustfrei hin- und zurückgewandelt werden (
-
Ungenauigkeit
- Die Fließkommawerte der Standardmethode sind nicht exakt, z. B. ist
128/255.0 ≈ 0.501961, während128/256.0 = 0.5 - Durch Rundungsfehler variiert der Abstand zwischen Fließkommawerten minimal, aber der Fehler ist so klein, dass er praktisch keine Rolle spielt
- 32-Bit-Fließkommazahlen haben eine 23-Bit-Mantisse, und der Fehler liegt auf dem Niveau des niederwertigsten Bits, also unter
2⁻²³ - Ein relativer Fehler von 0.00001 % ist selbst für anspruchsvolle Bildverarbeitung bedeutungslos; die Ungenauigkeit ist eher ein ästhetisches als ein technisches Problem
- 32-Bit-Fließkommazahlen haben eine 23-Bit-Mantisse, und der Fehler liegt auf dem Niveau des niederwertigsten Bits, also unter
- Die Fließkommawerte der Standardmethode sind nicht exakt, z. B. ist
-
Werte, die auf keiner Ganzzahl liegen
- Die alternative Methode platziert jeden Fließkommawert genau zwischen zwei Ganzzahlen
- Da der ursprüngliche quantisierte Wert unbekannt ist, ist der Mittelpunkt zweier benachbarter Ganzzahlen ein sinnvoller Kompromiss als Schätzwert
- Es gibt die Behauptung, dass Dithering dadurch einfacher wird (Andrew Keslers Blogbeitrag von 2015, "Converting Color Depth")
- Man kann Rauschen hinzufügen, ohne sich um Sonderfälle zu kümmern
- Umgekehrt erfordern die unhandlichen Extremwerte der Standardformel eine sorgfältigere Behandlung, wenn die Rauschverteilung konsistent bleiben soll
- Die alternative Methode platziert jeden Fließkommawert genau zwischen zwei Ganzzahlen
Zwei Arten von Quantisierern
- Die beiden Ansätze lassen sich als zwei Arten von uniformen skalaren Quantisierern auffassen
- Laut dem Wikipedia-Artikel zur Quantisierung werden uniforme Quantisierer für vorzeichenbehaftete Eingangsdaten in zwei Typen eingeteilt
- mid-tread: bildet 0 auf die Rekonstruktionsstufe 0 ab (die waagerechte Stufe)
- mid-riser: bildet 0 auf die Klassifikationsschwelle 0 ab (die senkrechte Stufenkante)
- Wikipedia verweist als Quelle auf eine Arbeit von 1977 (Allen Gresho, "Quantization")
- Quantisiererformeln (L ist die Anzahl der Ausgabestufen, z. B. 256)
- mid-tread-Treppenquantisierer: Kodierung
k = trunc(xL + 0.5), Dekodierungyₖ = k/L - mid-riser-Treppenquantisierer: Kodierung
k = trunc(xL), Dekodierungyₖ = (k+0.5)/L
- mid-tread-Treppenquantisierer: Kodierung
- Auf die beiden Methoden angewandt
- Standardformel = mid-tread (L=255)
- Alternative Formel = mid-riser (L=256)
- Die Standardmethode ist eine Kombination aus mid-tread für vorzeichenlose Eingaben mit dem Code
L=255und damit nicht optimal für 8-Bit-Eingaben- Diese Wahl dient der praktischen Bequemlichkeit, die Endpunkte auf 0.0 und 1.0 abzubilden
-
Höherer Quantisierungsfehler, aber praktisch nicht relevant
- Bei einem System, das gleichverteilte reelle Werte x∈[0,1] in 8-Bit-Integer kodiert und anschließend wieder als reelle Werte rekonstruiert, verschwendet die Standardformel Bandbreite
- Der darstellbare Bereich der Standardmethode ist
[-0.5/255, 255.5/255]und damit weiter als für Eingaben in [0,1] nötig, was den Rekonstruktionsfehler erhöht - Laut einer Berechnung des StackOverflow-Nutzers Peter Mudrievskij beträgt der mittlere absolute Fehler bei Division durch 255
1/1020, bei Division durch 2561/1024; daher ist die Division durch 256 theoretisch etwas präziser
- Der darstellbare Bereich der Standardmethode ist
- In der Praxis rekonstruiert man aber nicht auf diese Weise
- Voraussetzung ist ein 8-Bit-RGB-Bild, das geladen, verarbeitet und wieder gespeichert wird; beim Speichern hat man die Quantisierungsmethode oft nicht unter Kontrolle, und verlorene Information bleibt dauerhaft verloren
- Wenn das Bild mit der Standardformel skaliert und gerundet gespeichert wurde, lässt sich durch Division durch 256 beim Laden keine Präzision zurückholen
- Der geringere Rekonstruktionsfehler ist nur relevant, wenn man sowohl Speichern als auch Laden kontrolliert
- Lädt man Bilder anderer mit der alternativen Formel, erzeugt man sogar mehr Fehler
- Diese Bilder wurden höchstwahrscheinlich mit der Standardformel quantisiert; eine Dekodierung mit der falschen Skalierung ist theoretisch ungenauer
- Praktisch sind Farben allerdings keine absoluten Messwerte, sodass man nur in einem etwas kleineren Bereich mit einem kleinen Offset arbeitet
- Man darf die Kodierungs- und Dekodierungsschritte der beiden Quantisierer nicht mischen; genau das führt oft zu kaputtem Code
- Bei einem System, das gleichverteilte reelle Werte x∈[0,1] in 8-Bit-Integer kodiert und anschließend wieder als reelle Werte rekonstruiert, verschwendet die Standardformel Bandbreite
Fazit
- Wenn man ein Bild verarbeitet, das von jemand anderem stammt, sollte man RGB-Werte durch 255 normalisieren
- Sorgen über ungenaue Fließkommawerte oder abstrakte Rekonstruktionsfehler sind kein guter Grund für die Alternative
- Wenn man das Speichern und Laden vollständig kontrolliert, 0 nicht auf 0 abbilden muss und damit leben kann, den Verarbeitungscode an den 8-Bit-Dynamikbereich zu binden, kann man durch Division durch 256 etwas mehr Präzision erreichen
- Man sollte aber bedenken, dass ein Kollege das Bild mit der Standardformel laden und den Plan damit zunichtemachen könnte
Andere Sichtweisen
- Jonathan Blows Text von 2002 behandelt mid-riser- und mid-tread-Quantisierer ohne diese Namen zu verwenden; von dort stammt die Idee für die Diagramme
- Andrew Keslers Blogbeitrag von 2015 verteidigt die alternative Formel
- Allerdings wird dort mit einer Standardformel ohne Rundung verglichen, wodurch ein Großteil der Analyse hinfällig wird
2 Kommentare
Hacker-News-Kommentare
Was ein Farbwert genau bedeutet, ist bei 8 Bit pro Komponente meist kein großes Thema. Der Fehler durch den Unterschied zwischen einem Nenner von 255 oder 256 ist sehr klein, und um ihn zu sehen, müsste man ein gutes Farbempfinden haben und sehr nah an den Bildschirm herangehen; außerdem sind Monitor- oder Smartphone-Displays in der Regel nicht kalibriert.
Wenn man jedoch mit einem Mikrocontroller ein VGA-Signal erzeugt und nur 8 Pins für die Farbausgabe hat (3 Rot, 3 Grün, 2 Blau), wird es ziemlich knifflig. In diesem Fall sind die Farbwerte selbst die Spannungspegel von 0 V bis 0,7 V, die an den VGA-Monitor gesendet werden müssen.
Der Blaukanal wird auf 0→0 V, 1→0,23 V, 2→0,47 V, 3→0,7 V abgebildet, Rot/Grün dagegen auf 0→0 V, 1→0,1 V, …, 7→0,7 V. Lässt man die beiden Endpunkte außen vor, passt keine einzige Blau-Spannung zu den Rot-/Grün-Spannungen, sodass man kein reines Grau sehen kann; selbst die nächstliegenden Farben haben je nach Richtung einen leichten Blau- oder Gelbstich.
Außerdem wirken fast alle Verläufe, in denen Blau mit anderen Kanälen gemischt wird, verschoben. Zum Beispiel sehen die nächstliegenden Farben auf der Linie von reinem Rot zu reinem Weiß leicht orange oder violett aus.
Hier ist Code für 8-Bit-Farb-VGA-Ausgabe mit einem doppelt gepufferten 320x240-Framebuffer auf dem Raspberry Pi Pico 2: https://github.com/moefh/pico-vga-8bit-demo
Dadurch treten Unterschiede bei kleinen und großen Werten viel deutlicher hervor: 2^2.2 = 4.595, 255^2.2 = 196,964.699
Wenn es mit 30 Hz wechselt, dürfte es für Menschen schwer sein, den Unterschied zwischen leicht bläulich und leicht gelblich zu erkennen.
Ein Argument für 255 ist der Extremfall eines Schwarzweißbilds. Bei einem einzelnen Bit ist 0 Schwarz und 1 Weiß.
Dass 0 auf 0.0 und 1 auf 1.0 abgebildet werden sollte, ist ziemlich klar. Es ist schließlich Schwarzweiß und nicht Hellgrau (0.25) und Dunkelgrau (0.75). Ein Schwarzweißbild wird also nicht mit 2, sondern mit 1 normalisiert.
Bei 2 Bit hat man normalerweise 0=Schwarz, 1=Hellgrau, 2=Dunkelgrau, 3=Weiß, daher ist eine Abbildung auf 0.0, 0.33, 0.66, 1.0 naheliegend. Schwarz soll Schwarz und Weiß soll Weiß sein, und die Abstände sollen gleich sein, also normalisiert man mit 3.
Führt man diese Logik bis zu 8 Bit fort, landet man bei einer Normalisierung mit 255. Denn auch wenn der Unterschied bei 8 Bit sehr klein wird, sollten Schwarz 0.0 und Weiß 1.0 sein.
Die andere Methode, bei 8 Bit mit 256 zu normalisieren, führt dazu, dass sich der Ausgabebereich je nach Bitzahl verändert. Bei 1 Bit wäre es [0.25, 0.75], bei 2 Bit [0.125, 0.875]. Gewünscht ist normalerweise, dass mit steigender Bitzahl mehr Nuancen hinzukommen, nicht dass sich der Kontrast ändert.
Das war wirklich ein Text, der zum Nachdenken anregt, und er hat mich dazu gebracht, einige meiner eigenen Annahmen noch einmal zu prüfen.
Aus Sicht der Elektrotechnik fällt es mir schwer, der Darstellung von „zwei Arten von Quantisierern“ im Text zuzustimmen. Mathematisch ist sie sauber, aber sie beschreibt keine realen Systeme.
ADCs haben immer eine inhärente Quantisierungsunsicherheit von ±1/2 LSB. Die Übertragungskennlinie ist immer eine Mid-Tread-Abtastung, jedenfalls habe ich noch nie ein Gegenbeispiel gesehen. Das gilt sowohl für bipolare als auch für unipolare ADCs.
Der kleinste Code entspricht der negativen Referenzspannung und der größte Code der positiven Referenzspannung. Ein Diagramm der Übertragungskennlinie zeigt, dass das oberste und unterste Intervall, wie im Text dargestellt, effektiv eine Breite von 1/2 LSB haben.
In unipolaren Systemen kann man Mittelspannungen nicht exakt darstellen; anders gesagt tritt wieder das Grau-Problem auf. In bipolaren Systemen ist 0 V der Wert N/2 einer Mid-Tread-Kennlinie, aber das bedeutet nicht, dass es „256 Intervalle“ gibt.
Deshalb würde ich weiter
(VREF+ - VREF-) * k / (2^N - 1)verwenden. Ich stimme also der Normalisierung mit 255 zu. Letztlich ist das derselbe Fencepost-Fehler: Es gibt N Werte, aber N-1 Intervalle. Wenn es weniger Intervalle als Werte gibt, muss ein Intervall auf zwei Werte verteilt werden, und deshalb entstehen an den Endpunkten 1/2-LSB-Intervalle.Der Übergang von 126 auf 127 erfolgt 1.5 LSB unterhalb der positiven Vollaussteuerung. Ein Unterschied von 1 LSB bedeutet 1/128=0.00781 V und nicht 2/255=0.00784 V.
Aber wenn in der Praxis Spannung und Unsicherheit wichtig sind, ist dieser Unterschied meist ohnehin bedeutungslos. Die Referenzspannung hat einen Bias und es gibt Linearitätsfehler. 1 LSB entspricht weder exakt 1/128 noch exakt 2/255, und man braucht Parameter zur Kalibrierung.
Das ähnelt in wissenschaftlichen Berechnungen dem Unterschied zwischen node-centered und cell-centered Samples in einer Dimension. Man muss entscheiden, ob ein Wert in der Mitte eines Intervalls liegt (oder im Zentrum eines Dreiecks/Tetraeders) oder auf einer Intervallgrenze (oder an einem Eckpunkt eines Dreiecks/Tetraeders).
In wissenschaftlichen Berechnungen ergibt es keinen Sinn, mit der Datenverarbeitung zu beginnen, ohne zu wissen, wie die Werte interpretiert werden sollen. Auch bei der Audiosignalverarbeitung gilt: Wenn man nur einen Integer-Stream erhält, muss man wissen, welche Darstellungsabsicht hinter diesen Integern steckt, etwa ob es sich um mu-law-Codierung oder lineare Codierung handelt, bevor man Berechnungen am Ursprungssignal durchführen kann. Man erwartet, dass die an den Werten hängenden Metadaten diese Antwort liefern.
Bei 8-Bit-Pixelwerten treibt man jedoch orientierungslos dahin, wenn es keine brauchbaren Metadaten im Dateiformat gibt, die die Darstellungsabsicht übermitteln, und dann gibt es keine richtige Antwort. Wie der Autor sagt, kann man niemanden dafür kritisieren, die Variante zu wählen, die für den eigenen Zweck bessere Ergebnisse liefert; man kann aber darauf hinweisen, dass Bits ohne Kontext ihre Bedeutung verlieren.
Grob gesagt sieht es so aus: Die Digital Number DN=0 bleibt als Wert „NO_DATA“ reserviert, und wenn DN im Bereich [1; 1;215-1] liegt, dann ist der L2A-SR-Reflexionswert
L2A_SRi = (L2A_DNi + BOA_ADD_OFFSETi) / QUANTIFICATION_VALUE.https://sentiwiki.copernicus.eu/web/s2-products
Hier steckt der Fehler, anzunehmen, es gebe 256 Stufen von 0 bis 255. Tatsächlich gibt es 256 mit 8 Bit darstellbare Werte, und zwischen 0 (Schwarz) und 255 (reines Weiß) liegen 255 Intervalle.
Deshalb ist das Teilen durch 255 kein Problem. Natürlich ist 128 nicht exakt ein mittleres Grau, und quantisierte 8-Bit-Werte von 0–255 liegen fast immer nicht in einem linear wahrgenommenen Raum, sondern in sRGB.
Eine ähnliche Verwirrung entsteht in modernen APIs beim Umgang mit Abtastpositionen, weil Positionen als Koordinaten und nicht als Pixelzentren angegeben werden.
Algebraisch betrachtet ist die Antwort eindeutig: f(x) -> [0, 255].
Wenn nicht f(n * 0) == n * f(0) gilt, passieren seltsame Dinge. Wenn zum Beispiel f(x) -> [0, 255], dann ist f(0) + f(0) + f(0) = 0 + 0 + 0 = 0 = f(0).
Dagegen gilt bei f(x) -> [0.5/8, 7.5/8]: f(0) + f(0) + f(0) = 0.5/8 + 0.5/8 + 0.5/8 = 1.5/8 != f(0).
Wenn man Letzteres wählt, kann man nicht erwarten, dass Rechnungen auf der x-Seite und Rechnungen auf der f(x)-Seite zusammenpassen. Das heißt, die algebraische Entsprechung geht kaputt.
Ich würde die +0.5-Lösung unterstützen. Erstens gefallen mir die halb so großen Intervalle an den Rändern nicht, und zweitens sind 255-basierte Darstellungen normalerweise keine HDR-, sondern SDR-Bilder.
RGB-Werte stehen für Luminanz relativ zu einem Adaptionszustand, und die „0“ in einer Tagesszene ist nicht „Luminanz 0“. Sie ist nur ungefähr das 0,001-Fache des hellsten Punkts, und das sind immer noch Millionen von Photonen, also weit mehr als 0.
In gewisser Weise erlebt das Auge Kontrast auf einer gleitenden Skala, und im System gibt es kein absolutes 0. So verwendeten Rundfunksysteme historisch 16–235 als SDR-Luminanzbereich. Ich halte die Logik „es muss unbedingt eine 0 geben“ für verzerrend und denke, dass man in den meisten Fällen keine 0 braucht.
Außerdem setzen viele Workflows für Bildverarbeitung und Compositing, ob zu Recht oder nicht, voraus, dass 0 eben 0 bedeutet. Deshalb wird bei 8 Bit oft angenommen, dass 0u auf 0.0f und 255 auf 1.0f abgebildet wird. Wenn bei Masken oder Alpha der Wert 0 etwas größer als 0.0 wird, entstehen Artefakte, weil irgendwo Code mit einem harten Schwellenwert von 0.0 andere Operationen maskiert. Umgekehrt wird ein Objekt nach Premultiplikation minimal transparent, wenn 255 im Alpha-Kanal nicht mehr 1.0f ist.
Dasselbe kann bei +0.5 passieren, wenn in einer Maske 254 zu 1.0f wird.
Entscheidend ist nicht, ob man 0 Photonen darstellt, sondern ob man die in 1 Byte gespeicherte Information maximiert. Idealerweise sollte man den Bytewert 0 nicht seltener verwenden und auch keine Verzerrung hinzufügen, sodass Daten, die in den 0. Bucket gehört hätten, verschoben werden. Selbst in einem Farbraum von hell bis sehr hell sollte jedes Byte ein gleich großes Stück des Helligkeitsbereichs repräsentieren.
Wenn ein Lineal bis 12 Zoll geht, sollte man mit der Länge L normalisieren und nicht mit 13, der Anzahl der Punkte auf dem Lineal.
>> 8ist viel schneller.Angenehmer Artikel über ein Thema, über das ich lange nicht nachgedacht hatte. Er hat mich an Momente in der Spieleentwicklung erinnert, in denen die Spiellogik Gleitkomma-Arithmetik nutzte, Pixel Art aber auf ganzzahligen Koordinaten gezeichnet werden musste.
An einigen Stellen habe ich etwas Ähnliches wie +0.5 verwendet, damit es weniger seltsam aussah. Das galt besonders bei bewegter Kamera, und die Kamera selbst musste ebenfalls gerastert werden.
Der unten verlinkte Text von Jonathan Blow aus dem Jahr 2002 [1] war auch interessant. Die Visualisierung im ersten Artikel hilft sehr, wenn man tiefer einsteigen will.
[1] https://web.archive.org/web/20240706043551/https://number-no...
Lobste.rs-Meinungen
Falls es nicht intuitiv wirkt, hilft ein degenerierter 2-Bit-Fall. Wenn die einzigen möglichen ganzzahligen Werte 0, 1, 2 und 3 sind und man die Umwandlung von Integer zu Fließkomma vollständig durchrechnet, erhält man 0.0, 0.33..., 0.66..., 1.0, wenn man seltsames Verhalten vermeiden will, bei dem Schwarz/Weiß nicht Schwarz/Weiß ist oder die Abstände offensichtlich ungleichmäßig sind
Daher erfolgt die Rückumwandlung durch Multiplikation mit 3, nicht mit 4 (2^2)
Für die Rückumwandlung braucht man Quantisierung (Rundung), und genau dort wird die Symmetrie gebrochen
Wenn man einen gleichmäßigen reellen Gradienten im Bereich 0..=1 erzeugt und ihn auf 0, 1, 2, 3 quantisiert, sieht man, dass Multiplikation mit 3 kein gleichmäßiges Ergebnis liefert. Nach ×3 und
round()sind 1 und 2 überrepräsentiert; nach ×3 undflooroderceilwerden 0 oder 3 wie Sonderfälle an den Rand gefaltet, sodass der Gradient so wirkt, als nutze er nur 3 der 4 FarbenDie
/3- und×3-Logik sieht für exaktes Hin-und-zurück-Konvertieren von Zahlen in Ordnung aus, aber Zwischenwerte hängen stark von der Rundungswahl ab und werden wichtig, sobald man mit der Datenverarbeitung beginntGleichmäßige Integer-Anteile erhält man nur mit Multiplikation mit (4-ε) und anschließendem Abrunden, was äquivalent zu ×4,
floor()undclamp()ist. Es fühlt sich wie ein seltsamer Off-by-one- oder ε-Unterschied an, ist aber intuitiv die am besten aussehende LösungFür mich war die Antwort immer „natürlich“ [0.0..255.0], aber offenbar ist das nicht für alle selbstverständlich
Im Artikel wird gesagt, die „Extrem“-Intervalle hätten nur halb so viel Kapazität wie die anderen, aber auch dieses Framing halte ich für falsch
Wenn es keine Werte außerhalb von [0..1] gibt, ist das scheinbar schmalere Intervall nur ein Artefakt der Darstellung. Es wird nur schmaler gerendert, weil man die Buckets anhand des Wissens abgeschnitten hat, dass es keine Werte außerhalb des Bereichs gibt
Wenn es dagegen Werte außerhalb von [0..1] gibt, dann ist dieser Bereich unendlich. Der Artikel akzeptiert Letzteres, aber nicht Ersteres
Sobald man Ersteres akzeptiert, scheint das korrekte Verhalten klar zu sein, aber dass es überhaupt solche Artikel gibt, zeigt objektiv auch, dass das Problem nicht wirklich „klar“ ist :D
Wenn 0..<1 zu Integer 0 wird und 254>..255.0 zu Integer 255, dann wird 128 verschluckt. Vermutlich soll 127.5..128.5 zu 128 werden, aber wohin sollen dann diese Hälften gehen?
Wenn man alles ein wenig verschiebt, damit 128 passt, wird 0..0.99609375 auf Integer 0 gemappt
round()aufrufenDiese Methode fühlt sich für viele offenbar ziemlich natürlich an, und dürfte deshalb wegen ihrer Einfachheit zum Standard geworden sein
pngcrushkomprimiert. Oder meinst du, dass inhaltlich etwas mit dem Bild nicht stimmt?