TL; DR: 2 * 1LSB. Треугольные-pdf разрывы дизеринга в краевых корпусах при 0 и 1 из-за зажима. Решение состоит в том, чтобы перейти к 1-битному равномерному колебанию в этих случаях.
Я добавляю второй ответ, видя, что это оказалось немного сложнее, чем я первоначально думал. Похоже, что эта проблема была "TODO: нужно зажимать?" в моем коде с тех пор, как я перешел с нормализованного на треугольное сглаживание ... в 2012 году. Приятно наконец посмотреть на него :) Полный код для решения / изображений, использованных в этом посте: https://www.shadertoy.com/view/llXfzS
Прежде всего, вот проблема, которую мы рассматриваем при квантовании сигнала на 3 бита с дизерингом 2 * 1LSB triangular-pdf:
- По сути, что показали hotmultimedia.
При увеличении контраста эффект, описанный в вопросе, становится очевидным: выходной сигнал не усредняется по черно-белому в краевых корпусах (и на самом деле перед этим он значительно превышает 0/1).
Глядя на график, вы получите немного больше информации:
(серые линии обозначают 0/1, также серым цветом обозначен сигнал, который мы пытаемся вывести, желтая линия - среднее значение сглаженного / квантованного выхода, красная - ошибка (среднее значение сигнала)).
Интересно, что не только средний выходной сигнал не равен 0/1 на границах, он также не является линейным (вероятно, из-за треугольного pdf шума). Глядя на нижний предел, становится понятным, почему выходной сигнал расходится: поскольку сигнал со сглаживанием начинает включать отрицательные значения, фиксация на выходе изменяет значение нижних сглаженных участков вывода (то есть отрицательных значений), тем самым увеличивая значение среднего. Иллюстрация выглядит по порядку (равномерное, симметричное смещение 2LSB, среднее значение все еще в желтом цвете):
Теперь, если мы просто используем нормализованный дизеринг 1LSB, в краях-случаях вообще нет проблем, но тогда, конечно, мы теряем хорошие свойства треугольного дизеринга (см., Например, эту презентацию ).
Таким образом, (прагматичное, эмпирическое) решение (хак) должно вернуться к [-0,5; 0,5 [равномерное сглаживание для граничного случая:
float dithertri = (rnd.x + rnd.y - 1.0); //note: symmetric, triangular dither, [-1;1[
float dithernorm = rnd.x - 0.5; //note: symmetric, uniform dither [-0.5;0.5[
float sizt_lo = clamp( v/(0.5/7.0), 0.0, 1.0 );
float sizt_hi = 1.0 - clamp( (v-6.5/7.0)/(1.0-6.5/7.0), 0.0, 1.0 );
dither = lerp( dithernorm, dithertri, min(sizt_lo, sizt_hi) );
Который фиксирует кромки, сохраняя треугольное сглаживание без изменений для оставшегося диапазона:
Поэтому, чтобы не отвечать на ваш вопрос: я не знаю, существует ли более математически надежное решение, и в равной степени стремлюсь узнать, что сделали Мастера прошлого :) До тех пор, по крайней мере, у нас был этот ужасный хак, чтобы поддерживать наш код в работе.
РЕДАКТИРОВАТЬ
Я, вероятно, должен охватить предложение обхода, данное в Вопросе, о простом сжатии сигнала. Поскольку среднее значение не является линейным в крайних случаях, простое сжатие входного сигнала не дает идеального результата - хотя оно фиксирует конечные точки:
Ссылки