Skip to content

Бенчмарк ​

Как HazeHash соотносится с BlurHash и ThumbHash и почему он устроен именно так. Все числа получены скриптами из папки bench/ репозитория и воспроизводятся локально:

bash
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, тем лучше.

КодекБюджетМедиана байтСредняя ΔESSIM(L)
HazeHash16168.410.495
HazeHash20207.890.549
HazeHash24247.540.588
HazeHash28287.290.614
HazeHash36367.000.644
HazeHash48436.910.651
BlurHash161615.780.243
BlurHash282814.320.335
BlurHash484813.620.405
ThumbHashnative219.130.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.8946.2165.899
узкая маска, i/nx + j/ny < 16.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 и b7.368+6.9%6.666+7.2%6.213+5.3%
гамма-sRGB (Y'CbCr) вместо OKLab7.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 мс. Больший вход добавляет только время уменьшения по площади.