Files
vphash/docs/ARTICLE.ru.md
T
2026-06-07 00:22:19 +03:00

16 KiB

Алгоритм цифрового видео отпечатка VPHash

Всем привет!

В этой статье я расскажу про легковесный и открытый аналог YouTube ContentID - как получить устойчивый к изменениям цифровой отпечаток видео на основе массива перцептивных хэшей с помощью алгоритма, имеющего сложность O(log n).

Даже на многочасовых файлах алгоритм работает молниеносно - многократно быстрее существующих аналогов на основе нейросетей, без особых требований к железу. Вполне может выступать в качетсве первого этапа в пайплайне создания "цифрового отпечатка". Может работать как на клиенте (например, WASM), так и на сервере.

Сценарии использования:

  1. Сравнение загружаемых видео для установления оригинальности
  2. Поиск ретрансляций оригинального видео в режиме реального времени
  3. Автоматическое разбиение видео на сцены
  4. Выявление наличия/подсчет количества заимствованных сцен

⚠️⚠️⚠️ Дисклеймер: я придумал не просто конкретную реализацию на каком-то языке программирования, а непосредственно сам алгоритм. Поэтому убедительная просьба:

  • При использовании в проектах с открытыми исходниками - указать моё имя, оставить ссылку на одну из моих статей и github-аккаунт в пул реквесте/ридми
  • При использовании в закрытых проектах - выкатить мне жирный оффер (Шутка. Просто закажите пиццу)

Введение

Обычные алгоритмы вроде взятия хэша абсолютно не подходят для создания цифровых отпечатков у контента, потому что их крайне просто обойти. Достаточно изменить 1 бит - получаешь новый хеш, установить факт сходства - невозможно. Более того, для видео до появления этого алгоритма - было не совсем понятно, а что вообще должно быть результатом работы алгоритма - результирующая структура данных сама была вопросом.

БигТехи вроде гугла используют для данных целей целый ансамбль технологий, которые включают нейросетевые движки, тяжелую статистику, покадровый анализ, в общем полный тумач - долго, медленно, дорого и не портируемо.

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

Перцептивный хэш, расстояние Хэмминга и бинарный поиск

Для понимания принципа работы алгоритма необходимо понимать 3 концепции: перцептивный хеш, расстояние хэмминга и бинарный поиск. Подсвечу основные моменты.

  1. Перцептивный хэш (pHash) не смотрит на точные значения пикселей, а описывает общую структуру изображения: где светлые области, где тёмные, как проходят границы объектов и текстур. За счёт этого он устойчив к цветокоррекции, водяным знакам, ресайзу и пережатию - кадр визуально тот же - хэш очень похожий.

  2. Расстояние Хэмминга - это простой способ измерить «насколько сильно» различаются два таких хэша. Поскольку pHash это битовая строка (вектор), мы просто считаем количество битов, которые не совпадают. Два почти одинаковых кадра дадут расстояние, близкое к нулю.

  3. Бинарный поиск - это алгоритм, который находит нужную точку в отсортированном массиве, на каждом шаге сокращая область поиска вдвое.

Принцип разделения видео на чанки

Ядро алгоритма - адаптация бинарного поиска под задачу видео-сегментации. Вместо линейного прохода по каждому кадру мы работаем с чанками: берём начальный и конечный кадр, вычисляем их перцептивные хэши и считаем расстояние Хэмминга между ними. Если расстояние мало - весь чанк признаётся одной сценой и дальше не дробится. Если велико - делим чанк пополам и рекурсивно проверяем каждую половину. Так мы получаем логарифмическую сложность O(log n) вместо линейной O(n).

Ключевой механизм детекции основан на природе перцептивного хэша. Пока кадры принадлежат одной сцене, их pHash остаётся стабильным, а расстояние Хэмминга колеблется в узком диапазоне. Но как только происходит монтажная склейка - освещение, композиция и текстуры меняются разом, и pHash совершает резкий скачок. Именно этот скачок служит триггером: алгоритм фиксирует границу сцены и запускает процедуру уточнения, чтобы найти точный кадр перехода.

Рекурсивное дробление продолжается до одного из двух исходов. Либо расстояние Хэмминга падает ниже порога, и чанк признаётся однородной сценой. Либо мы упираемся в конечный фрейм атомарного размера, который и является точной границей перехода на следующую сцену. Сложность остаётся логарифмической.

