Бенчмарк
Как HazeHash соотносится с BlurHash и ThumbHash и почему он устроен именно так. Все числа получены скриптами из папки bench/ репозитория и воспроизводятся локально:
node scripts/fetch-test-images.mjs # однократно: набор из 513 изображений в test-images/
pnpm bench # report.html, results.csv, summary.csv в bench/out/
pnpm ablate # таблица абляции в bench/out/ablation.md
pnpm --filter hazehash-bench perf # замеры времениМетодика
- Набор — 513 изображений (фото, портреты, архитектура, товары, скриншоты, графика, 91 с прозрачностью, еда, документы, ночные сцены, панорамы), не больше 1280 px по длинной стороне.
- Эталон — исходное изображение, усреднённое по площади в линейном свете до размера вывода декодера. Изображения с альфой оцениваются на белом и на чёрном фоне, а ошибки усредняются.
- Ошибка — ΔE это 100 × евклидово расстояние в OKLab на пиксель. Оценка изображения это среднее по его пикселям, а в таблицах приводится среднее по изображениям. SSIM считается по каналу L в OKLab с окном 7×7.
- Базовые линии при том же числе байт — BlurHash берёт самую большую сетку, строка которой несёт не больше бюджета по информации (длина × log₂ 83 / 8), и видит изображение, сплющенное на белый. ThumbHash использует собственный выход, около 21 байта на этом наборе.
Результаты
Профиль default. Чем меньше ΔE, тем лучше, чем больше SSIM, тем лучше.
| Кодек | Бюджет | Медиана байт | Средняя ΔE | SSIM(L) |
|---|---|---|---|---|
| HazeHash | 16 | 16 | 8.41 | 0.495 |
| HazeHash | 20 | 20 | 7.89 | 0.549 |
| HazeHash | 24 | 24 | 7.54 | 0.588 |
| HazeHash | 28 | 28 | 7.29 | 0.614 |
| HazeHash | 36 | 36 | 7.00 | 0.644 |
| HazeHash | 48 | 43 | 6.91 | 0.651 |
| BlurHash | 16 | 16 | 15.78 | 0.243 |
| BlurHash | 28 | 28 | 14.32 | 0.335 |
| BlurHash | 48 | 48 | 13.62 | 0.405 |
| ThumbHash | native | 21 | 9.13 | 0.449 |
При 28 байтах средняя ΔE у HazeHash на 49,1% ниже, чем у BlurHash, и на 20,2% ниже, чем у ThumbHash. 95-й процентиль по изображениям равен 14,55 против 15,74 у ThumbHash, так что выигрыш не куплен ценой выбросов. Даже при 20 байтах, размере выхода ThumbHash, HazeHash лучше на 13,6%.
Бюджет по умолчанию
| Шаг | Изменение средней ΔE | Байт |
|---|---|---|
| 28 → 24 | +3.4% | −14% |
| 24 → 20 | +4.6% | −17% |
| 28 → 36 | −4.0% | +29% |
Значение по умолчанию в 28 байт (38 символов) сохраняет большой запас над ThumbHash и лежит между крутой частью кривой ниже 24 байт и пологой выше 36. Берите budget: 24, это 32 символа и всё ещё на 17% лучше ThumbHash, когда важнее хранилище.
Абляция
Каждая строка меняет один проектный выбор боевого энкодера, при помощи лабораторного кодека, базовая линия которого воспроизводит боевой бит в бит. 120 непрозрачных изображений, средняя ΔE и изменение относительно базовой линии.
| Вариант | ΔE при 20 Б | к базе | ΔE при 28 Б | к базе | ΔE при 36 Б | к базе |
|---|---|---|---|---|---|---|
| базовая линия (боевой энкодер) | 6.894 | 6.216 | 5.899 | |||
узкая маска, i/nx + j/ny < 1 | 6.889 | −0.1% | 6.445 | +3.7% | 6.422 | +8.9% |
| прямоугольная маска | 6.906 | +0.2% | 6.243 | +0.4% | 5.894 | −0.1% |
| полосы Qmax, зависящие от частоты | 6.838 | −0.8% | 6.219 | +0.0% | 5.939 | +0.7% |
| фиксированные 4 бита вместо Райса | 6.878 | −0.2% | 6.268 | +0.8% | 5.968 | +1.2% |
| без оптимизации «скорость–искажение» | 6.904 | +0.1% | 6.244 | +0.5% | 5.931 | +0.5% |
| одна общая сетка для L, a и b | 7.368 | +6.9% | 6.666 | +7.2% | 6.213 | +5.3% |
| гамма-sRGB (Y'CbCr) вместо OKLab | 7.031 | +2.0% | 6.358 | +2.3% | 6.030 | +2.2% |
Что это говорит:
- Отдельные сетки для яркости и цвета важнее всего: без них ошибка выше на 5–7%.
- OKLab даёт около 2% по сравнению с базисом Y'CbCr в гамма-кодировке.
- Маска важна при больших бюджетах. Исходный, более узкий треугольник стоит 3,7% при 28 байтах и 8,9% при 36 байтах, потому что поиск «скорость–искажение» может выбирать только среди коэффициентов, которые разрешает маска. Боевая маска сохраняет
i/nx + j/ny < 1.5, а полный прямоугольник ничего не добавляет, храня больше коэффициентов. - Кодирование Райса экономит около 1% по сравнению с фиксированным 4-битным кодом, а оптимизация «скорость–искажение» около 0,5%; обе достаточно дёшевы, чтобы их оставить.
- Квантование, зависящее от частоты, ничего не даёт (±1%), поэтому формат использует одно плоское значение на тип канала: 7 уровней для яркости и 3 для цвета и альфы.
Скорость
Примерное время для входа 64×48 на настольной машине, порядок величин, которого стоит ожидать. Скрипт perf из репозитория измерит их на вашем железе.
- Декодирование превью в 32 px занимает около 0,3 мс.
- Кодирование с
fastзанимает около 1 мс, сdefaultоколо 5 мс и сhighоколо 14 мс. Изображения с альфой медленнее, около 100 мс. Больший вход добавляет только время уменьшения по площади.