Deband Filter Algorithmus
-
Das ist ein interessantes Thema. Sehr viele (denke sogar der Grossteil) von selbst AAA-Schmieden verzichtet aus irgendeinem Grund auf derlei Sachen. Dabei würde es die Bildqualität enorm erhöhen.
Das Problem ist, dass die paar bit die man üblicherweise für RGB benutzt für dunkle und helle Farben gleichverteilt sind, obwohl das menschliche Auge viel mehr Details in dunklen Farben erkennen kann. Deshalb fällt einem dieses Banding besonders stark bei dunklen Farbtönen auf.
Ich habe vor kurzem dazu eine interessante Präsentation von einem Naughty Dog Engineprogrammierer im Bereich Grafik gesehen, wo er auf derartiges Zeug eingangen ist und erklärt hat, wie ihnen das bei Uncharted 3 geholfen hat.
Mal schauen ob ich die wieder irgendwo finden kann.
-
Hmja, sehr cool.
Danke herzlichst!Mal sehen ob ich mich aufraffen kann das auch wirklich einzubauen
Achja: Dithering fehlt natürlich noch bei deinem Beispiel, aber das bekomm ich dann schon hin, das ist ja einigermassen trivial. Ich denke da lässt sich auch die Rauschetextur wiederverwenden, bzw. man könnte natürlich auch ne extra Dither-Textur machen (wenn man geordnet dithern will).
-
Warum baut man in Videos den eigendlich Dithering ein?
Ich kenne das eigentlich nur aus Zeiten wo man mit 16 oder 256 Farben gearbeitet hat und nur so eine "größere Farbpalette" zur Verfügung stand.Ist aber recht einfach zu realisieren:
uniform sampler2D texture0; float rand(vec2 co){ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); } void main(void) { float mdRGB = 0.02; vec4 maxDifference = vec4(mdRGB, mdRGB, mdRGB, 1.0); float stepMin = 5.0; float stepMax = 20.0; //I cut the image size to 1024x1024 float pixelStepX = 1.0 / 1024.0; float pixelStepY = 1.0 / 1024.0; vec2 tcord = gl_TexCoord[0].st; vec4 cbase = texture2D(texture0, tcord); float rndX = pixelStepX*(stepMin + (rand(tcord) * (stepMax-stepMin))); float rndY = pixelStepY*(stepMin + (rand(tcord) * (stepMax-stepMin))); vec4 c1 = texture2D(texture0, tcord + vec2(rndX, 0)); vec4 c2 = texture2D(texture0, tcord + vec2(-rndX, 0)); vec4 c3 = texture2D(texture0, tcord + vec2(0, rndY)); vec4 c4 = texture2D(texture0, tcord + vec2(0, -rndY)); //Selective anti aliasing c1 = mix(cbase, c1, vec4(all(lessThan(abs(vec4(cbase - c1)), maxDifference)))); c2 = mix(cbase, c2, vec4(all(lessThan(abs(vec4(cbase - c2)), maxDifference)))); c3 = mix(cbase, c3, vec4(all(lessThan(abs(vec4(cbase - c3)), maxDifference)))); c4 = mix(cbase, c4, vec4(all(lessThan(abs(vec4(cbase - c4)), maxDifference)))); vec4 minColor = min(cbase, min(c1, min(c2, min(c3, c4)))); vec4 maxColor = max(cbase, max(c1, max(c2, max(c3, c4)))); float ditherRnd = rand(tcord + vec2(0.33)); gl_FragColor = (minColor*ditherRnd) + (maxColor*(1-ditherRnd)); }
-
Naja... mit dem "deband" Filter entfernt man erstmal schön die Bänder, und durch die folgende Quantisierung auf 8 Bit pro Kanal holt man sie sich wieder zurück
=> also dithern.Speziell bei manchen Zeichentrick-Serien ist ohne Dithering nämlich das Banding in bestimmten Szenen deutlich sichtbar (meistens dunkle Szenen mit "langsamen" Farbübergängen). Und das auch ohne Sprünge > 1 im YUV Raum.
Daher wurden auch Videostandards wie H.264 auf 9 bzw. 10 Bit pro Farbkanal erweitert. (Das ist ausnahmsweise mal eine Erweiterung die wirklich Sinn macht, nicht so wie 192/24 bei Audio-gedöns, wo kein Mensch den Unterschied zu 96/24 hören kann - und vermutlich nichtmal zu 48/24).
-
TravisG schrieb:
Das ist ein interessantes Thema. Sehr viele (denke sogar der Grossteil) von selbst AAA-Schmieden verzichtet aus irgendeinem Grund auf derlei Sachen. Dabei würde es die Bildqualität enorm erhöhen.
was meinst du mit 'derlei sachen'?
Das Problem ist, dass die paar bit die man üblicherweise für RGB benutzt für dunkle und helle Farben gleichverteilt sind, obwohl das menschliche Auge viel mehr Details in dunklen Farben erkennen kann. Deshalb fällt einem dieses Banding besonders stark bei dunklen Farbtönen auf.
normalerweise benutzt man heutzutage ein HDR format zum rendern, das ist weit mehr als dein auge wahrnehmen koennte, am ende muss man natuerlich wieder auf 8bit tonemappen in den meisten faellen (auf manchen grakas kann man 10bit ausgeben, z.b. matrox).
Ich habe vor kurzem dazu eine interessante Präsentation von einem Naughty Dog Engineprogrammierer im Bereich Grafik gesehen, wo er auf derartiges Zeug eingangen ist und erklärt hat, wie ihnen das bei Uncharted 3 geholfen hat.
Mal schauen ob ich die wieder irgendwo finden kann.
waere nett, bin immer noch gespannt was du mit 'derartiges' meinst
-
TravisG schrieb:
Das Problem ist, dass die paar bit die man üblicherweise für RGB benutzt für dunkle und helle Farben gleichverteilt sind, obwohl das menschliche Auge viel mehr Details in dunklen Farben erkennen kann. Deshalb fällt einem dieses Banding besonders stark bei dunklen Farbtönen auf.
Da ist nix gleichverteilt, man verwendet üblicherweise nen Gamma von 2.2.
D.h. du hast bei dunklen Farben deutlich mehr Auflösung als bei hellen. Anders gesagt: der Helligkeitssprung (Energie/Fläche) von z.B. 11,11,11 auf 12,12,12 ist VIEL kleiner als der Sprung von 250,250,250 auf 251,251,251.
Blöderweise ist das menschliche Auge um so viel empfindlicher bei dunklen Farben, dass im Bereich von ca. 0-10 IRE (0 bis 10% auf der Gamma 2.2 Skala) die Auflösung trotz Gamma 2.2 noch "zu gering" ist.
Verschärft wird das ganze noch dadurch, dass viele nicht (gut) kalibrierte LCDs gerade bei dunklen Farben sehr ungenau sind, und dort einen "steileren" Anstieg haben als sie haben sollten. Wenn das LCD ein MVA/PVA ist, und man dann noch leicht schräg draufguckt (5-10° reichen schon), wird dieser Effekt nochmal ordentlich verstärkt.
Langer Rede kurzer (Un)sinn: wenn man ne dunkle Stelle in einem Film auf einem heute üblichen Fernseher guckt (=grösstenteils LCDs mit MVA oder PVA Panel), dann springt einem das Banding nur so ins Gesicht.
Und noch schnell dazu...
Das ist ein interessantes Thema. Sehr viele (denke sogar der Grossteil) von selbst AAA-Schmieden verzichtet aus irgendeinem Grund auf derlei Sachen. Dabei würde es die Bildqualität enorm erhöhen.
Weiss nicht ob das bei Spielen SO wichtig wäre. Bei manchen Spielen würde Dithering sicher nen sichtbaren Unterschied in manchen Szenen machen. "Bildqualität enorm erhöhen" halte ich im Allgemeinen aber für leicht übertrieben
-
hustbaer schrieb:
TravisG schrieb:
Das Problem ist, dass die paar bit die man üblicherweise für RGB benutzt für dunkle und helle Farben gleichverteilt sind, obwohl das menschliche Auge viel mehr Details in dunklen Farben erkennen kann. Deshalb fällt einem dieses Banding besonders stark bei dunklen Farbtönen auf.
Da ist nix gleichverteilt, man verwendet üblicherweise nen Gamma von 2.2.
...
Blöderweise ist das menschliche Auge um so viel empfindlicher bei dunklen Farben, dass im Bereich von ca. 0-10 IRE (0 bis 10% auf der Gamma 2.2 Skala) die Auflösung trotz Gamma 2.2 noch "zu gering" ist.das gamma kommt durch die crt monitore (und das lcds das wegen der kompatibilitaet emulieren). das hat nicht wirklich was mit dem auge zu tun, wenn du linear die analoge signalstaerke bei input eines alten crt steigern wuerdest, haettest du die 2.2 gamma curve.
[edit]hmm, wikipedia behauptet es liegt am auge, aber viele paper die ich las behaupten es liegt am phosphor von monitoren?
zudem behauptet wikipedia "Gamma encoding of floating point images is not required (and may be counterproductive) because the floating point format already provides a pseudo-logarithmic encoding." was ein wenig strange is, zwar ist float von der genaugikeit her logarithmic, aber das hat nichts mit der ausgabe zum monitor zu tun.[/edit]
-
@rapso
Ich glaube dass die alten CRT-Schirme der Grund sind warum von Anfang an nicht linear aufgezeichnet wurde. Und der Umstand dass Gamma 2.2 sich zumindest besser als lineare Kodierung mit dem deckt, was das menschliche Auge macht, wird vermutlich der Grund sein, warum auch heute noch fast überall Gamma 2.2 verwendet wird. (Bzw. der Grund für den genauen Wert, also 2.2 und nicht 1.8 oder 2.0 oder sonstwas, ist vermutlich, dass es Windows-Standard war, und es als sRGB standardisiert wurde einfach viel mehr Windows-Monitore gab als Mac-Monitore *g*. Vom technischen Standpuntk aus betrachtet hätte vermutlich Gamma 2.0 mehr Sinn gemacht, weil viel viel einfacher umzurechnen.)Und mit der Floating-Point Geschichte ist vermutlich gemeint: wenn man Floats statt Integer verwendet, dann besteht keine Notwendigkeit mehr das Bild mit Gamma 2.2 im Speicher zu halten, als Datei zu speichern bzw. zu bearbeiten.
Gamma 2.2 hat ja auch einige Nachteile. z.B. dass man das Bild dann für fast jede Operation erstmal linearisieren, bearbeiten und dann wieder zurückwandeln müsste. Darauf wird leider all zu oft verzichtet, siehe z.B.:
http://www.4p8.com/eric.brasseur/gamma.htmlDass man es dann zur Ausgabe wieder in das Format bringen muss, das das Display-Device erwartet (also fast meistens Gamma 2.2), ist natürlich klar.
----
Was mich immer wieder wundert, ist dass die Gamma-Geschichte so viele Leute nicht wissen/kennen/verstehen. Klar, ein Maurer muss das nicht wissen, aber von Grafikern hätte ich es mir erwartet. Trotzdem wissen es viele nicht
-
Soooooo...
Ich hab' mal mit dem XBMC Jungs Kontakt aufgenommen. Die wären soweit auch interessiert.
Als nächstes hab' ich einen Test mit MediaPlayer Classic gemacht - der kann ja beliebige Shader im Renderer laufen lassen (so lange diese keine zusätzlichen Texturen als Input brauchen).
Dummerweise hat sich dabei gezeigt, dass die Performance enorm einbricht, wenn man mit zufälligen Offsets aus der Textur liest. Ein Problem das ich irgendwie fast erwartet habe - hab' mir nur gedacht "mach dir keinen Kopf bevor du nicht weisst dass es wirklich zu langsam ist". Naja, jetzt weiss ich es
Bei 5-10 Pixel Radius geht alles noch halbwegs, darüber wird es dann wirklich langsam. Mit meiner Grafikkarte (G210) degradiert das Video zur Diashow.
Zugegeben, ne G210 ist nicht die flotteste, aber viele HTPCs verwenden ION Boards, und es wäre natürlich sehr wünschenswert wenn der Spass auch mit ION/ION2 funktionieren würde.Ich wäre also über weitere Vorschläge dankbar, wie man sowas GPU schonend umsetzen kann.
-
Hmm... hast du es jetzt im media player classic noch mit der "GLSL-Zufallsfunktion" getestet? Weil du sagst, dass du keine extra Texturen mitgeben kannst, und meines Verständnisses nach somit keine Rauschtextur möglich ist.
Weil die Zufallsfunktion auch nicht ganz ohne Performance Einbußen sein wird.Und wenn es von der Performance her nur an dem zufälligem Lesezugriff gehen sollte, würde ich vorschlagen dass du mal meinen ersten Shader mit den 8 Prüfpunkten ausprobierst.
Die Dithering-Erzeugung kann man dort auch noch einbauen. Der benötigte Zufall würde dann ja nicht mehr die Lesezugriffe beeinflussen.
-
Ja, ich hab' mit dem frac(sin())-Zufall getestet. Der bleibt sich ja aber immer gleich, d.h. wenn ich mit Radius=3 akzeptable Geschwindigkeit hab und mit Radius=50 Diashow, dann liegts mal nicht an der Zufalls-Funktion.
Und die erste Variante... naja. Klar wird die schneller laufen. Bloss die macht keine schönen Bilder
Wobei ich deinen Shader auch leicht modifiziert hatte, und zwar was die Koordinaten angeht. Hab aber im Moment grad schlecht Zeit, ich melde mich wenn ich mehr weiss
-
Dann wird es wie du sagtest der zufällige Zugriff sein.
Was heißt hier mein erster Versuch macht keine schönen Bilder?
Aus deinem Referenzbild hat mir der erste Shader schon akzeptable Ergebnisse geliefert und wenn man dort noch Dithering einbaut sollte es noch besser ausschauen.
Oder hast du diesen schon selber ausprobiert und bei anderen Bildern deutlich schlechtere Ergebnisse erhalten?Ich habe jetzt leider nur die eine Grafikkarte hier zum Testen. Denn ich hätte noch eine Idee wie man den Shader umbauen könnte um die Performance zu retten.
Dazu würde ich die 4 Linienbereich ganz auslesen welche als Prüfpunkte in frage kommen.Das währen
(Byte pro Pixel)(Länge einer Linie)(Anzahl Linien)
4 * (20-5) * 4 = 240 ByteIch weiß nicht wie viel Cache man pro GPU Kern bei dem ION erwarten darf.
Zu meiner Radeon 5770 habe ich z.B. 8 KiB Cache pro SIMD + 16 KiB Shared pro Block gefunden. Und die ist schon gehobene Mittelklasse.Wenn das aber alles in den Cache eines GPU Kernes passen sollte, anschließend einfach aus dieser Shadervariable die Werte zufällig herauspicken.
Übrigens, das ist alles reine Theorie!
-
Hmmmmm...
Ich weiss auch nicht wie das mit ION/ION2 aussieht. Ich glaube nur zu wissen dass meine G210 eng verwandt mit nem ION2 ist. Also wenns auf der nicht gut läuft, dann stehen die Chancen mit dem ION2 vermutlich auch nicht gut.
Und Performance-Testen mit Media-Player Classic ist auch nicht das Wahre, ich fürchte da muss wohl ein kleines Testprogramm her.
Was den Cache angeht: da müsste man wohl genau wissen wie Grafikkarten so rendern tun, und wie das mit den Texture-Fetches läuft.
Ich kann da nur Vermutungen anstellen.z.B. vermute ich dass die Grafikkarte immer kleine Quadrate aus der Textur fetchen tut, vielleicht 4x4 oder 8x8 Texel. Möglicherweise tut die Texturing-Unit dann auch prefetchen. Aber alles nur geraten.
Fakt ist: ich kenn' mich mit Shader-Optimieren so-gut-wie gar nicht aus
Was mich wieder zum Testprogramm bringt: wenn ich da schnell & einfach rumprobieren kann, an ein paar Werten schrauben etc., und schön ablesbare Zahlen als Ergebnis bekomme kann das vielleicht was werden. So, einfach ins Blaue geraten vermutlich weniger