[алгоритм] Сравнение видео

viktor954

Пишу поиск дубликатов файлов для QNAP. Если с text/binary всё более или менее просто (размер посмотрел, хэш посчитал и всё то чуточку сложнее с музыкой. Хотя тоже в некотором приближении решаемое - существует куча классов, которые могут вытягивать информацию из заголовков и тегов всевозможных форматов. Тоже есть, что сравнивать.
А вот с видео...
На что я замахнулся - сравнение видео по контенту. Так, чтобы даже видео разных пропорций, разного качества (CAMRip vs DVDRip) более-менее нормально сопоставлялось.
Пока придумал только вот так:
Полный "рендеринг" видео. Ищем явные смены "сцены" - например, смену яркости картинки на 75%(от балды) от предыдущеей, которая длится 10 секунд (от балды) от предыдущей "сцены". Запоминаем время между сценами и как дополнительную информацию - относительную яркость(относительно "средней яркости видео") и/или тон сцены ("усреднённый тон по кадру").
Что сравниваем - первично сравниваем "цепочки длин сцен". По идее тут должен быть алгоритм, похожий на "расстояние Хемминга". Чем меньше "ошибка" тем больше похоже "последовательности сцен", тем больше похожи ролики. Потом при необходимости сравниваем для совпадающих по длительности сцен "тон" сцены. Даже если у роликов разная длительность и разное качество, то такой алгоритм должен дать достаточно хорошие результаты.
Явный минус алгоритма - ресурсоёмкость. С одной стороны - не страшно - оно будет потихоньку шуршать с низким приоритетом и особой нагрузки не создаст, с другой - на больших коллекциях это всё равно будут недели, месяцы и годы (если считать, что чтобы не нагружать проц хранилки надео рендерить самое быстрое 1:1, а в случае HD - 0,1:1, то даже без учёта остальной части алгоритма чисто на рендеринг уйдёт в среднем полтора часа, т.е. всего 16 фильмов в сутки)
Гугл с ходу алгоритмов, "замахивающихся" на такое соотнесение не дал.
Можете что-нибудь подсказать или посоветовать?

apl13

как дополнительную информацию - относительную яркость
Сразу уж дополнительно вейвлетизировать! :bud:

salamander

Несколько идей, не оформленных в алгоритм.
Смену сцен, вообще говоря, кодек уже нашел в процессе кодирования. Ключевые кадры будут часто попадать именно на смену сцен. Из этого получается:
1) у дубликатов будет довольно большое количество совпадающих (по времени) ключевых кадров
2) эти кадры можно легко декодировать не декодируя другие
3) их должно быть возможно достать с помощью libavcodec/libavformat (mplayer это как-то делает для перематывания)
Далее задача сводится к сравнению картинок на похожесть. Это должна быть более известная задача.
Тут, конечно, будет куча всяких интересных моментов. Кроме тривиального: "один кодек поставил ключевой кадр на это смене сцен, а другой нет" есть крайне реальная проблема, что одно видео может быть ускорено относительно другого. Преобразование 23.976fps (фильмы снимают в таком) в 25 fps (PAL DVD) чаще всего делают ускорением.

apl13

Ну обезразмерить надо относительно времени. Плохо, если при таком проеб... тьфу, преобразовании сместятся КК и сожмется их решетка.

viktor954

Замечания:
1)
(по времени)
у нас НЕТ времени. У нас есть отступы от начала. Пример - камрип, где пират начал снимать в самом конце титров и DVDRip, где титры полностью. В одном случае переход "сцена 0"(титры)-"сцена 1"(первые кадры фильма") придётся, например, на 0:0:7, а во втором случае - на 0:1:30. Зато длина "сцены 1" (т.е. дельта до перехода к "сцене 2") будет практически одинакова для обоих "источников"
2) Ты уже написал - в зависимости от кодека выбор I-фреймов может существенно отличаться. Вероято, что при "сильных" сменах сцен кодеки ведут себя одинаково и пишут I. Тогда, наверное, можно сравнивать текущий I с предыдущими и если он не сильно поменялся ПО НАШИМ меркам - считать, что сцена продолжается.
3) сравнивать картинки - тоже ресурсоёмко. Этого хотелось бы по-максимуму избежать.
При сравнении "цепочки длительности сцен" проблемы с разным фреймрейтом отпадают, потому что мы находимся во "времени зрителя", т.е. у нас время реальное.

viktor954

