8Bit RGB -> 12Bit RGB wandeln.

  • Servus Zusammen,


    ich bin gerade auf der Suche nach einer Methode 8 Bit RGB in 12 Bit RGB zu wandeln.
    Also gegeben ist jeder Kanal mit 8 Bit.


    Hintergrund:
    Für mein Matrixprojekt hatte ich eine Idee, für den ich eine solche Funktion benötige,
    genaueres gibt es erst mit der Veröffentlichung meines Projektes und das dauert noch =)


    Pesi, synvox und ich hatten ja schonmal in meinem Sammelbestellungsthread TLC5947 über das Konvertieren von RGB zu HSV und innerhalb der Farbräume von 8 zu 12 Bit.
    Hab das gerade nochmal alles durchgelesen und werde nicht richtig schlau daraus.


    Einfachste Methode wäre einfach die 8Bit * 16 zu nehmen, so bekommt man maximal 4080 raus, also nicht ganz ausgefüllte 12 Bit.
    Eine andere Methode wäre eine Lookuptabelle mit 256 Werten zu nehmen die dann einen 12 Bit Wert raus gibt.
    Hier könnte man dann auch gleich eine LED Korrekturkurve einbringen.


    Was habt Ihr so für Vorschläge, was ist am besten bzw resourcenschonensten auf einem AVR zu realisieren.
    Multiplizieren sollte relativ lange dauern, ist ja nicht gerade die Meisterdisziplin eines AVR.


    So und nun legt mal los.
    Greetz

  • Einfachste Methode wäre einfach die 8Bit * 16 zu nehmen, so bekommt man maximal 4080 raus, also nicht ganz ausgefüllte 12 Bit.


    8bit sind 256 verschiedene Werte, inklusive der 0. *16 ergibt sich natürlich genau 4096, also volle 12bit.
    Multiplizieren ist tatsächlich nicht so schlimm. Da du aber mit einer 2er-Potenz multiplizierst, könntest du den Wert auch shiften. In Bascom wäre das
    Shift dein_wert, Left, 4


    Bei meinen Anwendungen war aber ein 8-bit Farbwert immer RRRGGGBB, ein 12-bit Wert RRRRGGGGBBBB.
    Den kannst du ja so nicht als Ganzes multiplizieren, sondern müsstest immer nur den entsprechenden Farbteil nehmen.

    Zitat

    Eine andere Methode wäre eine Lookuptabelle mit 256 Werten zu nehmen die dann einen 12 Bit Wert raus gibt.
    Hier könnte man dann auch gleich eine LED Korrekturkurve einbringen.


    Dies sehe ich auch so. Aber hier müsstest du 16 bit (Word) nehmen. Dies würde also insgesamt 512 Byte belegen.


    BEye

  • Hey, klar Shiften geht auch. =)


    Aber 255*16 sind bei mir 4080 und 255 ist nunmal der höchste 8Bit Wert.
    Wenn man übrigens 1111 1111 shiftet kommt auch 1111 1111 0000 = 4080 raus


    Zum Thema 8 Bit RGB, ich sagte ja gegeben ist 8Bit pro Farbe, und das ganze als HEX vorliegend RR GG BB also z.B.
    FF FF FF für Weiß
    Um genauer zu werDen der Standard kommt vom 24Bit *.bmp, dort liegen die Daten so vor.


    Zum Thema Platzverbrauch, es ist ein uC mit mindestens 64k Flash geplant, da verkrafte ich das halbe gerade so =)
    (Word) kenne ich als Cler nicht, aber ist klar was du meinst :P


    Greetz

  • Nutze doch einfach Normalisierung.
    http://de.wikipedia.org/wiki/Normalisierung_(Mathematik)
    Wende ich zur Zeit auch bei meinem Terminal-Programm und dem Temperaturverlauf mit HDSP-2502 + DS18S20 an.
    Die meiste Rechnerei kann man als Konstanten ablegen wenn die Min/Max Werte statisch sind (ist ja hier der Fall).


    (hier nochmal Danke für den selben Tip letztens von DaOriginalFighter ;) )


    Noch ein kleiner Gedanke zu den 12Bit:
    Ggfs. sollte man vielleicht nicht nur stump umrechnen, sondern bei Fades die Lücken zwischen den 8Bit Werten füllen.
    Wenn ein Fade z.B. von 3 auf 4 in 8Bit ginge, profitiert man sicher von den 14 möglichen Zwischenstufen in 12Bit.

  • Okay also cih bin jetzt nicht so der über Mathe Freak,
    habe mir die Wiki Seite aber mal gründlich durchgelesen und mit der Formel in Excel mal etwas experimentiert.


    [Blockierte Grafik: http://upload.wikimedia.org/math/8/3/6/836c7bd5f9e038f4f123cfca3c440c25.png]


    12bit_wert = (8bit_wert- 0) * (4095-0) / (255-0) + 0


    12bit_wert = 8bit_wert * 4095 / 255


    12bit_wert = 8bit_wert * 16,0588235


    Ergo, hier wird einfach mit einer genaueren Zahl und zwar dem Verhältniss von 12 zu 8 Bit multipliziert, dadurch verliert man ncihts am Ende des Wertbereichs, aber lässt sich das noch resourcenschonend nem uC beibringen?


    Greetz


    PS: Fading spielt bei mir keine Rolle, da ich wirklich die 8 Bit 1:1 als 12 Bit weitergeben möchte

  • Also der einzig vernünftige Weg, hier von 8 Bit auf 12 Bit zu kommen, ist die "Umrechnung" über ne Tabelle - wenn Du irgendwie multiplizierst, hast Du letztlich auch wieder nur 8 Bit Auflösung, also kannst Du Dir die 12 Bit gleich sparen...


    die Tabelle ist mit exponentiell ansteigenden Werten gefüllt, um die logarithmische Empfindlichkeit des Auges auszugleichen - damit ein Anstieg von z.B. 10 auf 20 als ebenso großer Schritt wie der von 200 auf 210 empfunden wird - ohne Korrektur verläuft das nicht linear, wäre doch schade, 12 Bit zu nehmen und dann hast Du von (Eingangswert) 230 bis 255 so gut wie keine Helligkeitsänderung mehr - dafür findest Du 5 doppelt so hell wie 4...


    siehe dazu auch hier (inkl. weiterführenden Links)

    It's only light - but we like it!


    Da es sich in letzter Zeit häuft: Ich beantworte keine PNs mit Fragen, die sich auch im Forum beantworten lassen!
    Insbesondere solche von Mitgliedern mit 0 Beiträgen, die dann meist auch noch Sachen fragen, die bereits im entsprechenden Thread beantwortet wurden.
    Ich bin keine private Bastler-Hotline, technische Tipps etc. sollen möglichst vielen Lesern im Forum helfen!

  • ...kannst Du Dir die 12 Bit gleich sparen...


    die Tabelle ist mit exponentiell ansteigenden Werten gefüllt, um die logarithmische Empfindlichkeit des Auges auszugleichen - damit ein Anstieg von z.B. 10 auf 20 als ebenso großer Schritt wie der von 200 auf 210 empfunden wird - ohne Korrektur verläuft das nicht linear, wäre doch schade, 12 Bit zu nehmen und dann hast Du von (Eingangswert) 230 bis 255 so gut wie keine Helligkeitsänderung mehr - dafür findest Du 5 doppelt so hell wie 4...

    Ich sage nur TLC5947, ich brauche also 12 Bit, habe aber nur 8 Input...


    Das mit der Tabelle ist ja was ich oben sagte, Kennlinie anpassen und jut ist, somit hat man dann trotzdem nur 8 Bit, aber immerhin eine log Kennlinie.


    Thanks& Greetz

  • Aber Achtung:
    Wenn du die Werte für R, G und B einzeln über eine exponentielle Anpassungskurve jagst, dann stimmt nachher die Farbdynamik überhaupt nicht mehr. Das war ja auch der Grund, dass wir in dem anderen Thread über eine Umwandlung nach HSV und wieder zurück geschrieben haben. Bei HSV ist eben die Gesamthelligkeitsinformation von der Farbinformation getrennt, so dass du eben gezielt nur die Helligkeit über die Tabelle anpassen kannst. Alles andere ist total kontraproduktiv.
    Wenn du dir diesen Aufwand (RGB -> HSV -> V über Exponentialtabelle anpassen -> RGB) aber nicht antun willst, ist auf jeden Fall eine lineare Erweiterung deiner 8-Bit-Werte auf 12 Bit vollkommen unproblematisch, also 4 x Links-Shift deiner R-, G- und B-Werte. Damit bekommst du zwar keine Verbesserung der Auflösung, wie oben auch schon angemerkt wurde, aber immerhin bekommst du die RGB-Werte verhältnistreu in deinen TLC5947 (im Sinne von "what comes is gets out"), falls primär dies dein Ziel ist.


    Gruss
    Neni

  • Ich habs bei meiner 10Bit BCM so gemacht wie Pesi vorgeschlagen hat.


    Da gibts so einen Excelsheet irgendwo auf der Seite: Klick
    Da muss man seine Werte nur mehr eingeben und bekommt linearisierte Werte ...


    Außerdem hat das mit der Formel berechnen noch einen Nachteil:
    Wenn du nen Array machst mit
    uint16_t feld[255] und dem im Programmspeicher ablegst braucht das ganze 510Bytes Platz aber du brauchst beim umrechnen immer nur 3Zyklen


    Bei der Berechnung brauchst du definitiv länger (außer wenn dus statisch mit *16 Multiplizierst dann kannste das ganze shiften und braucht auch 3 Zyklen insgesammt)

  • Nun, ich sage nur, was Sache ist. Wenn man mit einer vollkommen falschen Farbdynamik (resultierend aus falschen Verhältnis-Werten der R-, G- und B-Werte zueinander nach einer unabhängigen 'Exponentialisierung' aller drei Werte) leben kann/will, dann ist's mir auch egal.


    Die Problematik kennt Pesi übrigens auch ;) , er hat ja auch schon selbst oft genug darauf hingewiesen. Ich nehme mal an, dass er es hier in diesem Thread (und auch in deinem bezüglich BCM) schlicht vergessen (bzw. gar nicht daran gedacht) hat, darauf hinzuweisen.


    Gruss
    Neni

  • Okay so wie es aussieht, werde ich es einfach shiften.
    3 Taktzyklen hört sich gut an, sehr gut sogar =)
    Laut synvox bekomm ich dann auch keine Farbverschieung und der weis ja was er redet.


    Evtl werde ich dann das ganze mit der LookUp Tabelle zusätzlich proggen, dann nur Versuch macht klug =)


    Ich danke euch =)


    Greetz

  • die 3 Zyklen waren geschätzt ....
    für den shift einer 8Bit zahl braucht er 1Zyklus bei 16bit nehm ich mal 3 an weil er 2 Zyklen zum shiften braucht und 1en wird er brauchen um das Register nachzuladen, dazu kommen dann aber sicher noch 1-2 Zyklen vor und nach dem shift (die kommen bei jeder Methode, dort muss er halt irgendwo was in einen Register laden usw ....).......

  • Was auch funktionieren sollte, um eine grössere und insbesondere exponentielle Dynamik ohne Farbverschiebungen zu erhalten, ist folgendes:


    Du hast eine entsprechende Exponential-Tabelle mit 256 Werten, welche den Bereich 0 bis 4095 abdecken. Bei der Umwandlung bestimmst du zunächst den grössten der drei Werte R, G oder B. Mit diesem fütterst du deine Tabelle und erhälst einen entsprechenden Ergebniswert. Diesen Ergebniswert teilst du nun durch den Ursprungswert (mit dem du die Tabelle gefüttert hast) und bekommst einen Faktor. Diesen Faktor multiplizierst du nun mit den anderen beiden Ursrprungswerten und hast am Ende so die Ergebniswerte für alle drei Grundfarben R, G und B.


    Der Grauwert (Helligkeits-Wert; gewichtete Summe der Werte für R, G und B) des RGB-Wertes folgt so einer exponentiellen Kennlinie (bzw. der Kennlinie der Tabelle) mit Dynamikumfang der Werte für R, G und B von 0 bis 4095, ohne dass sich die Verhältnisse von R, G und B zueinander ändern, also ohne Farbverschiebungen.


    Als ich in der anderen Diskussion damals den Grauwert als mögliche Lösung ins Spiel gebracht hatte, kam mir einfach nicht die richtige Idee. Der Fehler war damals, dass ich mit dem Grauwert selbst irgendwie arbeiten wollte, und das war eher kontraproduktiv ;) . Hier sieht man, dass man den Grauwert eigentlich gar nicht benötigt. Er folgt automatisch der auferlegten Kennlinie, wenn man es eben richtig macht ;) . Manchmal ist es eben doch von Vorteil, nach einem längeren Zeitintervall wieder das gleiche Problem vor die Nase gestossen zu bekommen :D .


    Abschliessend ist noch zu sagen, dass man auch hier keine bessere Auflösung bekommt (die bleibt 8 Bit pro Grundfarbe). Der Dynamikumfang erhöht sich aber auf die vollen 12 Bit, und das mit einer exponentiellen (oder was die Tabelle auch immer macht) Kennlinie für die Helligkeitsinformation.


    Die zusätzlich erforderliche Faktor-Rechnung benötigt natürlich schon deutlich mehr Zyklen bei der Umwandlung als eine rein lineare Bereichsstreckung. Durch geschickte Wahl der Variablen-Typen und mittels Wertebereichserweiterungen bei den Zwischenergebnissen kann allerdings auf Fliesskomma-Arithmetik verzichtet werden, ohne dabei grosse Ungenauigkeiten in Kauf nehmen zu müssen.


    Gruss
    Neni

  • Ich sage nur TLC5947, ich brauche also 12 Bit, habe aber nur 8 Input...

    ich weiß ;) - ich wollte nur darauf hinaus: wenn Du es so machst:

    Okay so wie es aussieht, werde ich es einfach shiften.

    dann verschenkst Du die kleinsten 4 Bit (die sind dann immer "0000") und hast dann im Endeffekt ne 8-Bit-PWM - und dafür ist der TLC doch zu schade, wir (also ich zumindest) haben den doch extra wegen den 12 Bit genommen...

    3 Taktzyklen hört sich gut an, sehr gut sogar =)

    der Atmega kann auch HW-Multiplikation, zwei 8-Bit-Zahlen multiplizieren macht genau 2 Takte... ;)

    Die Problematik kennt Pesi übrigens auch ;) , er hat ja auch schon selbst oft genug darauf hingewiesen. Ich nehme mal an, dass er es hier in diesem Thread (und auch in deinem bezüglich BCM) schlicht vergessen (bzw. gar nicht daran gedacht) hat, darauf hinzuweisen.

    Doch , ich habe dran gedacht... ;) - ich habe nur gelesen, dass hier Daten aus nem .bmp ausgegeben werden sollen, also wohl Bilder - und da kommt dann im Prinzip die selbe Korrektur in Frage wie bei nem Monitor, und die geht anders (habe mich zwischenzeitlich informiert).


    im Bildverarbeitungs-Farbraum sind nämlich die Farbwerte schon auf das Helligkeitsempfinden des Auges normiert, nicht auf die Strahlungsleistung! - also z.B. der Wert "128" ist hier bereits "halbe Helligkeit", während bei der Strahlungsleistung (wenn jetzt LED aus = 0, LED voll an = 255) ein Wert von 128 deutlich mehr als "halbe Helligkeit" ergibt.


    Bzgl. Strahlungsleistung (= PWM-Wert) sind die RGB-Daten in nem Bild also schon total krumm! d.h. wenn ich die Daten aus dem Bild 1:1 an PWM ausgebe, dann ergibt z.B. 60:30:20 nicht die selbe Farbe wie am Monitor, weil es einmal die "Augen-Helligkeit" ist und einmal die Strahlungsleistung.


    Also muss hier *pro Kanal* wieder von "empfundener Helligkeit" auf "Strahlungsleistung" zurückgerechnet werden - weil z.B. ein Rückgang von 60 auf 30 nicht halbe Strahlungsleistung bedeutet, sondern halbe empfundene Helligkeit... soll die Matrix als "Monitor"/Videowall o.ä. genutzt werden, ist das also schon richtig, jede Farbe einzeln durch die Kurve zu jagen (im Idealfall sogar durch 3 getrennte Kurven, um Farbstiche ausgleichen zu können)


    natürlich funktioniert das dann nicht, dass ich mit nem Lichtpult ne Farbe einstelle, die runterdimme und sie bleibt gleich - weil ich am Lichtpult letztlich normalerweise (ohne alle Korrekturen) nicht die Helligkeit einstelle, sondern die Strahlungsleistung der LED...


    dafür (Lichtpult-Anwendung) wäre dann natürlich die oben von Dir genannte Methode super - das Problem beim Grauwert war ja die "doppelte Dimmung", das umgeht man so... und auch mir ist was neues eingefallen, um das einfacher zu machen:


    normal hat man ja ne Lookup-Tabelle, wo man nachschaut, *z.B.*:


    0 rein = 0 raus
    1 rein = 1 raus
    128 rein = 1.600 raus
    255 rein = 4.095 raus


    man macht nun stattdessen ne Multiplikator-Tabelle, schaut da also nach, womit man den Eingangswert multiplizieren muss, um auf den Ausgangswert zu kommen - z.B.:


    0 rein = 0 raus x 0 = 0
    1 rein = 1 raus x 1 = 1
    128 rein = 12,5 raus x 128 = 1.600
    255 rein = 16,06 raus x 255 = 4.095


    damit man nicht mit FK-Zahlen rechnen muss, kann man das hier ja auf 16 Bit machen, und dann nur die obersten 12 Bit nehmen, also z.B.


    255 rein = 257 raus (ja, Tabelle dann halt auch in 16 Bit) x 255 = 65.535, davon die obersten 12 Bit = 4.095


    multiplizieren kann der ATMega wie gesagt in HW, die obersten 12 Bit nehmen ist auch nur etwas Geschiebe...


    und der Witz dran: man sucht sich aus der Tabelle praktisch den einen Multiplikator, und wendet diesen dann auf alle 3 Farben an - womit das Verhältnis der Farben wieder gleich bleibt, aber der Zusammenhang zwischen 8 Bit rein und 12 Bit raus nicht mehr linear ist, sondern wie gewünscht angepasst...


    also praktisch *genau die Methode von Neni*, nur mit etwas weniger Rechnerei... ;) (ich muss nicht jedesmal den Ergebniswert durch den Ursprungswert teilen (das geht nicht in HW), sondern habe eben *diese* 255 möglichen Faktoren schon *vorberechnet* in ner Tabelle drin..)


    P.S.: das Nonplusultra wäre natürlich, wenn man zwischen diesen beiden Korrekturmöglichkeiten umschalten und evtl. sogar noch versch. Tabellen auswählen könnte - gibt's bei Videobeamern ja auch, meiner hat z.B. Presets "Kino", "Präsentation", "helle Umgebung", "Grafik" etc., macht je nachdem ein ziemlich unterschiedliches Bild was Farben und Kontrast betrifft...

    It's only light - but we like it!


    Da es sich in letzter Zeit häuft: Ich beantworte keine PNs mit Fragen, die sich auch im Forum beantworten lassen!
    Insbesondere solche von Mitgliedern mit 0 Beiträgen, die dann meist auch noch Sachen fragen, die bereits im entsprechenden Thread beantwortet wurden.
    Ich bin keine private Bastler-Hotline, technische Tipps etc. sollen möglichst vielen Lesern im Forum helfen!

    Einmal editiert, zuletzt von Pesi ()

  • Hey Pesi, ich weis das ich dann 4 Bit verchenken würde, aber das ganze soll auch nur eine von vielen vielen Funktionen sein.
    Wie gesagt die Quelle soll eine BMP auf SD Karte im 24 Bit Format sein. Darin sind dann halt die 8 Bit Farben.


    Danke für den Tipp mit dem HW-Multi, wieder etwas gelernt ;)


    Das die BMP schon angepasst sind, also an die Helligkeitskurve war mir ebenfalls neu,
    wie du schon sgst wirft das ganz neue Möglichkeiten auf, bzw macht die LookUp Tabelle garnicht so abwägig.


    Deine Multiplikator-Tabellen-Methode versteh ich noch nicht ganz.
    B.z.w. sag mir mal ob ich das richtig verstanden habe:


    Rot ist 128 -> Aha unser Multi ist 12,5
    rot12 = rot8 * 12,5
    grün12 = grün8 * 12,5
    blau12 = blau8 * 12,5


    Wenn ich das nicht richtig verstanden habe, sach mir ma bitte wer den Multiplikator bestimmt.



    Greetz

  • Nach der Methode die hellste Farbe - also wenn jetzt z.B. Rot den höchsten Wert hat, dann wird das genommen, um den Wert aus der Tabelle zu holen, wenn Grün den höchsten Wert hat, dann halt das - muss man halt vorher schauen, welche von den 3 Farben am hellsten ist...


    nur schon mal so vorab, da muss man gar nicht groß sortieren, einfach so (Pseudocode):


    Temp = Rot
    Wenn Grün größer als Temp, dann Temp = Grün
    Wenn Blau größer als Temp, dann Temp = Blau


    und dann mit dem Wert aus Temp in der Tabelle nachgucken...


    wie gesagt, wenn Du BMPs ausgeben willst, würde ich das direkt mal versuchen mit einfach jeden Wert durch die Kurve zu jagen - wenn's komisch aussieht, kann man immer noch weiter überlegen...


    wie ist das denn mit der SD-Karte (Neugier)? - spielst Du die Daten am Rechner da drauf..? - ich habe mich auch schon mit sowas befasst, kann aber nur Bytes in Blöcken schreiben und lesen (geht einfach über SPI), mit Dateisystem kenne ich mich nicht aus, also wie ich nun Daten aus Bildern holen sollte, die ich mit dem PC auf die Karte gespeichert habe... schreibst Du das selbst, oder hast Du da ne Lib irgendwo...? (Du machst auch Assembler, oder..?)

    It's only light - but we like it!


    Da es sich in letzter Zeit häuft: Ich beantworte keine PNs mit Fragen, die sich auch im Forum beantworten lassen!
    Insbesondere solche von Mitgliedern mit 0 Beiträgen, die dann meist auch noch Sachen fragen, die bereits im entsprechenden Thread beantwortet wurden.
    Ich bin keine private Bastler-Hotline, technische Tipps etc. sollen möglichst vielen Lesern im Forum helfen!

  • Werde es jetzt se machen wie du es sagst,
    erstmal Kurve, wenns nicht gut aussieht kann man weiter schauen.


    Jetzt hab ich deine Theorie auch verstanden, da hat die Info gefehlt =)


    Bin leider nen .c und kein .asm :D


    Zum Thema SD-Karte, ich habs noch nie gemacht, aber alles in Planung, und sehr viel gelesen die letzten Tage.
    Da ich zwar viel kann aber so viel dann auch nicht, werde ich eine fertige Lib nehmen.
    Angesprochen wird über SPI wie du schon sagst, daten möchte ich am PC erstellen und drauf spielen. Prinzip digitaler Bilderrahmen


    Ganz interresante Libs gibts von Ulrich Radig, einfach googlen, und von mikrocontroller.net
    Für meinen Zweck gibts dann ne fertige Lib sammt Fat16/32 mit verschiedenen file Befehlen.
    Also einfach f_open(); und f_read() wobei ich dann ab nem bestimmten Offset anfange, da bmp Dateien ja auch nen Header mit Infos haben.
    Und dann kommt nacheinander R G B R G B... jeweils als 8Bit rein angefangen von Pixel links unten nach rechts unten und dann nach oben.


    Greetz

  • Mit einfachem Schieben der 8 Bit füllst du ja nicht den vollen Wertebereich der 12 Bit aus. Wenn die Helligkeit nicht bis zum Maximum ausgeschöpft wird, fällt das zwar nicht sonderlich auf, ist aber trotzdem unschön, weil man mit extrem wenig Aufwand den vollen Bereich nutzen könnte.


    Kopiere doch einfach in die vier niederwertigen Bits des 12-Bit-Wortes die vier höherwertigen Bits des originalen 8-Bit-Wortes rein. Damit wird in 16er-Stufen die Helligkeit noch etwas angehoben. 8-Bit-Null bleibt auch 12-Bit-Null und aus 255 wird 4095.