# RemoveDirt

## Общая информация

Автор: Rainer Wittmann (aka kassandro)
Версия: 0.6.1
Загрузка: http://www.removedirt.de.tf/
Категория: временные сглаживатели (Temporal Smoothers)
Требования:

- Цветовое пространство YV12 или YUY2
- Поддержка набора инструкций SSEMMX в процессоре
- Ширина и высота клипа должны быть кратны 8

## Обзор

`RemoveDirt` – это временной сглаживатель для Avisynth 2.5x. Если вам лень читать документацию, используйте его без всяких параметров – для среднестатического клипа это уберёт примерно половину грязи без появления заметных искажений (артефактов). Хотя установки по умолчанию достаточно умеренны, очень резкие движения могут создать некоторый риск появления артефактов. Впрочем, поскольку постобработка (постпроцессинг) убирает все явные несглаженные артефакты, эти редкие явления, как правило, сглажены, кратковременны и малозаметны для человеческого глаза. Различные видеоматериалы существенно отличаются друг от друга, поэтому тонкая подстройка параметров фильтра может давать весьма различные результаты. Для контроля настройки имеются два разных отладочных метода. Значение параметров лучше всего поясняется принципом работы алгоритма. Если вы не понимаете смысла параметра, не меняйте его значения, а задайте вопрос в форуме Doom9, в ветке, посвящённой фильтру RemoveDirt, а не посылайте мне письмо.

Никакой автоматический очиститель не сможет полностью убрать грязь без внесения искажений в картинку. Качество очистки сильно зависит от количества движения. Для предотвращения появления артефактов необходимо подавлять сглаживание в движущихся областях. Перемещающаяся камера, разумеется, это достаточно сложный случай. Первый и последний кадр клипа не обрабатываются фильтром, и поэтому на резкой смене сцены кадры не будут очищены, т.к. `RemoveDirt` использует предыдущий и следующий кадры, которые должны быть достаточно похожи на текущий. Поскольку `RemoveDirt`, в отличие от других очистителей, пытается убрать грязь, но никогда не размывает её, можно посоветовать использовать его вместе с лёгким смягчителем (softener) для оставшейся грязи, чтобы улучшить сжимаемость клипа. (в этом случае второй фильтр надо ставить после `RemoveDirt`). Если вы используете DivX 5.1.1, его встроенный препроцессор достаточно хорош для этого, но я бы рекомендовал использовать его только в лёгком (light) режиме. С настройками по умолчанию `RemoveDirt` вряд ли справится с большими участками грязи, но, как правило, убирает много мелких загрязнений и пыли; после фильтра клип должен смотреться существенно чище.

`RemoveDirt` поддерживает два наиболее важных цветовых пространства – YV12 и YUY2. Возможно использование других пространств класса YUV, но не RGB (если вам необходимо обработать клип в RGB, пользуйтесь встроенным в Avisynth преобразователем ConvertToYUY2). Ширина и высота клипа должны быть кратны 8.

Как будет видно из описания принципа работы, `RemoveDirt` достаточно сложен. Для достижения разумной скорости обработки пришлось использовать ассемблер и набор инструкций Intel integer SSE (iSSE) во всех низкоуровневых процедурах. Таким образом, для работы необходим процессор с поддержкой iSSE.

## Установка

Начиная с версии 0.5, дистрибутив RemoveDirt содержит две версии плагина: RemoveDirt.dll (динамически подключаемый, небольшого размера) и RemoveDirtS.dll (статически подключаемый и большего размера). Для работы первого необходим файл msvcr70.dll; если этого файла нет в папке c:\windows\system или где-либо ещё в доступном месте:), вам придётся заменить RemoveDirt.dll на RemoveDirtS.dll в папке для плагинов AviSynth (пожалуйста, не держите в ней оба файла; множество лишних dll-файлов замедляет работу любой программы, использующей AviSynth). `RemoveDirt` может использоваться во многих экземплярах внутри одного скрипта; конфликтов с другими фильтрами тоже не должно быть.