Почти готовое решение для дампа КК:
http://lists.mplayerhq.hu/pipermail/mplayer-users/2006-May/0...
"mplayer -vf framestep=I some_video.ogg -vo jpeg:outdir=/tmp'"
но "плохие" имена файлов - просто сквозная нумерация. Вот если бы это было ВРЕМЯ...
похоже есть аналогичное решение и для ffmpeg
http://planetcakephp.org/aggregator/items/3401-ffmpeg-multip...
но, похоже проблема с именованием файлов остаётся.

salamander

3) сравнивать картинки - тоже ресурсоёмко. Этого хотелось бы по-максимуму избежать.
Смотря сколько сравнений придется делать. В твоем первоначальном варианте алгоритма нужно декодировать все кадры и потом еще считать яркость. В двухчасовом фильме их порядка 172 тысяч.
2) Ты уже написал - в зависимости от кодека выбор I-фреймов может существенно отличаться. Вероято, что при "сильных" сменах сцен кодеки ведут себя одинаково и пишут I. Тогда, наверное, можно сравнивать текущий I с предыдущими и если он не сильно поменялся ПО НАШИМ меркам - считать, что сцена продолжается.
Если таким образом удастся найти несколько очень "сильных" смен сцен, то по ним можно искать возможное начальное смещение и/или ускорение, а дальше найти несколько совпадающих КК и сравнить в них картинки.
Но все это эвристики. Эвристики в теории всегда хорошо работают, а вот на практике... Вобщем, без экспериментов это все умозрительные рассуждения, не более.
При сравнении "цепочки длительности сцен" проблемы с разным фреймрейтом отпадают, потому что мы находимся во "времени зрителя", т.е. у нас время реальное.
Не, фильм реально ускоряют. То есть двухчасовой фильм при записи на PAL DVD станет на пять минут "короче", зато кадров в нем останется столько же.
PS: придумал тут два интересных юзкейза:
1) одна и та же серия какого-нибудь сериала записанная с разных телеканалов; в одной из записей есть реклама посередине (не вырезали по какой-то причине);
2) есть обычная версия фильма и "Directors cut".

viktor954

По юзкейсам:
1) Вот тут-то на помощь придёт "расстояние Хемминга"
2) Тут уже хуже - ошибка будет существено больше, хотя по идее, если учитывать вставку любого числа сцен как один "токен", то вставка пары-тройки сцен в фильм всё равно оставит цепочки "неделёкими".
С разным фреймрейтом - да, понятно - надо учитывать время начала сцен с некоторой возможной погрешностью.
В целом - да, надо писать и смотреть, что получится.
Спасибо.

kiracher

На что я замахнулся - сравнение видео по контенту. Так, чтобы даже видео разных пропорций, разного качества (CAMRip vs DVDRip) более-менее нормально сопоставлялось.
а зачем тебе сравнивать по видео ? сравнивай по аудио треку, он то наверняка всегда есть и тоже уникален.
берешь кусками аудио, переводишь в общий формат (частота да битность пониже - например 10 кгц 8 бит) и вычисляешь корреляцию между эталонным куском и текущим.

viktor954

Несколько аудиодорожек/разная озвучка?
Авторское кино без звука?
Ролики со всяких тьюбов без звука?

5777

Насколько я знаю, чем-то очень похожим занимались на ВМК, в лабе графики и мультимедиа. Попробуй с ними связться.

alexkravchuk

