Bayer-Pattern
zu RGB |
 |
von
Dirk Schäfer |
 |
Die meisten digitalen Farbkameras sind mit CCDs ausgerüstet,
welche über eine Farbmaske das Licht filtern. Diese Bayer-Maske
(oder Bayer-pattern) gewichtet Grün stärker als Blau und Rot.
RGRG |
R = Rot |
G = Grün |
B = Blau |
GBGB |
|
|
|
RGRG |
|
|
|
Innerhalb des Fertigungsprozesses startet die Maske nicht
immer mit einem Filter für Rot, und auch nicht immer in einer Zeile
ohne Blau-Filter. Es gibt also 4 Masken.
RGRG |
GRGR |
GBGB |
BGBG |
GBGB |
BGBG |
RGRG |
GRGR |
RGRG |
GRGR |
GBGB |
BGBG |
Die Farbanteile eines RGB-Bildes, Rot, Grün und Blau,
können also nur durch Mittelung der Nachbarpixel im Graubild gewonnen
werden. Das folgende Bild zeigt ein Graubild mit Bayer-Filter und das Farbbild.
Da sich die möglichen Spalten RG oder GR, sowie GB oder
BG, wiederholen, und
die Zeilen RG-GB, GR-BG, GB-RG und BG-GR dies ebenfalls
tun, ergeben sich folgende Möglichkeiten.
RGRG |
GRGR |
GBGB |
BGBG |
GBGB |
BGBG |
RGRG |
GRGR |
RGRG |
GRGR |
GBGB |
BGBG |
GBGB |
BGBG |
RGRG |
GRGR |
Bei DWORD-Zugriffen kann man also in einer Zeile immer zwei
Masken gleichzeitig bestimmen, und den DWORD-Zeiger jeweils nur um 2 Byte
erhöhen. Auch lassen sich gerade und ungerade Zeilen nacheinander
berechnen, da sich beide dann wiederholen.
RGRG B= 22 B= (22+24)/2
GBGB G= (12+21+23+32)/4 G= 23
RGRG R= (11+13+31+33)/4 R= (13+33)/2
GBGB B= (12+32)/2 B= (12+14+32+34)/4
RGRG G= 22 G= (13+22+24+33)/4
GBGB R= (21+23)/2 R= 23
Bei Masken die mit BG oder GR starten, ist die Reihenfolge
umzudrehen.
Da die Umrechnung der Bilddaten rechenintensiv ist, wird
hier eine Lösung mit MMX vorgestellt. Als Vorraussetzung gilt, dass
die Zeilen im Grau- und im Farbbild DWORD-aligned sind.
Der C-Source ist einfach und arbeitet mit Byte-Zeigern.
Den C-Quellcode finden Sie als HTML-Dokument in einem
separaten Browser-Fenster |
 |
Dieser C-Code benötigt auf einem 2,5 Jahre alten
PIII 500MHz ca. 33 ms.
In Assembler, und mit MMX, reduziert sich die Zeit auf
13 ms, auf einem PIII 1GHz mit 133 FSB sogar auf 8 ms.
Da es sich bei dem Bild um ein BG-Bild handelt, wurde
der Code auch nur für dieses Format geschrieben. Optimierungen über
pairing, also gutes Laden der U- und V-Pipe um parallele Ausführung
zu ermöglichen, sind nicht vorgenommen worden. Auch lassen sich z.B.
MMX-Memory-Befehle nur mit MMX-Befehlen pairen.
Die ersten 4 Pixel, also Bytes, des Graubildes sind wie
folgt angeordnet:
BGBG 11,12,13,13
GRGR 21,22,23,24
BGBG 31,32,33,34
Das Farbbild startet also mit dem 1. Rotpixel der zweiten
Zeile, R1 = 22. Der Grünwert errechnet sich zu (12+21+23+32)/4 und
der Blauwert zu (11+13+31+33)/4. Der zweite Pixel des Farbbildes ist auch
in diesen 3 DWORDs enthalten.
R2= (22+24)/2, G2= 23, B2= (13+33)/2
Verschiebt man jetzt die DWORDs um 2 Bytes, die Adressen
bleiben gerade, kann man die nächsten 2 Pixel des Farbbildes bestimmen.
Die o.g. Masken kommen innerhalb einer Zeile abwechselnd zum Einsatz.
Die Formeln für die Farbwerte sind also:
R1= 22
G1= (12+21+23+32)/4
B1= (11+13+31+33)/4
R2= (22+24)/2
G2= 23
B2= (13+33)/2
In der nächsten Zeile ist dann folgende Maske zu
bearbeiten:
GRGR
BGBG
GRGR
Diese beiden Zeilen wechseln sich nun im Bild ab. Die
Schleife über die Zeile wird also zweimal hintereinander ausgeführt,
zuerst mit der BG-Mittelung, dann mit der GR-Mittelung.
Den Assembler-Quellcode finden Sie als HTML-Dokument
in einem separaten Browser-Fenster |
 |
