Frage

Ich habe meine Hände auf ein 16-bit-rgb565-Bild (speziell, ein Android-framebuffer-dump), und ich möchte es konvertieren zu 24 bit rgb888 für die Anzeige auf einem normalen monitor.

Die Frage ist, wie stellt man das konvertieren einer 5 - oder 6-bit-Kanal an 8 bit?Die offensichtliche Antwort ist, zu verschieben.Ich begann mit dem schreiben dieses:

puts("P6 320 480 255");
uint16_t buf;
while (read(0, &buf, sizeof buf)) {
    unsigned char red = (buf & 0xf800) >> 11;
    unsigned char green = (buf & 0x07e0) >> 5;
    unsigned char blue = buf & 0x001f;
    putchar(red << 3);
    putchar(green << 2);
    putchar(blue << 3);
}

Dies bedeutet jedoch nicht, haben eine Eigenschaft, die ich möchte, die für 0xffff zur Karte 0xffffff, statt 0xf8fcf8.Muss ich das erweitern der Wert in einige Weg, aber ich bin mir nicht sicher, wie das funktionieren sollte.

Das Android SDK enthält ein tool namens ddms (Dalvik Debug Monitor), nimmt screenshots.So weit wie ich kann sagen, aus Lesen Sie den code, es implementiert die gleiche Logik;doch seine Bilder kommen aus verschiedenen, und weiß ist die Zuordnung zu weiß.

Hier ist die raw framebuffer, die intelligente Konvertierung durch ddms, und die dumm Umwandlung durch den oben beschriebenen Algorithmus.Beachten Sie, dass der letztere ist etwas dunkler und grüner.

(Übrigens, dieser Umwandlung ist implementiert in ffmpeg, aber es ist auch nur die Durchführung der dumme conversion oben aufgeführten verlassen des LSBs auf alle null.)

Ich glaube, ich habe zwei Fragen:

  • Was ist der vernünftigste Weg, um zu konvertieren rgb565 zu rgb888?
  • Wie ist DDMS der Umwandlung der screenshots?
War es hilfreich?

Lösung

Sie können verschieben und dann oder mit den höchstwertigen Bits; d.

Red 10101 becomes 10101000 | 101 => 10101101
    12345         12345---   123    12345123

Dies hat die Eigenschaft, die Sie suchen, aber es ist nicht die lineare Abbildung von Werten von einem Raum zum anderen. Es ist schnell, though. :)

Cletus' Antwort ist vollständiger und wahrscheinlich besser. :)

Andere Tipps

Sie wollen eine Karte von dieser aus eine 5/6 etwas Platz, um ein 8-bit-Raum.

  • 5 bits = 32 Werte
  • 6 bit = 64 Werte
  • 8 bit = 256 Werte

Der code, die Sie verwenden, ist unter der naive Ansatz, der x5 * 256/32 = x8, wo 256/32 = 8 und Multiplikation von 8 ist die linke shift-3, sondern, wie Sie sagen, dies bedeutet nicht unbedingt, füllen Sie die neue Anzahl space "richtig".5 bis 8 für max-Wert ist der 31 255, darin liegt dein Schlüssel zu der Lösung.

x8 = 255/31 * x5
x8 = 255/63 * x6

wo x5, x6 und x8 sind 5 -, 6-und 8-bit-Werte jeweils.

Jetzt gibt es eine Frage über den besten Weg, um dies zu implementieren.Es bezieht mit division und die division, Sie wird verlieren alle übrigen Ergebnis (Runden nach unten ab, im Grunde), so dass die beste Lösung ist wahrscheinlich zu tun, Gleitkomma-Arithmetik und dann rund die Hälfte bis zurück in eine Ganzzahl.

Dies beschleunigt erheblich, indem Sie einfach unter Verwendung dieser Formel zu generieren, die ein lookup-Tabelle für jedes der 5-und 6-bit-Konvertierungen.

Meine paar Cent:

Wenn Sie genaue Zuordnung kümmern, noch schneller Algorithmus können Sie dies berücksichtigen:

R8 = ( R5 * 527 + 23 ) >> 6;
G8 = ( G6 * 259 + 33 ) >> 6;
B8 = ( B5 * 527 + 23 ) >> 6;

Es verwendet nur: MUL, ADD und SHR -> so ist es ziemlich schnell! Von der anderen Seite ist es in 100% Gleitkomma-Mapping mit dem richtigen Rundung kompatibel:

// R8 = (int) floor( R5 * 255.0 / 31.0 + 0.5);
// G8 = (int) floor( G6 * 255.0 / 63.0 + 0.5);
// B8 = (int) floor( R5 * 255.0 / 31.0 + 0.5);

Einige zusätzliche Cent: Wenn Sie in 888-565 Umwandlung interessiert sind, das funktioniert sehr gut auch:

R5 = ( R8 * 249 + 1014 ) >> 11;
G6 = ( G8 * 253 +  505 ) >> 10;
B5 = ( B8 * 249 + 1014 ) >> 11;

Konstanten wurde unter Verwendung von Brute-Force-Suche mit einigen frühen Ablehnungen Geschwindigkeit Dinge etwas gefunden.

iOS Vimage Conversion

Die NEON-Spezifika

Von Arm Community Forum Tutorial

  

Als erstes werden wir an, RGB565 zu RGB888 konvertieren. Wir gehen davon aus acht 16-Bit-Pixel im Register q0 sind, und wir möchten separaten Rot-, Grün- und Blautöne in 8-Bit-Elemente über drei Register auf d4 d2.

 vshr.u8      q1, q0, #3      @ shift red elements right by three bits,
                                @  discarding the green bits at the bottom of
                                @  the red 8-bit elements.
vshrn.i16    d2, q1, #5      @ shift red elements right and narrow,
                                @  discarding the blue and green bits.
vshrn.i16    d3, q0, #5      @ shift green elements right and narrow,
                                @  discarding the blue bits and some red bits
                                @  due to narrowing.
vshl.i8      d3, d3, #2      @ shift green elements left, discarding the
                                @  remaining red bits, and placing green bits
                                @  in the correct place.
vshl.i16  q0, q0, #3      @ shift blue elements left to most-significant
                                @  bits of 8-bit color channel.
vmovn.i16    d4, q0          @ remove remaining red and green bits by
                                @  narrowing to 8 bits.
  

Die Auswirkungen jeden Befehl sind oben in den Kommentaren beschrieben, aber zusammenfassend die Operation auf jedem Kanal ausgeführt ist:   Entfernen von Farbdaten für benachbarte Kanäle verschieben die Bits aus jedem Ende des Elements zu drücken.   Verwenden eine zweite Verschiebung der Farbdaten in den höchstwertigen Bits jedes Elements zu positionieren, und verengen Elementgröße von 16 bis acht Bits zu reduzieren.

     

Beachten Sie die Verwendung von Elementgrößen in dieser Reihenfolge Adresse 8 und 16-Bit-Elemente, um einige der Maskierungsoperationen zu erreichen.

     

Ein kleines Problem

     

Sie können feststellen, dass, wenn Sie den Code oben zu konvertieren RGB888 Format verwenden, Ihre Weißen sind nicht ganz weiß. Dies liegt daran, dass, für jeden Kanal, die untersten zwei oder drei Bits Null sind, und nicht als eins ist; ein weißer in RGB565 als (0x1F, 0x3F, 0x1F) dargestellt wird (0xF8, 0xFC, 0xF8) in RGB888. Dies kann durch Verschiebung mit Einlage fixiert werden einige der höchstwertigen Bits in die unteren Bits zu setzen.

Für ein Android konkretes Beispiel fand ich ein YUV-RGB-Umwandlung in intrinsics geschrieben.

Versuchen Sie diese:

red5 = (buf & 0xF800) >> 11;
red8 = (red5 << 3) | (red5 >> 2);

Damit werden alle Nullen in alle Nullen Karte, alle 1 in alle 1'en, und alles dazwischen in alles dazwischen. Sie können durch Verschieben des Bits in in einem Schritt es effizienter machen:

redmask = (buf & 0xF800);
rgb888 = (redmask << 8) | ((redmask<<3)&0x070000) | /* green, blue */

Do ebenfalls für Grün und Blau (für 6 Bits, Verschiebung nach links 2 und rechts 4 jeweils in der Top-Methode).

Die allgemeine Lösung ist, die Zahlen als binäre Fraktionen zu behandeln - so wird die 6-Bit-Zahl 63/63 das gleiche wie die 8-Bit-Nummer 255/255 ist. Sie können diese unter Verwendung von Gleitkomma-Mathematik berechnen zunächst, dann eine Lookup-Tabelle berechnen, wie andere Plakate vorschlagen. Dies hat auch den Vorteil, dass sie intuitiver als Bit-Bashing Lösungen. :)

Es ist ein Fehler jleedev !!!

unsigned char green = (buf & 0x07c0) >> 5;
unsigned char blue = buf & 0x003f;

der gute Code

unsigned char green = (buf & 0x07e0) >> 5;
unsigned char blue = buf & 0x001f;

Cheers, Andy

habe ich die folgende und bekam gute Ergebnisse. Es stellte sich heraus war mein Logitek cam 16bit RGB555 und mit dem folgenden konvertieren RGB888 24bit mir erlaubt, als JPEG zu speichern mit den kleineren Tieren IJG. Danke für den Hinweis hier auf Stackoverflow gefunden

// Convert a 16 bit inbuf array to a 24 bit outbuf array
BOOL JpegFile::ByteConvert(BYTE* inbuf, BYTE* outbuf, UINT width, UINT height)
{     UINT row_cnt, pix_cnt;     
      ULONG off1 = 0, off2 = 0;
      BYTE  tbi1, tbi2, R5, G5, B5, R8, G8, B8;

      if (inbuf==NULL)
          return FALSE;

      for (row_cnt = 0; row_cnt <= height; row_cnt++) 
      {     off1 = row_cnt * width * 2;
            off2 = row_cnt * width * 3;
            for(pix_cnt=0; pix_cnt < width; pix_cnt++)
            {    tbi1 = inbuf[off1 + (pix_cnt * 2)];
                 tbi2 = inbuf[off1 + (pix_cnt * 2) + 1];
                 B5 = tbi1 & 0x1F;
                 G5 = (((tbi1 & 0xE0) >> 5) | ((tbi2 & 0x03) << 3)) & 0x1F;
                 R5 = (tbi2 >> 2) & 0x1F;
                 R8 = ( R5 * 527 + 23 ) >> 6;
                 G8 = ( G5 * 527 + 23 ) >> 6;
                 B8 = ( B5 * 527 + 23 ) >> 6;
                 outbuf[off2 + (pix_cnt * 3)] = R8;
                 outbuf[off2 + (pix_cnt * 3) + 1] = G8;
                 outbuf[off2 + (pix_cnt * 3) + 2] = B8;
            }
       }
       return TRUE;
}        
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top