Полный "рендеринг" видео. Ищем явные смены "сцены" - например, смену яркости картинки на 75%(от балды) от предыдущеей, которая длится 10 секунд (от балды) от предыдущей "сцены". Запоминаем время между сценами и как дополнительную информацию - относительную яркость(относительно "средней яркости видео") и/или тон сцены ("усреднённый тон по кадру").
В принципе, всё это реализовано в AviSynth (фреймсервер).
В том числе, эта система поддерживает фильтры, которые и просто высчитывают яркости/тона кадров (в YUV, не уверен насчёт HSV, надо смотреть и даже поддерживают подобные фильтры для смен кадров, то есть разницу между кадрами можно анализировать.
В общем, советую глянуть, или саму систему, или идеи, как это реализовано (и система, и обычно плагины доступны в исходниках). Я думаю, можно именно самой системой обойтись.
Система очень мощная, хотя глюкодром тот ещё.

karkar

Кстати, если искать смены сцен по содержимому, советую сравнивать не яркость, а цвет (в терминах YUV - не Y, а UV и не среднее значение, а гистограмму.
С ключевыми кадрами идея интересная, но может оказаться, что ряд кодеков на длинных сценах просто ставят ключевики каждые N кадров, может возникнуть ложное впечатление, что там сцены совпадают.

viktor954

Не-не-не-не-не! Всё нормально! Мы же ЗНАЕМ ВРЕМЯ этого КК! Смотри (I - КК, индекс - сцена(сильное изменение UV время - timestamp КК):
Кодек1: I1(0:0:0)-I1(0:0:7)-I2(0:0:9)-I2(0:0:20)-I2(0:0:27)-I3(0:0:40)
Кодек2: I1(0:0:0)-I1(0:0:2)-I1(0:0:4)-I1(0:0:6)-I1(0:0:8)-I2(0:0:9)-I2(0:0:11)-I2(0:0:13)-I2(0:0:15)-I2(0:0:17)-...-I2(0:0:27)-...-I3(0:0:40)
Сцена2 как начиналась в 0:0:9 так и начинается.

karkar

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

viktor954

Абсолютные времена
См.самый первый пост. Я об этом изначально писал, да, мы живём в "пространстве дельт между сценами". Тут я время привёл абсолютное, чтобы было нагляднее.
алгоритмы нечеткого сравнения строк

Блин! Уже не смешно. Смотри отсылку к расстоянию Хемминга.
связываться с ключевыми кадрами

См. выше - выдрать ключевые кадры существенно быстрее, чем отрендерить ВСЁ видео. И это должен быть очень странный алгоритм кодека, чтобы при кодировании КК не попал на нужную нам "сильную смену кадра". Значит можно попробовать пользоваться именно КК.

barbos

Блин! Уже не смешно. Смотри отсылку к расстоянию Хемминга.
А можешь подробнее пояснить применение расстояния Хемминга в данном случае?

viktor954

?! Один из самых простых алгоритмов нечёткого сравнения. Почему бы его не применить тут?
Пусть у нас есть две последовательности дельт (в секундах)
7,4000,56237,731948203
73,4000,56237,731948203
расстояние = 1
Смотреть надо. Если на практике дельты будут сильно прыгать (пока я надеюсь, что округление длительности сцены до секунд даст нужный результат) — найти алгоритм ещё более нечёткого сравнения, чтобы
7,4000,56237,731948203
73,4010,56137,731948000
он считал "похожими на 555 условных единиц".

barbos

Пусть ты получил две последовательности времен ключевых кадров (разности t_{KK} - t_{начало}) одинаковой длины, потом обнаружил, что между ними расстояние Хемминга 5. Что хорошего дает такой результат?

viktor954

0) Не "t_{KK} - t_{начало}", а "t_{НАЧАЛО_СЦЕНЫn} - t_{НАЧАЛО_СЦЕНЫn-1}"
1) Из (0) следует, что два видео отличаются в длительности 5 сцен, что при общем числе сцен (условно) 250 составляет 2%,что "достаточно мало" (написано от балды - реально надо будет смотреть результаты, которые алгоритм будет давать на практике) и поэтому мы считаем видео одинаковыми.

barbos

Я туплю, и кажется, что это уже объяснено выше, но, алгоритм выглядит так:
1. Для каждого файла:
1.1. В видеопоследовательности находим абсолютные времена "смены сцен";
1.2. Получаем последовательность длительностей сцен;
2. Сравниваем две последовательности расстоянием Хемминга или чем-то похожим. Если расстояние мало — видеопоследовательности считаем "одинаковыми"
?
Если это так, то вставка сцены с рекламой сдвигает одну последовательность относительно другой и в итоге можно легко получить максимальное расстояние Хемминга. В связи с этим, похоже, полезнее считать наибольшую общую подпоследовательность, чем расстояние Хемминга.

karkar

 
См.самый первый пост. Я об этом изначально писал, да, мы живём в "пространстве дельт между сценами". Тут я время привёл абсолютное, чтобы было нагляднее.

Тогда что значит твое ЗНАЕМ ВРЕМЯ! ?
 
Смотри отсылку к расстоянию Хемминга.

Да видел я. Это очень плохая метрика, для строк (и данной задачи) гораздо лучше есть алгоритмы. Или ты имел в виду расстояние Левенштейна все же?
 
См. выше - выдрать ключевые кадры существенно быстрее, чем отрендерить ВСЁ видео. И это должен быть очень странный алгоритм кодека, чтобы при кодировании КК не попал на нужную нам "сильную смену кадра". Значит можно попробовать пользоваться именно КК.

Т.е. брать КК, сравнивать их UV и так отсеивать лишние? Ок, годится.

viktor954

Да, всё верно.
Я спорю, что ли? Хорошо, Хемминг в чистом виде не подходит, значит какой-нибудь Левенштейн или, как ты говоришь, искать наибольшую совпадающую цепочку.

viktor954

При генерации "дельта-цепочек" для каждого КК мы знаем его "абсолютное" время (грубо говоря _абсолютный_номер_кадра_/фреймрейт). По этим абсолютным временам после нахождения смены сцены мы будем вычислять дельты.
С Хеммингом уже разобрались. Спасибо. Буду думать. Тут и без алгоритма сравнения уже можно укодиться.
С отсеиванием КК - да, так.

alexkravchuk

КК — очень плохой критерий смены сцен. Все, или почти все кодеки имеют параметры вроде max_key_interval и min_key_interval. Максимальный интервал выставляют обычно вручную, все по-разному, из своих личных соображений. С минимальным хитрее, но скажем в x264 он есть по-умолчанию, по формуле от максимального вычисляется. Из-за этого KK может быть и без смены сцен, и на смене сцен не обязательно будет КК. Это реальность :)
Если брать общую, наиболее сложную задачу, вместе с обработкой экранок, то тут такие проблемы встают:
1) возможные небольшие вставки фрагментов
2) разные ролики могут быть сняты с разной яркостью, разная гамма может быть, особенно сильно могут цвета гулять (причём это актуально не только для экранок, но в экранках тут вообще полная попа)
наилучший инвариант, как мне кажется — это смена яркости, как абсолютные яркости, так и дельты между кадрами. Такое пройдёт даже через экранку.
Поэтому, я бы задачу разбил на следующие:
1) Обработать видео файлы и получить текстовые файлы вида "время:абсолютная яркость:разница между соседними кадрами". Такое, по идее, можно сделать с помощью AviSynth
2) полученные данные интерпретировать как просто некие функции от t, функции вещественные. После этого выбирать определённым образом фрагмент функции из первого фильма (по какому-нибудь критерию, начиная с явной смены кадра, например определённым образом нормировать, и сравнивать с фрагментами нормированных кусков из второго фильма (по метрикам из L2, скажем). После чего делать выводы.
В общем, нужно научиться решать задачу 1, после чего поиграться с 2. С 2 уже начинаются нетривиальные вещи, поэтому загадывать дальше смысла нет, сначала нужно поиграться, и посмотреть, как это на практике работает.
Ну, по крайней мере, я бы, наверное, по такому пути пошёл.

viktor954

Из-за этого KK может быть и без смены сцен

Это чуть выше обсуждалось — после получения всех КК мы по ним пробегаем и ищем смены сцен
возможные небольшие вставки фрагментов

обсуждалось - будем искать наибольшие повторяющиеся цепочки дельт
сняты с разной яркостью

первый пост - "относительную яркость(относительно "средней яркости видео""
это смена яркости

первый пост - "например, смену яркости картинки на 75%(от балды) от предыдущеей"
В общем, нужно научиться решать задачу 1, после чего поиграться с 2. С 2 уже начинаются нетривиальные вещи, поэтому загадывать дальше смысла нет, сначала нужно поиграться, и посмотреть, как это на практике работает.

чуть выше - "Тут и без алгоритма сравнения уже можно укодиться."
Спасибо!

alexkravchuk

основная идея, понятно, в том, что какая-то программа создаёт для каждого фильма функцию v=F(t и потом уже вторая программа сравнивает эти функции. При этом, как мне кажется, что лучше использовать не дискретные способы сравнения (всякие алгоритмы сравнения последовательностей а именно сравнения функций. Ну, примерно, как есть алгоритмы сравнения аудио, и тут аналогично.
Какая идея приходит в голову.
Создаём функцию, которая показывает, насколько меняется яркость кадра. Далее, рассматриваем особые точки, где яркость или начинает расти быстрее, чем на 10% в секунду, или, наоборот, падать (цифра от балды, но небольшая должна быть). Смотрим на расстояния между этими точками, и составляем таблицу с распределением таких расстояний, то есть, что-то вроде спектра строим. Потом сравниваем 2 распределения (для одного фильма, и для другого на основе чего и делаем выводы о похожести фильмов.
Плюсы: сравнение должно довольно быстро работать, алгоритм устойчив к помехам вроде коротких вставок (спектр поменяется незначительно можно строить много разных функций, увеличив качество поиска, можно делать адаптивное вычисление спектра (если в одном ролике найдено сильно больше особых точек, чем во втором, то можно изменить порог реагирования для одного из фильмов, тем самым ряд проблем с экранками решается).
Минусы, впрочем, тоже есть.

tokuchu

Распознавай текст, который встречается в кадрах и сравнивай его! :)

viktor954

Саш, тебя из гестапо за жестокость выгнали, по-моему....

peter1dav

ИМХО, мое предложение, искать объекты в кадре.. по типу как в "арументе" висел экранчик, который транслировал картинку с камеры наблюдения где пипл выделялся в рамочку =)
Сравнивать поведение таких вот рамочек :o
Или то ж гестапо? :ooo:
ЗЫ..я не в теме :cool:

viktor954

motion detection будет чертовски плохо работать, если согласно практически утверждённому плану система будет рендерить только КК.
Но травой поделись!

tokuchu

система будет рендерить только КК
Чтозанах? Поясни для тех кто в танке. :)

viktor954

КК - ключевые кадры.

tokuchu

КК - ключевые кадры.
А, тьфу. Я чего-то подумал, что у тебя будет видео только какое-то определённое. В смысле не сразу понял, что "система", которая будет рендерить — это та, что дубликаты ищет.

alexkravchuk

motion detection будет чертовски плохо работать, если согласно практически утверждённому плану система будет рендерить только КК
Короче, фигнёй ты страдаешь, если не сказать матернее, со своими КК. Ты какую вообще задачу в первую очередь хочешь решить? Всё и сразу? Забей, и научись сначала решать задачу сравнения видео, когда все кадры доступны. Анализ проще всего делать с помощью Avisynth. Вот такая программа (упрощённый вариант):

#v=AviSource("video_xvid.avi").KillAudio
v=DirectShowSource("video_x264.avi").KillAudio

function fff(frame_num, t_dy, t_du, t_dv)
{
tt = "[Frame:" + String(frame_num) + "][Y_diff:"+ String(t_dy) + "]"+\
"[U_diff:"+ String(t_du) + "][V_diff:"+ String(t_dv) + "]"
return String(tt)
}

v = FrameEvaluate(v, "tdy = YDifferenceFromPrevious")
v = FrameEvaluate(v, "tdu = UDifferenceFromPrevious")
v = FrameEvaluate(v, "tdv = VDifferenceFromPrevious")
v = FrameEvaluate(v, "ta = fff(current_frame, tdy, tdu, tdv)")

WriteFile(v, "video_info.log", "ta")

  создаст тебе лог-файл для видео, со строками вида:

[Frame:1832][Y_diff:2.680630][U_diff:0.465540][V_diff:0.533312]
[Frame:1833][Y_diff:2.057590][U_diff:0.357804][V_diff:0.391417]
[Frame:1834][Y_diff:1.624959][U_diff:0.333042][V_diff:0.422066]
[Frame:1835][Y_diff:0.814241][U_diff:0.310328][V_diff:0.367870]
[Frame:1836][Y_diff:38.886059][U_diff:5.146197][V_diff:5.838218]
[Frame:1837][Y_diff:7.528607][U_diff:0.734853][V_diff:1.120834]
[Frame:1838][Y_diff:7.237834][U_diff:0.532971][V_diff:0.874563]
[Frame:1839][Y_diff:7.053646][U_diff:0.558129][V_diff:0.929810]

   Это файл читается программой на любом удобном тебе языке программирования, и анализируется. Ключевые кадры видны довольно хорошо, плюс куча других интересных моментов появляется. Можно и более навороченные фильтры делать. Разумно сначала научиться сравнивать видео, а уже потом, когда поймёшь, что для этого нужно, пытаться обрабатывать avi напрямую.
   Avisynth мощная, но глючная система, причём под Винды. Не факт, что под wine пойдёт. Но и тут есть альтернативные варианты, например перекодировать фильм так, чтобы все кадры были ключевыми, а проще вообще в отдельные jpeg'и. Потом, правда, придётся функции анализа картинок подключать, но куча либ есть для этого, да и не такие сложные эти функции, при желании можно и самому написать.
    Ты же пытаешься начать с того, чтобы научиться парсить avi, причём неполноценно. Полноценная задача парсинга видео сложна, надо кучу форматов учитывать, системо-зависимые кодеки использовать и т.п. Даже программы вроде mplayer или функции из AviSynth криво работают. КК — заведомый тупик, уже обсудили, будет убогое решение, которое окончательно обломается на первом же DVD.
   Кстати, с КК могу другое решение предложить. Берёшь несколько КК из одного видео, случайным образом. И сравниваешь его со всеми КК из второго. Если будет много совпадений, значит это похожее видео :)

karkar

1. Декодировать все видео, когда можно этого не делать, плохо.
2. *DifferenceFromPrevious сравнивают среднее значение, это тоже плохо, нужны гистограммы.

apl13

Распознавай текст, который встречается в кадрах и сравнивай его! :)
Сабы просто надо найти в инете и их сравнить. :umnik2:

karkar

Наткнулся вот на презентацию по теме:
http://www.slideshare.net/MSUGMLVideogroup/20081217-video-ma...

viktor954

О! Спасибо!
Оставить комментарий
Имя или ник:
Комментарий: