Por que replicar os bits mais altos do RGB565 ao converter para RGBA8888?


7

Vi em algumas bases de código de alguns softwares de computação gráfica que, às vezes, os bits mais altos dos dados de imagem no formato RGB565 são replicados nos bits mais baixos ao converter para o formato RGBA8888 de profundidade com bits mais altos.

Encontrei, por exemplo, o comentário do usuário "eq" neste tópico do gamedev.net :

Eu prefiro replicar os bits mais altos nos bits mais indefinidos:
R8 = (R5 << 3) | (R5 >> 2);

No entanto, eu não entendo a razão por trás.

Para que serve replicar esses bits nos dados convertidos?


11
Sem replicar os bits, os LSBs serão 0, portanto, para o valor máximo de 0x1f (máximo de 5 bits), ele seria expandido para 0xf8 quando convertido em 8 bits. O que você deseja é 0xff, então o intervalo de 0x00-> 0x1f será mapeado para 0x00-> 0xff em vez de 0x00-> 0xf8.
PaulHK 23/10

2
@PaulHK Por favor, poste isso como resposta. Está completo como está, mas, como comentário, não é pesquisável.
Dan Hulme

Sim, obrigado @PaulHK, isso responde corretamente minha pergunta #
wip #:

Respostas:


7

Sem replicar os bits, os LSBs serão 0, portanto, para o valor máximo de 0x1f (máximo de 5 bits), ele seria expandido para 0xf8 quando convertido em 8 bits. O que você deseja é 0xff, então o intervalo de 0x00-> 0x1f será mapeado para 0x00-> 0xff em vez de 0x00-> 0xf8. Sem mesclar o LSB, você não conseguiria converter 0x1f, 0x1f, 0x1f em branco (0xff, 0xff, 0xff). Aliás, isso é o mesmo 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)

7

Na verdade, existe uma razão matemática razoavelmente boa para fazer a replicação de bits:

Primeira nota que a cadeia n-bit, , na verdade, representa o valor de e queremos produzir a seqüência de m-bit, , onde e NN2n1Mn<m

N2n1M2m1

Escalamos primeiro o numerador e o denominador com e isso simplifica para

N.(2n+1)(2n1)(2n+1)M2m1
N.(2n+1)22n1M2m1

No seu caso, e e nós podemos "stop" aqui, mas mas o processo pode ser repetido, (ad nauseum), se m >> n.n{5,6}m=8

Em seguida, fazemos a aproximação ... que simplifica para

N.(2n+1)22nM2m
N.(2n+1)22nmM

Observe que é equivalente a repetir a sequência de n bits, para criar uma sequência de 2 bits e a divisão desliga os LSBs de para deixar um resultado em M bits.N.(2n+1)2nm

QED

Obviamente, o cálculo 'correto' é mas essa aproximação, em geral , funciona na maioria das vezes.É claro que há momentos em que é impreciso, mas o IIRC é apenas um pouco e relativamente pouco frequente.M=((2m1)N2n1+12


2
Obrigado por uma explicação detalhada com boas fórmulas. Como estava curioso sobre o erro introduzido pela aproximação, criei este gráfico que compara as duas fórmulas: desmos.com/calculator/cvaqofyvbf . No entanto, prefiro a resposta de PaulHK, pois é mais fácil de entender.
Wip

11
Quibble menor, se m> = 2n, então você precisa alterar sua equação de "aproximação". Um extremo, por exemplo, é se n = 1, é necessário repetir a sequência 8 vezes (por exemplo, execute log2 (8) = 3 etapas). Obviamente, se você pressionar "10 ... 0" em vez de todos os zeros, em média, ocorrerá um erro menor, mas perderá os extremos. "No entanto, prefiro a resposta de PaulHK" :-) Bem, não há explicação para o gosto 8P.
Simon F
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.