Perché replicare i bit più alti di RGB565 durante la conversione in RGBA8888?


7

Ho visto in alcune basi di codice di alcuni software di computer grafica che a volte i bit più alti di dati di immagine in formato RGB565 vengono replicati nei bit più bassi durante la conversione in formato RGBA8888 con profondità di bit superiore.

Ho trovato ad esempio il commento dell'utente "eq" in questo thread di gamedev.net :

Preferisco replicare i bit più alti nei bit inferiori non definiti:
R8 = (R5 << 3) | (R5 >> 2);

Tuttavia non capisco il motivo dietro.

A che cosa serve replicare quei bit nei dati convertiti?


1
Senza replicare i bit gli LSB saranno 0, quindi per il valore massimo di 0x1f (massimo per 5 bit) si espanderebbe a 0xf8 quando convertito in 8 bit. Quello che vuoi è 0xff, quindi l'intervallo di 0x00-> 0x1f sarà mappato su 0x00-> 0xff invece di 0x00-> 0xf8.
PaulHK,

2
@PaulHK Ti preghiamo di pubblicarlo come risposta. È completo così com'è, ma come commento non è ricercabile.
Dan Hulme

Sì, grazie @PaulHK, questo risponde correttamente alla mia domanda
cancella il

Risposte:


7

Senza replicare i bit gli LSB saranno 0, quindi per il valore massimo di 0x1f (massimo per 5 bit) si espanderebbe a 0xf8 quando convertito in 8 bit. Quello che vuoi è 0xff, quindi l'intervallo di 0x00-> 0x1f sarà mappato su 0x00-> 0xff invece di 0x00-> 0xf8. Senza unire l'LSB non sarebbe possibile convertire 0x1f, 0x1f, 0x1f in bianco (0xff, 0xff, 0xff). Per inciso, questo è uguale a 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

In realtà c'è una ragione matematica ragionevolmente buona per eseguire la replicazione dei bit:

Prima nota che la stringa n-bit, , rappresenta in realtà il valore e vogliamo produrre la stringa m-bit, , dove e NN2n1Mn<m

N2n1M2m1

Per prima cosa scaliamo numeratore e denominatore con e questo semplifica a

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

Nel tuo caso, e e possiamo "fermarci" qui, ma ma il processo può essere ripetuto, (fino alla nausea), se m >> n.n{5,6}m=8

Facciamo quindi l'approssimazione ... che semplifica a

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

Si noti che equivale a ripetere la stringa n-bit, per creare una stringa 2n-bit e la divisione sposta gli LSB per lasciare un risultato M bit.N.(2n+1)2nm

QED

Naturalmente, il calcolo 'corretto' è ma questa approssimazione, in generale , funziona la maggior parte delle volte. Naturalmente ci sono momenti in cui è impreciso, ma IIRC solo di un bit e relativamente di rado.M=((2m1)N2n1+12


2
Grazie per una spiegazione dettagliata con belle formule. Ero curioso dell'errore introdotto dall'approssimazione, quindi ho creato questo grafico che confronta entrambe le formule: desmos.com/calculator/cvaqofyvbf . Comunque preferisco la risposta di PaulHK poiché è più facile da capire.
pulire il

1
Minimo cavillo, se m> = 2n allora devi cambiare l'equazione di "approssimazione". Un esempio estremo è se n = 1, quindi è necessario ripetere la stringa 8 volte (ovvero eseguire log2 (8) = 3 passaggi). Naturalmente, se si pad con "10 ... 0" anziché tutti gli zeri, in media si avrà un errore inferiore, ma si perderanno gli estremi. "Comunque preferisco la risposta di PaulHK" :-) Beh, non esiste una spiegazione per il gusto 8P.
Simon F,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.