Mengapa mereplikasi bit RGB565 yang lebih tinggi ketika mengkonversi ke RGBA8888?

7

Saya telah melihat di beberapa basis kode perangkat lunak komputer grafis bahwa kadang-kadang bit yang lebih tinggi dari data gambar format RGB565 direplikasi menjadi bit yang lebih rendah ketika mengkonversi ke format yang lebih tinggi-bit-kedalaman RGBA8888.

Saya telah menemukan misalnya komentar oleh pengguna "eq" di utas gamedev.net ini :

Saya lebih suka mereplikasi bit yang lebih tinggi ke dalam bit yang lebih rendah yang tidak terdefinisi:
R8 = (R5 << 3) | (R5 >> 2);

Namun saya tidak mengerti alasan di baliknya.

Apa gunanya tujuan mereplikasi bit-bit itu ke dalam data yang dikonversi?

usap
sumber
1
Tanpa mereplikasi bit LSBs akan menjadi 0, jadi untuk nilai maksimum 0x1f (maks untuk 5 bit) itu akan diperluas ke 0xf8 ketika dikonversi menjadi 8 bit. Yang Anda inginkan adalah 0xff sehingga kisaran 0x00-> 0x1f akan dipetakan ke 0x00-> 0xff alih-alih 0x00-> 0xf8.
PaulHK
2
@ PaulHK Silakan posting itu sebagai jawaban. Lengkap seperti apa adanya, tetapi sebagai komentar tidak dapat dicari.
Dan Hulme
Ya, terima kasih @PaulHK, ini menjawab dengan benar pertanyaan saya
hapus

Jawaban:

7

Tanpa mereplikasi bit LSBs akan menjadi 0, jadi untuk nilai maksimum 0x1f (maks untuk 5 bit) itu akan diperluas ke 0xf8 ketika dikonversi menjadi 8 bit. Yang Anda inginkan adalah 0xff sehingga kisaran 0x00-> 0x1f akan dipetakan ke 0x00-> 0xff alih-alih 0x00-> 0xf8. Tanpa menggabungkan LSB Anda tidak akan dapat mengkonversi 0x1f, 0x1f, 0x1f menjadi putih (0xff, 0xff, 0xff). Kebetulan ini sama dengan 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
sumber
7

Sebenarnya ada alasan matematika yang cukup baik untuk melakukan replikasi bit:

Catatan pertama bahwa string n-bit, N, sebenarnya mewakili nilai N2n-1 dan kami ingin menghasilkan string m-bit, M.dimana n<m dan

N2n-1M.2m-1

Kami pertama-tama skala pembilang dan penyebut dengan

N.(2n+1)(2n-1)(2n+1)M.2m-1
dan ini disederhanakan menjadi
N.(2n+1)22n-1M.2m-1

Dalam kasus anda, n{5,6} dan m=8 dan kita bisa "berhenti" di sini, tetapi prosesnya dapat diulangi (ad nauseum), jika m >> n.

Kami selanjutnya membuat perkiraan ...

N.(2n+1)22nM.2m
yang disederhanakan menjadi
N.(2n+1)22n-mM.

Catat itu N.(2n+1) sama dengan mengulangi string n-bit, untuk membuat string 2n-bit, dan divisi bergeser dari 2n-m LSB meninggalkan hasil bit M.

QED

Tentu saja, perhitungan yang 'benar' adalah M.=((2m-1)N2n-1+12tetapi perkiraan ini, secara umum, bekerja sebagian besar waktu. Tentu saja ada kalanya tidak akurat, tetapi IIRC hanya sedikit demi sedikit dan relatif jarang.

Simon F
sumber
2
Terima kasih atas penjelasan terperinci dengan formula yang bagus. Saya ingin tahu tentang kesalahan yang diperkenalkan oleh aproksimasi jadi saya membuat grafik ini yang membandingkan kedua formula: desmos.com/calculator/cvaqofyvbf . Namun saya lebih suka jawaban PaulHK karena lebih mudah dimengerti.
usap
1
Minor quibble, jika m> = 2n maka Anda perlu mengubah persamaan "aproksimasi" Anda. Contoh ekstrem, adalah jika n = 1, maka Anda perlu mengulangi string 8 kali (yaitu melakukan log2 (8) = 3 langkah). Tentu saja, jika Anda pad dengan "10 ... 0" bukan semua nol, maka rata-rata Anda akan memiliki kesalahan yang lebih rendah, tetapi kehilangan ekstrem. "Namun saya lebih suka jawaban PaulHK" :-) Yah, tidak ada akuntansi untuk rasa 8P.
Simon F