## Обнаружение грязи

1. Грязь или царапина появляются только в одном кадре, а не в последовательности из нескольких кадров. Это основной принцип работы любого временного сглаживателя. Таким образом, царапины из-за плохого проектора в одном положении на нескольких подряд кадрах не могут быть очищены временным сглаживателем. В RemoveDirt это основное свойство определяется следующим конкретным признаком: пиксел является потенциальной грязью (помехой), если cf[x,y] не лежит между min(pf[x,y],nf[x,y]) и max(pf[x,y],nf[x,y]). Здесь cf[x,y] обозначает яркость пиксела с координатами x,y в текущем кадре, и соответственно pf[x,y] и nf[x,y] – на предыдущем и следующем кадрах. Другими словами, потенциальная помеха выскакивает за диапазон между предыдущим и следующим кадрами, является выбросом. Мы используем атрибут "потенциальная", т.к., к сожалению, не только помехи обладают этим признаком, но и некоторые виды движения в кадре приводят к такого рода выбросам. Если не различать эти два случая, фильтрация будет скорее не чистить, а портить клип. Это малоприятное утверждение делает создание автоматических очистителей с малым уровнем искажений таким нетривиальным делом. Крайний пример – движущаяся тонкая чёрная линия на белом фоне. Из-за движения любой чёрный пиксель в текущем кадре является белым в соседних кадрах, поэтому, согласно нашему определению, они все являются выбросами. С другой стороны, если ширина объекта достаточно велика в направлении движения, и если точки этого объекта имеют сходные цвета, то они не будут заметно выскакивать за пределы пикселей соседних кадров. Таким образом, с точки зрения очистителя, имеется "хорошая" и "плохая" разновидность движения. Попытка очистки "плохого" движения приводит к артефактам, а "хорошего" – нет.

2. Если очищаемый блок имеет общую границу с другим блоком, который не был очищен по какой-либо причине, процедура чистки не должна слишком увеличивать разницу между прилегающими линиями этих двух блоков, в противном случае очистка должна быть признана некорректной и отменена. Другими словами, очищенный блок должен достаточно хорошо подходить к неочищенным. (Предполагается, что очистка производится раздельно для прямоугольных блоков некоторого размера, в данном случае 8х8 - прим. перев.) Это задача постобработки (постпроцессинга). Хотя она может выглядеть слишком технической, тем не менее эта идея очень помогает избежать неприятных артефактов. Откровенно говоря, я думаю, что автоматичесий очиститель с малым уровнем искажений вряд ли можно создать без применения этой идеи. Для постобработки `RemoveDirt` использует параметры pthreshold и cthreshold. Если общая разница в яркости двух прилегающих друг к другу линий разных блоков увеличивается более чем на pthreshold, то очистка блока отменяется. Аналогично происходит, если разница в цвете увеличивается больше чем на cthreshold. Максимальная разница двух линий из 8 пикселов – 8*255. Если cthreshold превышает эту величину, то постобработка для цветности не производится. Для пространства YUY2 постпроцессинг цветности пока не реализован. Если и pthreshold, и cthreshold больше максимального значения, постобработка вообще отключена. Значение по умолчанию для pthreshold равно 20, а для cthreshold по умолчанию равно pthreshold, если не сказано иначе. Очевидно, что постпроцессинг яркости более существенен, чем постпроцессинг цветности. Если cthreshold и особенно pthreshold велики, то могут появиться малоприятные блочные искажения, наиболее вероятно, в областях с очень слабым контрастом. Конечно, для их появления в клипе при этом должно быть достаточно сильное движение. Если вы видите такого рода артефакты, следует уменьшить порог постобработки. Её имеет смысл вообще запрещать, только если все кадры проверены на отсутствие артефактов. По смыслу алогритма постпроцессинга, он включается только если имеется хотя бы один неочищенный блок, и перебирает циклически все блоки, пока имеются блоки, для которых он отменяет обработку. Тем не менее работает он достаточно эффективно. Изюминка работы `RemoveDirt` как раз в том, что определителю движения достаточно найти по крайней мере один, а не обязательно все блоки движущегося объекта, остальное сделает алгоритм постпроцессинга.

