¿Por qué replicar los bits más altos de RGB565 al convertir a RGBA8888?

7

He visto en algunas bases de código de software de gráficos de computadora que a veces los bits más altos de datos de imagen en formato RGB565 se replican en los bits más bajos cuando se convierten al formato RGBA8888 de mayor profundidad de bits.

He encontrado, por ejemplo, el comentario del usuario "eq" en este hilo de gamedev.net :

Prefiero replicar los bits superiores en los bits inferiores indefinidos:
R8 = (R5 << 3) | (R5 >> 2);

Sin embargo, no entiendo la razón detrás.

¿De qué sirve el propósito de replicar esos bits en los datos convertidos?

wip
fuente
1
Sin replicar los bits, los LSB serán 0, por lo que para el valor máximo de 0x1f (máximo para 5 bits) se expandiría a 0xf8 cuando se convierta a 8 bits. Lo que desea es 0xff, por lo que el rango de 0x00-> 0x1f se asignará a 0x00-> 0xff en lugar de 0x00-> 0xf8.
PaulHK
2
@PaulHK Por favor, publique eso como respuesta. Está completo tal como está, pero como comentario no se puede buscar.
Dan Hulme
Sí, gracias @PaulHK, esto responde correctamente a mi pregunta
wip

Respuestas:

7

Sin replicar los bits, los LSB serán 0, por lo que para el valor máximo de 0x1f (máximo para 5 bits) se expandiría a 0xf8 cuando se convierta a 8 bits. Lo que desea es 0xff, por lo que el rango de 0x00-> 0x1f se asignará a 0x00-> 0xff en lugar de 0x00-> 0xf8. Sin fusionar el LSB, no podrá convertir 0x1f, 0x1f, 0x1f a blanco (0xff, 0xff, 0xff). Por cierto, esto es lo mismo que N * 0xff / 0x1f.

Example: 

left shift only (<< 3)
%---00001 -> %00001000     (0x01 -> 0x08)
%---10000 -> %10000000     (0x10 -> 0x80)
%---11111 -> %11111000     (0x1f -> 0xf8)

merging MSB to LSB 
%---00001 -> %00001000     (0x01 -> 0x08)
%---10000 -> %10000100     (0x10 -> 0x84)
$---11111 -> %11111111     (0x1f -> 0xff)
PaulHK
fuente
7

En realidad, hay una razón matemática razonablemente buena para hacer la replicación de bits:

Primera nota que la cadena de n bits, norte, en realidad representa el valor norte2norte-1 y queremos producir la cadena de m bits, METRO, dónde norte<metro y

norte2norte-1METRO2metro-1

Primero escalamos el numerador y el denominador con

norte.(2norte+1)(2norte-1)(2norte+1)METRO2metro-1
y esto se simplifica a
norte.(2norte+1)22norte-1METRO2metro-1

En tu caso, norte{5 5,6 6} y metro=8 y podemos "parar" aquí, pero el proceso puede repetirse (ad nauseum), si m >> n.

A continuación hacemos la aproximación ...

norte.(2norte+1)22norteMETRO2metro
que se simplifica a
norte.(2norte+1)22norte-metroMETRO

Tenga en cuenta que norte.(2norte+1) es equivalente a repetir la cadena de n bits, para crear una cadena de 2 bits, y la división se desvía del 2norte-metro LSB para dejar un resultado de M bits.

QED

Por supuesto, el cálculo 'correcto' es METRO=((2metro-1)norte2norte-1+12pero esta aproximación, en general, funciona la mayor parte del tiempo. Por supuesto, hay momentos en que es inexacto, pero IIRC solo por un bit y con poca frecuencia.

Simon F
fuente
2
Gracias por una explicación detallada con buenas fórmulas. Tenía curiosidad sobre el error introducido por la aproximación, así que hice este gráfico que compara ambas fórmulas: desmos.com/calculator/cvaqofyvbf . Sin embargo, prefiero la respuesta de PaulHK ya que es más fácil de entender.
wip
1
Menuda objeción, si m> = 2n, entonces necesita cambiar su ecuación de "aproximación". Un ejemplo extremo es si n = 1, entonces necesita repetir la cadena 8 veces (es decir, realizar log2 (8) = 3 pasos). Por supuesto, si rellena con "10 ... 0" en lugar de todos ceros, entonces, en promedio, tendrá un error menor, pero perderá los extremos. "Sin embargo, prefiero la respuesta de PaulHK" :-) Bueno, no hay explicación para el sabor 8P.
Simon F