Для наглядности добавлю небольшую визуализацию с примером.

|------.....|...........|
A           M           B

Промежуток выше - это видеоряд. A - первый кадр, B - последний кадр, M - середина. Область с тире - первая сцена. Область с точками - вторая сцена. Алгоритм будет работать следующим образом: взять перцептивный хеш A и B -> расстояние Хэмминга большое, берем середину - M, берем перцептивный хэш -> расстояние с B маленькое - это одна сцена, расстояние с A большое - повторяем алгоритм на новом промежутке.

Отпечатки сцены

Основная ошибка предшественников моего алгоритма - использования неправильной результирующей структуры данных. Ближайший аналог - videohash делит видео на секундные чанки, складывает изображения из каждого чанка вместе и берет pHash. Итог - если взять половину видео или какую-то сцену то всё моментально ломается, другой хэш, практически неприменимая история.

Что бы избежать данных проблем - не нужно пытаться привести результат к хэшу фиксированной длинны, результат вполне может быть массивом метаданных принадлежащих атомарным неделимым частям видео - конкретным сценам.

Есть много опций как можно взять отпечаток конкретной сцены, как вариант - как раз применить механику описанну в videohash или взять несколько отпечатков у разных кадров, но для простоты самого алгоритма я буду использовать средний кадр и его перцептивный хэш - для большинства сценариев этого более чем достаточно. Копирование сцены из одного видео в другое - приведет или к полному копированию данного вектора, или его незначительному искажению при условии модификации видео фрагмента.

Интерпретация результатов

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

  1. Точные тайм коды начала и конца всех сцен в видео
  2. Продолжительность сцен - атомарных видео сегментов
  3. Перцептивные хэши для всех сцен из видео

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

Перцептивные хэши мы складываем в векторную базу - и проводим к каждому из них ассоциацию на длинну сцены и оригинальное видео. Коллизии минимальны, но их существование не критично - тк факт наличия дубликата можно установить по нескольким сценам для гарантий точности.

Потоковая обработка

Алгоритм естественным образом адаптируется под потоковое видео. Вместо анализа всего файла целиком мы накапливаем кадры в скользящий буфер фиксированной длительности (например, 10 секунд). Как только буфер заполнен — запускаем бинарный поиск сцен и получаем хэши для этого фрагмента. Следующий буфер начинается не с нуля, а с середины предыдущего — это гарантирует, что граница сцены, попавшая на стык двух буферов, не будет потеряна. Сложность обработки одного буфера — O(log n), поэтому даже на CPU анализ укладывается в доли секунды и не отстаёт от реального времени, без использования параллелизма. Результат сравнивается с базой эталонных хэшей, и при превышении порога совпадения система мгновенно фиксирует факт ретрансляции. Можно запускать на клиенте при компиляции в WASM (отправка перцептивных хэшей и границ сцен в real-time с клиента).

Заключение

Алгоритм опубликован под лицензией GPLv3, все его последующие версии (при учете использования бинарного деления в видео-сегментах и предствалении видео как упорядоченного массива) должны находиться в публичном доступе для возможности унифицированного использования.

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

Fun-Fact, я несколько раз просил даже самые крутые модели (Opus/GPT/Gemini) написать реализацию потоковой обработки на go, но в качестве результата получал просто жуткий мусор - неправльные структуры данных, бесконечные ошибки, отсутствие структуры. Наверное, это связано с тем, что реализации еще нет ни в одном источнике - алгоритм слишком самобытен, что ломает наши чудо-генераторы токенов, они не способны сгенерировать то, чего еще нет в природе.


Поддержка:

BTC: bc1qf0hftkqfmq2vlpppgla5ser9hssgphkv9e8knc
TON: UQAgCErQ-lU3QGUJOsncO_U96CpeDTiz03bYew0afu-Np6XL
USDT-TRC20: TSVa5K1PP3zaBJxCxQHhtPbJdRNVEdjBs7
ETH: 0x1EeFaD9DF89f042D748451391b05adb65c26F20F

Контакты:

Mail:      d1nch8g@gmail.com
Telegram:  @d1nch8g

Репозиторий:

Github:  https://m8sh.su/x/vphash