## Определение движения

Любая процедура, позволяющая отличить грязь и шум от движения, может считаться своего рода определителем движения. С этой точки зрения в предыдущем разделе уже было описано две таких процедуры. Здесь мы рассмотрим общего вида определитель движения, независящий от шумов. Основная идея при определении того, является ли блок движущимся, состоит в измерении отличия этого блока от соответствующих ему в предыдущем и следующем кадре. Однако, для целей очистки это неприменимо, т.к. если разница мала, то и грязи не может быть много. Вместо этого измеряется разница между предыдущим и следующим кадром, а не предыдущим и текущим, т.е. для определения движения текущий кадр не используется. В алгоритме работы `RemoveDirt` поведение определителя движения контролируется в основном параметром mthreshold. Отличия блоков изменяются от 0 (одинаковые блоки) до 8*255 (отличие полностью белого и чёрного блоков). Если разница превосходит mthreshold, блок помечается как движущийся. Значение по умолчанию mthreshold=150. Чем выше значение mthreshold, тем больше блоков чистится, но тем выше риск появления артефактов. Вдобавок к абсолютному порогу, задаваемому этим параметром, `RemoveDirt` также может использовать адаптивные пороги, меняющиеся от блока к блоку (подробности опущены). Эта опция контролируется параметром athreshold: чем выше её значение (по умолчанию 50), тем больше блоков чистится и тем выше риск артефактов. Если и mthreshold, и athreshold > 8*255, то все блоки будут очищены. При наличии “плохого” движения это создаст море искажений, и использовать это можно только для отдельных диапазонов кадров (см. ниже). Кроме того, есть ещё две переменные, dist и tolerance, управляющие определением движения. Значения по умолчанию dist=1 и tolerance=12. Блок B считается соседним с блоком A, если по горизонтали и вертикали они разделены не более dist блоками. При dist=0 блок имеет только одного соседа, т.е. себя; при dist=1 – 9 соседей (если он не на краю изображения), при dist=2 – 25 и т.д. Для каждого блока `RemoveDirt` подсчитывает число соседних блоков, помеченных как движущиеся, и если их процентная доля больше tolerance, то очистка блока не производится. Т.о. для значений по умолчанию один из 9 ближайших блоков может быть движущимся и это не запретит очистку данного блока (в частности, блок может сам быть движущимся, но у него должны быть неподвижные соседи). Это разумно, т.к. настоящее движение редко происходит только в одном отдельно стоящем маленьком блоке. С другой стороны, если плотность движущихся блоков больше некоторой, то и соседние с ними не должны быть очищены. Это рассуждение оправдывает введение параметров dist и tolerance. Более высокое значение dist уменьшает очистку; более высокое tolerance – увеличивает. Если tolerance >= 100, то все блоки очищаются. Со значениями по умолчанию `RemoveDirt` способен отличить движущуюся тонкую чёрную линию из рассмотренного выше примера от простой грязи (если она движется не слишком быстро). Определителю движения достаточно найти только отдельные участки движущихся областей, остальное сделает постпроцессинг. Недостаток такого механизма определения движения в том, что он не различает “хорошее” и “плохое” движение. На самом деле, хорошее легче определить. Я надеюсь, что когда-нибудь я смогу улучшить эту часть алгоритма.

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

    input = MPEG2Source("input.d2v")
    firstpass = RemoveDirt(input)
    cleaned = RemoveDirt(input, neighbour=firstpass)

Здесь neighbour – переменная с типом клип (значение по умолчанию - тот же клип, что и обрабатывается на входе). Разумеется, можно городить такую конструкцию и дальше, но скорость выполнения скрипта будет сильно уменьшаться. Обычно число очищаемых блоков увеличивается намного менее, чем на 1% за одну такую итерацию, а скорость падает вдвое. В принципе, в переменную neighbor можно пихать всё что угодно, `RemoveDirt` не позволяет её использовать, только если формат этого клипа сильно отличается от основного клипа, так что это помешает стабильной работе фильтра.

