Зачем реплицировать старшие биты RGB565 при конвертации в RGBA8888?

7

В некоторых базах кода программного обеспечения компьютерной графики я видел, что иногда старшие биты данных изображения в формате RGB565 реплицируются в младшие биты при преобразовании в формат RGBA8888 с большей глубиной бит.

Например, я нашел комментарий пользователя "eq" в этой теме на gamedev.net :

Я предпочитаю копировать старшие биты в неопределенные младшие биты:
R8 = (R5 << 3) | (R5 >> 2);

Однако я не понимаю причину этого.

Какая польза от репликации этих битов в преобразованные данные?

WIP
источник
1
Без репликации битов младшие биты будут равны 0, поэтому при максимальном значении 0x1f (максимум для 5 бит) он расширится до 0xf8 при преобразовании в 8 бит. То, что вы хотите, это 0xff, поэтому диапазон 0x00-> 0x1f будет отображаться в 0x00-> 0xff вместо 0x00-> 0xf8.
PaulHK
2
@PaulHK Пожалуйста, опубликуйте это как ответ. Он завершен, но в качестве комментария он не доступен для поиска.
Дэн Халм
Да, спасибо @PaulHK, это правильно отвечает на мой вопрос
стереть

Ответы:

7

Без репликации битов младшие биты будут равны 0, поэтому при максимальном значении 0x1f (максимум для 5 бит) он расширится до 0xf8 при преобразовании в 8 бит. То, что вы хотите, это 0xff, поэтому диапазон 0x00-> 0x1f будет отображаться в 0x00-> 0xff вместо 0x00-> 0xf8. Без объединения LSB вы не сможете конвертировать 0x1f, 0x1f, 0x1f в белый (0xff, 0xff, 0xff). Кстати, это то же самое, что и 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
источник
7

На самом деле есть достаточно веская математическая причина для выполнения битовой репликации:

Сначала обратите внимание, что n-битная строка, Nна самом деле представляет ценность N2N-1 и мы хотим получить m-битную строку, M, где N<м а также

N2N-1M2м-1

Мы сначала масштабируем числитель и знаменатель с

N,(2N+1)(2N-1)(2N+1)M2м-1
и это упрощает
N,(2N+1)22N-1M2м-1

В твоем случае, N{5,6} а также мзнак равно8 и мы можем «остановиться» здесь, но процесс можно повторить (до тошноты), если m >> n.

Затем мы сделаем приближение ...

N,(2N+1)22NM2м
что упрощает
N,(2N+1)22N-мM

Обратите внимание, что N,(2N+1) эквивалентно повторению n-битной строки для создания 2n-битной строки, и деление сдвигается 2N-м МЗБ, чтобы оставить результат M бит.

QED

Конечно, «правильный» расчет Mзнак равно((2м-1)N2N-1+12но это приближение, как правило, работает большую часть времени. Конечно, бывают случаи, когда это неточно, но IIRC только на один бит и относительно редко.

Саймон Ф
источник
2
Спасибо за подробное объяснение с красивыми формулами. Мне было любопытно, какую ошибку внесла аппроксимация, поэтому я создал график, который сравнивает обе формулы: desmos.com/calculator/cvaqofyvbf . Однако я предпочитаю ответ PaulHK, так как его легче понять.
протрите
1
Незначительный спор, если m> = 2n, вам нужно изменить уравнение «приближения». Например, если n = 1, вам нужно повторить строку 8 раз (т.е. выполнить log2 (8) = 3 шага). Конечно, если вы добавите «10 ... 0» вместо всех нулей, то в среднем вы будете иметь меньшую ошибку, но потеряете крайности. «Однако я предпочитаю ответ PaulHK» :-) Ну, нет никакого вкуса 8P.
Саймон Ф