Eine 3x3-Maske reduziert das Bild um 2 Zeilen und um 2
Spalten. Da pro DWORD-Zugriff zwei Pixel bestimmt werden können, und
zwei Schleifen jeweils eine gerade und die folgende Zeile errechnen, werden
die Schleifen nur über die halbe Anzahl Zeilen und Spalten geführt.
width -= 2;
width >>= 1; // an jeder 2. Stelle ein DWORD einlesen
height -= 2;
height >>= 1;
Die folgende Zeile zentriert das Bild, ist aber nicht
notwendig
pColor= pColor + iColorStep +3;
Der Assemblerteil der doppelten Schleife wird vorrausgesetzt.
Der erste MMX-Befehl liest ein DWORD ein,
movd mm0, [esi], die in den folgenden Zeilen
liegenden Pixel werden ebenfalls eingelesen,
wobei esi um die Länge einer Zeile, in Bytes, erhöht
wird
add esi, iGrayStep
; nächste Zeile
movd mm1, [esi]
add esi, iGrayStep
movd mm2, [esi]
Die MMX-Register mm0, mm1 und mm2 enthalten jetzt die
Bytes des Graubildes.
mm0: 00 00 00 00 7c 2a 7d 2a
mm1: 00 00 00 00 db 8b df 8d
mm2: 00 00 00 00 82 2b 83 2b
Vom niedrigsten Byte aus sieht die Matrix wie folgt aus:
00 00 00 00 14 13 12 11
00 00 00 00 24 23 22 21
00 00 00 00 34 33 32 31
Da bei der Addition ein möglicher Überlauf zwar
per Flag kontrolliert werden kann, hier aber höchstens 4 Bytes addiert
werden, ist eine Umwandlung in WORDs sinnvoll.
Der Befehl punpcklbw schiebt das höchste
Byte im lowdword des Operanden in das highbyte des höchsten WORD.
mm3: 7c00 2a00 7d00 2a00
mm4: db00 8b00 df00 8d00
mm5: 8200 2b00 8300 2b00
WORD-weise schieben erzeugt passende 16bit-Werte
psrlw mm3, 8
mm3: 007c 002a 007d 002a
mm4: 00db 008b 00df 008d
mm5: 0082 002b 0083 002b
Diese Werte können jetzt addiert werden, ohne das
ein Überlauf möglich ist.
Nach Addition und Division durch 2, paddw mm5, mm3,
psrlw mm5, 1, enthält mm5 die Terme: (14+34)/2 , (13+33)/2
, (12+32)/2 , (11+31)/2
Die Werte von mm4 nach mm6 kopiert, movq mm6, mm4,
und durch das Schieben von 32 nach rechts psrlq mm6, 32,
neu angeordnet.
mm6: 0000 0000 00db 008b
Die Addition von mm4 und mm6 ergibt, nach Teilung durch
2,
paddw mm6, mm4
psrlw mm6, 1
folgende Werte in mm6: 006d 0045 00dd 008c.
Die beiden oberen WORDs sind unwichtig, die beiden unteren
entsprechen
(22+24)/2 und (21+23)/2.
Um (14+34+12+32)/4 und (13+33+11+31)/4 zu bestimmen wird
mm5 in mm7 kopiert, um 32 geschoben, mit mm5 addiert und durch 2 geteilt.
movq mm7, mm5
psrlq mm7, 32
paddw mm7, mm5
psrlw mm7, 1
Die beiden oberen WORDs sind nutzlos.
mm5 in mm0, um 16 geschoben und mit mm6 addiert ergibt,
movq mm0, mm5
psrlq mm0, 16
paddw mm0, mm6
psrlw mm0, 1
, (12+32+21+23)/4 und (13+33+22+24)/4 in mm0.
mm7: 0x003f0015007f002a
mm6: 0x006d004500dd008c
mm5: 0x007f002a0080002a
mm4: 0x00db008b00df008d
mm0: 0x0036006200830086
Da Pixel in Farbbildern immer BGR geschrieben werden,
ergibt sich folgende Reihenfolge der 6 Bytes.
B1= (11+13+31+33)/4 -> mm7, Byte(0)
G1= (12+21+23+32)/4 -> mm5, Byte(2)
R1= 22 -> mm4, Byte(2)
B2= (13+33)/2 -> mm5, Byte(3)
G2= 23 -> mm4, Byte(4)
R2= (22+24)/2 -> mm6, Byte(3)
Die MMX-Register werden nun geschoben, nach links und
rechts, um alle nicht interessierenden Bytes auf 0 zu setzen. Dies ließe
sich auch mit AND und entsprechenden Masken durchführen.
Nachdem in jedem Register nur noch das/die entsprechenden
Byte(s) stehen, können alle Register ohne Überlauf addiert werden.
Da die Schleife über die Spalten mit dem ersten Pixel
beginnt, und das Farbbild DWORD-aligned ist, kann das gesamte MMX-Register
geschrieben werden.
movq [edi], mm4
Erhöhen von edi um 6, also 2 x RGB, sorgt beim nächsten
schreiben für das Überschreiben der sinnlosen 2 Byte, da ein
MMX-Register 8Byte enthält. Es wurden aber nur die unteren 6 Byte
mit den beiden Farbwerten geladen.
Die zweite innere Schleife berechnet jetzt die nächste
Zeile. Für die 4 möglichen Masken wird jeweils ein Assembler-Code
geschrieben und je nach Maske der entsprechende aufgerufen. |