## Режимы очистки

В текущей версии `RemoveDirt` имеются три режима очистки, определяемые параметром mode.
mode = 0 – простейший режим усреднения. Если блок помечен как очищаемый, то каждый его пиксел заменяется средним значением соответствующих пикселей в предыдущем и следующем кадрах. В отсутствие постобработки это с большой вероятностью приводит к заметным артефактам.
mode = 2 – режим по умолчанию – гораздо умнее и слегка медленнее. Пусть cf[x,y] – яркость пиксела в текущем кадре, pf[x,y], nf[x,y] – яркость тех же пикселей в предыдущем и следующем кадрах. Тогда пиксель не изменяется, если min(pf[x,y],nf[x,y]) <= cf[x,y] <= max(pf[x,y],nf[x,y]). Если cf[x,y] < min(pf[x,y],nf[x,y]), то cf[x,y] заменяется на min(pf[x,y],nf[x,y]); и если cf[x,y] > max(pf[x,y],nf[x,y]), то cf[x,y] заменяется на max(pf[x,y],nf[x,y]). Цветовые составляющие обрабатываются аналогичным образом. Этот метод я использую всё время, и он, по-видимому, приносит наилучший результат. mode = 1 – экспериментальный режим, нечто среднее между двумя вышеописанными (ближе ко второму). Наиболее сложный и медленный режим. Изначально я надеялся получить лучшую сжимаемость на этом режиме, но пока это не очень подтверждается.

## Более высокая скорость обработки чёрно-белых изображений

Если вам нужно обработать старый фильм, то вполне возможно, что он будет чёрно-белым. В этом случае фильтровать цветовые составляющие не требуется и можно сократить время обработки. Этот режим включается заданием grey = true. В нём цветовые составляющие просто заменяются на постоянное значение 128, что приводит к переводу всего клипа в чёрно-белый вид (то же самое делает встроенный фильтр greyscale). grey = true также отключает постобработку цветности, разумеется, бесполезную в этом случае; имеет смысл задавать pthreshold несколько меньше чем обычно, например, 30 или 40.

## Отладочный режим

Для погружения в детали этого режима обращайтесь к английской документации.

## Задание диапазонов

Как правило, количество грязи в кадрах склонно меняться на протяжении фильма. Например, первые минуты киноленты обычно более загрязнены, поскольку лента выступает за катушку; кроме того, отдельные особенно грязные кадры могут попадаться в любом месте. Такая ситуация неоптимально обрабатывается заданием одних и тех же параметров для всего фильма. Для работы с разными установками в `RemoveDirt` предусмотрены файлы диапазонов, числом до 9, определяемые переменными range1, range2, ... , range9. Каждый файл диапазона может иметь свой собственный набор параметров фильтра, к именам которых добавляется цифра в конце, соответствующая номеру диапазона. Например, строка

RemoveDirt(range3= "myrange", mthreshold3=200, athreshold3=300, tolerance3=0, dist3=2)

указывает, что `RemoveDirt` использует mthreshold = 200, athreshold = 300 и т.д. для всех кадров в диапазоне, описанном в файле "myrange", который находится в директории скрипта (впрочем, можно задать и произвольный путь к файлу). Для остальных кадров используются значения по умолчанию, т.к. ни один из глобальных параметров не был переопределён явно. Файл диапазона содержит или отдельные номера кадров, или диапазоны кадров типа 13756-64 (сокращённая запись для 13756-13764). Номера кадров в файле должны следовать по возрастанию. Это соглашение делает возможным сокращённую запись, как в следующем примере (отдельные диапазоны отделяются пробелами):

    0-43 67 287 9
    1211-39 387 1432-544
    11780-2833

Этот диапазон включает следующие кадры: 0-43, 67, 287, 289, 1211-1239, 1387, 1432-1544, 11780-12833. Если кадр попадает в несколько диапазонов (например, в range2 и range4), то используется более старший (т.е. range4).

## Оптимальное использование

1. Не обрезайте кадр после RemoveDirt. Современные кодеки делят кадр на блоки 8х8 пикселей таким же образом, как и `RemoveDirt`. Если вы обрезаете число пикселей, не кратное восьми, то блоки RemoveDirt будут не совпадать с блоками кодека, что ухудшит сжатие. Соответственно, обрезание на кратное 8 число пикселей не повлияет на это, например, Crop(8,64,0,-72) можно себе позволить.

2. Обрезайте только с параметром "align=true". `RemoveDirt` интенсивно использует инструкции SSE. Если вы обрезаете без выравнивания "align=true", то `RemoveDirt`, возможно, будет работать существенно медленнее. Лучше выполнять обрезку в Avisynth (с заданием такого параметра), а не в DVD2AVI.

3. Фильмы, преобразованные к телевизионному формату (Telecined), нужно преобразовать обратно перед применением RemoveDirt. В таких фильмах вставляются дополнительные поля, чтобы увеличить частоту кадров с 24 к/с до 30 к/с. На таких удвоенных полях основное свойство грязи – неповторяемость в соседних кадрах – перестаёт иметь место, и логика фильтра не работает корректно, кроме того, определитель движения тоже путается. (подробнее – в английской документации).

4. Ставьте остальные фильтры после RemoveDirt. За исключением упомянутых выше crop и inverse telecine, другие фильтры следует применять после `RemoveDirt`, поскольку, как правило, они оказывают отрицательное влияние на определение грязи.

## Сводная таблица всех параметров

параметр | тип | значение по умолчанию | примечание | раздел
neighbour | Clip | основной обрабатываемый клип |  | Определение движения
dist | Integer | 1 | >=0 | Определение движения
mthreshold | Integer | 150 | >=0 | Определение движения
athreshold | Integer | 50 |  | Определение движения
pthreshold | Integer | 20 | >=0 | Определение грязи
cthreshold | Integer | pthreshold | >=0, только для YV12 | Определение грязи
tolerance | Integer | 12 | 0<=tolerance<=100 | Определение движения
mode | Integer | 2 | только 0,1,2 | Режимы очистки
grey | Boolean | false |  | Чёрно-белое кино
debug | Boolean | false |  | Отладка
show | Integer | 0 | только 0,1,2, только YUY2 | Отладка

Все эти параметры могут задаваться для файлов диапазонов путём дописывания номера диапазона к имени параметра. Например, mode5 задаёт режим очистки для диапазона range5.

## RemoveDirt.ini

Для такого богатого параметрами фильтра, как `RemoveDirt` (вместе с параметрами для файлов диапазонов их число может превышать 100), и с учётом того, что настройки сильно зависят от характера клипа, желательно иметь больше одного комплекта настроек по умолчанию. Вместо того, чтобы жёстко запрограммировать их заранее, эти установки по умолчанию записаны в файле RemoveDirt.ini. Если вы напишете в скрипте `RemoveDirt(default="anime")`, то фильтр будет пытаться отыскать файл RemoveDirt.ini в директории скрипта, и если не находит, то вываливается с ошибкой (разумеется, этот файл нужен только при использовании параметра default). Затем в этои файле ищется строка anime, и если не находится, то тоже выдаётся ошибка. В конце концов, читаются все переменные после строки anime и берутся в качестве значений по умолчанию. Формат строки такой: имя переменной = значение. Если переменная типа строки, то её значение должно быть заключено в кавычки, и не должно содержать кавычек внутри. Если в строке появляется символ комментария # (вне пределов строковой переменной), то остаток строки после него игнорируется. Пример файла RemoveDirt.ini:

    clensing # экстремальная очистка, только для отдельных кадров, заданных в clensing.rmd
    range1 = "clensing.rmd"
    pthreshold1 = 5000
    mthreshold1 = 5000
    grey = false
    bw # чёрно-белый режим
    grey = true
    pthreshold = 20
    mthreshold =180
    anime # режим для аниме
    pthreshold = 40
    cthreshold = 30
    mthreshold = 200

Приведённый RemoveDirt.ini описывает три режима по умолчанию: clensing, bw, anime. Режим clensing определяет первый файл clensing.rmd диапазона range1 и задаёт pthreshold1 и mthreshold1 так, что все пиксели в кадрах, заданных в clensing.rmd, подвергаются очистке. Для остальных кадров задаются параметры grey = false, pthreshold = 20, mthreshold = 180 and cthreshold = 30, так как эти параметры заданы после строки clensing. Для прочих параметров берутся значения по умолчанию. Если вызвать `RemoveDirt(default="bw")`, то используется grey = true, pthresholdd = 20, mthreshold =180 и cthreshold = 30 (очевидно, cthreshold игнорируется, т.к. обработка чёрно-белая). Если вызвать `RemoveDirt(default= "anime")`, используется pthreshold= 40, cthreshold = 30 и mthreshold = 200. Если в файле содержатся синтаксические ошибки, то фильтр выдаёт ошибку с номером первой неправильной строки.

## ImproveSceneSwitch

По смыслу работы алгоритма, `RemoveDirt` не может делать очистку на резких сменах сцен. С другой стороны, как правило, на таких сменах сцен кадры кодируются как ключевые, и если в таком кадре осталось много грязи, то сжатие пострадает. Это проблема большинства временнЫх фильтров. `ImproveSceneSwitch` – это простой фильтр для исправления ситуации. Ключевым в нём является разница d(n) между кадрами n и n+1. Фильтр основан на SSE инструкции psadbw; в пространстве YV12 сравниваются только яркостные компоненты, иначе и цветовые тоже. Если field = 0 (по умолчанию), то для вычисления d(n) используется целый кадр; если field = 1, то только верхнее поле, если field = 2 – только нижнее (этот параметр важен для фильтров деинтерлейса типа AlignFields). Мы называем резкой сменой сцены между кадрами n и n+1 ситуацию, когда d(n) > ratio*d(n-1) и d(n)>ratio*d(n+1). Здесь ratio – целочисленная переменная больше единицы (по умолчанию 7, максимум 100), определяющая чувствительность фильтра к сменам сцен. Далее, если у нас есть последовательность кадров n-1,n,n+1,n+2, и между n и n+1 происходит смена сцены, то фильтр `ImproveSceneSwitch` заменяет её на последовательность n-1,n-1,n+2,n+2. Конечно, такое дублирование кадров должно происходить только на действительно резких сменах сцен, и тогда зритель вряд ли его заметит. `ImproveSceneSwitch` используется следующим образом:
`ImproveSceneSwitch` (clip, orig, ratio = integer, extrapolate = boolean, first = boolean, last = boolean, field=0,1,2, debug = boolean)
Здесь orig - входной клип, а clip – результат работы какого-либо временного фильтра, который надо обработать описанным образом. orig используется только для определения резких смен сцены. Вспышки и подобные эффекты, характерные для музыкальных клипов, могут ввести фильтр в заблуждение – для таких видеоматериалов его не стоит применять или же надо задавать большую величину ratio (> 10). По умолчанию, и последний кадр перед, и первый кадр после смены сцены заменяются соответственно на предпоследний и второй. Для некоторых фильтров нужно менять только один из них, для этого можно отключать замену параметрами first и last. Если first = false, то первый кадр после смены сцены не заменяется вторым, и аналогично при last = false последний кадр не заменяется предпоследним. По умолчанию first = true и last = true. Пример использования `ImproveSceneSwitch`:

    input = MPEG2Source("input.d2v")
    dein = RemoveDirt(input)
    ImproveSceneSwitch(dein, input)

By Rainer Wittmann "gorw at gmx.de"

`$English Date: 2004/08/17 20:31:19 $
Русский перевод 10.06.2005 Eugene Vasiliev (eugvas@mccme.ru)`