MaskTools

Přehled

autor: kurosu and Manao
verze: 1.5.8
stáhnout: http://manao4.free.fr/, http://www.avisynth.org/warpenterprises/
kategorie: Různé pluginy
požadavky: YV12 Barevné prostředí
license: GPL

Obsah

I) O pluginu MaskTools

1) Obecně

Po zpracování můžete potřebovat zachovat jen část výstupu. Řekněme, máte klip nazvaný smooth, který je výsledkem vyhlazování (blur() například) klipu nazvaného source.
Většina šumu z klipu source v klipu smooth zmizela, Ale také má detaily. Proto by jste mohli chtít zachovat jen filtované pixely a zahodit ty, ve kterých je velký rozdíl barev nebo světlosti. To je to co dělá například MSmooth od D. Grafta. Nyní uvažujme, že zapíšete pixely obrazu ze smooth, které chcete zachovat jako bílé pixely, a ty druhé z klipu source jako černé pixely. Získáne to co se nazývá maskou. MaskTools jsou o vytváření, přeměnách a manipulaci s takovými maskami pro každou komponentu barevného prostředí YV12.

2) Popis

Tento plugin pro Avisynth 2.5, který je určen jen pro YV12 nabízí několik funkcí manipulace s klipy jako maskami:

Dále, všechny funkce berou 3 parametry: Y, U a V (kromě FitPlane funkcí, kde jména jasně říkají co je zpracováno). Podle jejich hodnoty (value), jsou aplikovány různé operace na každou plochu:

Posledním bodem je schopnost některých funkcí zpracovat jen část snímku:

Toto bylo zamýšleno pro modularitu a atomické operace (nebo užitečné, jak je to možné), a ne právě pro rychlost. Stala se z toho nafouklá a pomalá věc. Nechám na vás rozhodnutí zda je toto tvrzení zcela pravdivé, nebo trochu méně... Příklady v kapitole III) jsou s největší pravděpodobností mnohem rychleji aplikovány původními filtry.

II) Popis funkcí

Binarize

Binarize (clip, int "threshold", bool "upper")

Filtr Binarize umožňuje základní vymezení prahových hodnot (thresholding) obrazu. Jestliže upper=true, pixel jehož hodnota je striktně větší než prahová hodnota threshold bude nastavena na nulu, jinak na 255. Naproti tomu, jestliže upper=false, pixel jehož hodnota je striktně větší než threshold bude nastaveno na 255, jinak na nulu.

Výchozí hodnoty jsou threshold = 20 and upper = true.

CombMask

CombMask (clip, int "thY1", int "thY2")

Tento filtr produkuje masku zobrazující oblasti, které jsou prokládané (combed). Prahové hodnoty fungují jako u jiných filtrů: je-li po výpočtu hodnoty prokládání tato hodnota níž než thY1, nastaví se pixel na 0, když je nad thY2, nastaví se na 255, a mezitím je nastavená hodnota prokládání podělena 256.

Hodnota prokládání je (vyšší_pixel - pixel)*(nižší_pixel - pixel). Tedy, není to normalizováno do rozsahu 0..255, protože, kdyby to tak bylo, by byla blízko 1 nebo 2, ne víc. To znamená můžete použít prahovou hodnotu vyšší než 255, dokonce, i kdyby neměly být užitečné.

Výchozí jsou thY1 = 10 a thY2 = 10 ( tedy vytvoření binární masky ).

DEdgeMask / DEdgeMask2

DEdgeMask (clip, int "thY1", int "thY2", int "thC1", int "thC2", string "matrix", float "divisor", bool "setdivisor", bool "vmode")
DEdgeMask2 (clip source, clip low_thres, clip high_thres, string "matrix", float "divisor", bool "setdivisor", bool "vmode")

Tento filtr vytváří masku hran obrazu. Algoritmus nalezení hran používá konvoluční jádro, a výsledek konvoluce je pak vymezen pomocí prahových hodnot thY1 a thY2 ( jas - luma ) a thC1 a thC2 ( barevnost - chroma ). Vymezení nastane takto ( r je výsledek konvoluce ) :

Za účelem vytvoření binární masky, musíte nastavit th1=th2.

Volba konvolučního jádra se provede maticí - matrix. matice musí být 3 na 3, jejíž koeficienty jsou celočíselné, oddělené jednou mezerou. Proto řetězece "-1 -1 -1 -1 8 -1 -1 -1 -1" a "0 -1 0 -1 0 1 0 1 0" dají jádra "laplace" a "sobel" filtru EdgeMask.

Koeficienty musí být celočíselné, divisor je použit pro očištění výsledku konvoluce. Tento výsledek bude jednoduše podělen parametrem divisor. Jestliže divisor není definovaný, vyjde se ze součtu kladných koeficientů matice, čímž se umožní klasická normalizace. Může být buď desetinný nebo celočíselný, z nichž ten druhý je rychlejší.
setdivisor je přítomen jen pro zpětnou kompatibilitu. Nepoužívejte ho.
A nakonec vmode umožní vytvářet masku středěnou na 128 místo nuly. Výchozí hodnoty jsou : thY1 = 0, thY2 = 20, thC1 = 0, thC2 = 20, matrix = "-1 -1 -1 -1 8 -1 -1 -1 -1" a vmode=false.

DEdgemask2 v zásadě pracuje jako DEdgeMask, kromě toho, že místo 2 nízkých / vysokých prahových hodnot bere 2 další klipy. Každý klip obsahuje lokální prahové hodnoty pro každý pixel. Řekněme, že chcete adaptivní prahové hodnoty beroucí lokální kontrast do své hodnoty. Dobrá, lokální min & max lze získat přes inpand() a expand(). Rozdíl může být vytvořen pomocí YV12LUTxy nebo YV12Subtract. A voila, máte prahový klip obsahující lokální kontrasty.

EdgeMask

EdgeMask (clip, int "thY1", int "thY2", int "thC1", int "thC2", string "type")

Tento filtr vytváří masku hran v obrazu. Algoritmus nalezení hran používá konvoluční jádro, a výsledek konvoluce je pak vymezen prahovými hodnotami thY1 a thY2 ( jas ) a thC1 a thC2 ( barevnost ). Vymezení prahových hodnot nastane takto ( r je výsledek konvoluce ) :

Aby se vytvořila binární maska, musíte nastavit th1=th2.

Volba konvolučnho jádra se provede parametrem type :

A nakonec, existují dvě další možné hodnoty pro type ( "cartoon" a "line" ), které mají chování v této dokumentaci neuvedené.

Výchozí hodnoty jsou : thY1 = 0, thY2 = 20, thC1 = 0, thC2 = 20 a type = "sobel".

FitY2U / FitY2V / FitY2UV  FitU2Y / FitV2Y / FitU2V / FitV2U

FitPlane (clip, string resizer

FitPlane má následující inkarnace:
- jas do barevnosti: FitY2U, FitY2V, FitY2UV
- barevnost do jasu: FitU2Y, FitV2Y
- barevnost do barevnosti: FitU2V, FitV2U

Tímto filtrem můžete rozšířit (použít) masku vytvořenou na jedné ploše do do jiné plochy.

Inpand / Expand / Deflate / Inflate

Inpand (clip)
Expand (clip)
Deflate (clip)
Inflate (clip)

Tyto filtry umožňují zvětšit / snížit masku. Expand nahradí hodnotu pixelu největší okolní hodnotou. Inpand ji naopak nahradí nejnižší okolní hodnotou. Inflate vypočítá průměr okolních pixelů, a nahradí hodnotu pixelu vypočtenou jen, když je tento průměr vyšší než původní hodnota pixelu. Deflate Udělá to samé jen když je průměr nižší než původní hodnota.

Obraz vrácený funkcemi Expand / Inflate bude vždy vyšší než původní obraz. Naopak, obraz vrácený funkcemi Inpand / Deflate bude vždy nižší.

Zvětšení / snížení vytvářené pomocí Deflate / Inflate je měkčí než to, které vytváří Expand / Inpand.

HysteresyMask

HysteresyMask (mask_clip1, mask_clip2)

Tento filtr vytváří masku ze dvou masek. Teoreticky, první maska by měla být uvnitř té druhé, ale může to fungovat i pokud tomu tak není ( ačkoli výsledky budou méně zajímavé ). Principem filtru je zvětšení částí, které patří k oběma maskám, uvnitř druhé masky.

Tento algoritmus je zajímavý protože umožňuje například získat masku hran se všemi zajímavými hranami, ale bez šumu. Sestavíte dvě masky hran, jednu s hodně hranami a šumem, a druhou s málo hranami a téměř bez šumu. Pak, použijete tento filtr, a měli by jste obdržet hrany bez šumu, protože šum ve druhé masce nebyl.

Invert

Invert (clip, int offX, int offX, int w, int h)

Tento filtr nahrazuje hodnotu pixelu hodnotou 255-(hodnota pixelu).

Binarize(upper=false) mohlo by být shledáno (ale není zpracováno) jako 

Invert().Binarize(upper=true)

Logic

Logic (mask_clip1, mask_clip2, string "mode")

Tento filtr produkuje novou masku, která je výsledkem binární operace mezi dvěma maskami. Operace je zvolena parametrem mode.

Pokud je logický operátor použit s nebinární maskou, výsledky jsou nepředvídatelné.

Výchozí : mode = "and".

RGBLUT / YV12LUT / YV12LUTxy / YUY2LUT

YV12LUT (clip, string "yexpr", string "uexpr", string "vexpr")
YUY2LUT (clip, string "yexpr", string "uexpr", string "vexpr")
RGBLUT (clip, string "Rexpr", string "Gexpr", string "Bexpr", string "AMPFile")
YV12LUTxy (clipx, clipy, string "yexpr", string "uexpr", string "vexpr")

Tyto filtry aplikují funkci na každý pixel obrazu. Aby byl umožněn rychlý výpočet, každá možná hodnota funkce je předvypočtena a uložena v tabulce Look-Up Table ( udtud jména funkcí LUT ). To dělá tyto filtry slušně rychlými. RGBLUT pracuje přesně stejně jako YV12LUT, kromě toho, že má přidaný argument AMPFile. Umožní vám načíst photoshop barevný profil. 

Aby bylo možné aplikovat téměř každou možnou funkci, je toto dáno řetězcem, který reprezentuje výraz v obráceném polském zápisu (reverse polish notation). Principem tohoto zápisu je zapisovat nejdříve operandy / parametry operátoru / funkce, a pak operátor / funkci samotnou. Proto, "3 + 7" se stane "3 7 +", a "sin(3)" se stane "3 sin". Půjdeme dále ve vysvětlování, "3 * 7 + 5" se stane "3 7 * 5 +", a "(3 + 7) * 5" : "3 7 + 5 *". Nyní rozumíte hlavnímu kladu tohoto zápisu (notation) : žádná potřeba závorek.

Výpočty jsou vedeny v reálných číslech. Kladná čísla představují pravdivé tvrzení, zatímco záporná čísla představují nepravdivé tvrzení. Symbol "x" v řetězci je hodnota pixelu před použitím funkce. Pro YV12LUTxy máte také symbol "y", který představuje hodnotu vázaného pixelu v druhém klipu. Symboly musí být odděleny jednou mezerou.

Jsou imlementovány některé operátory a funkce :

Několik příkladů :

* Binarizace obrazu pomocí prahové hodnoty 128 : "x 128 < 0 255 ?". Je to přeloženo jako : "(x < 128) ? 0 : 255".
* Levels(il, gamma, ih, ol, oh) ( Podívejte se na filtr Levels ) : "x il - ih il - / 1 gamma / ^ oh ol - *". To je přeloženo jako "(((x - il) / (ih - il)) ^ (1 / gamma)) * (oh - ol)".

Výchozí hodnoty jsou : Yexpr = Uexpr = Vexpr = "x" ( tedy filtr neudělá nic ).

MaskedMerge

MaskedMerge (base_clip, overlay_clip, mask_clip)

Tento filtr aplikuje klip overlay_clip na klip base_clip, s ohledem na klip mask_clip. Přesněji, s bc, oc a mc hodnotami tří pixelů vzatých z base_clip, overlay_clip a mask_clip, bude výsledek :

v = ((256 - mc) * bc + mc * oc + 128) / 256

128 je zde ke snížení chyby při zaokrouhlování celočíselného dělení.

Tedy, když je maska 255, pixel bude pixelem z overlay_clip, když je maska 0, pixel bude z base_clip, a mezitím bude smíchán z obou klipů.

MotionMask

MotionMask (clip, int "thY1", int "thY2', int "thC1", int "thC2", int "thSD")

Tento filtr vytváří masku pohybu obrazu. Jako u jiných filtrů vytvářejících masky, jakmile je pohyb vypočítán, je vymezen dvěma prahovými hodnotami. Tento filtr bude také prověřovat změnu scény, a nevytváří masku jestliže už je nějaká detekována.

Detekce změny scény se provádí výpočtem součtů absolutních rozdílů v obrazu a jeho předchozího. Tento součet je zprůměrován a pak porovnán s thSD. Pokud je to víc než thSD, je detekována změna scény.

Pohyb je vypočítán stejným způsobem NoMoSmooth, což znamená, že pro každý pixel budeme počítat absolutní součet rozdílů mezi pixelem a jeho okolím, a pixel a okolí v předchozím obrazu. Výsledná hodnota je podělena číslem 9, aby byl výsledek normalizován do rozsahu 0 a 255.

Tento algoritmus dává pouze přiblížení (aproximaci) pohybu. Bude dobře pracovat na hranách objektu, ale ne uvnitř.

Výchozí hodnoty jsou : thY1= 20, thY2 = 20, thC1 = 10, thC2 = 10 a thSD = 10.

YV12Convolution

YV12Convolution (clip, string "horizontal", string "vertical", int "total", bool "automatic", bool "saturate")

Tento filtr vypočítá konvoluční součin mezi obrazem a jádrem definovaným násobením hodnot horizontal a vertical. Tyto dva řetězce představují vektory. Musí mít lichý počet celých nebo reálných čísel, oddělených jednou mezerou. total je normalizační faktor, kterým je výsledek součinu podělen. Jestliže je automatic nastaveno na 'true', total je součtem koeficientů matice. To znamená, že touto cestou celková světlost obrazu není dotčena. Saturate umožní vybrat chování filtru, když je výsledkem záporné číslo.

Pokud není total definován, je nastaven na součet koeficientů konvolučního jádra, čímž se umožní dobrá normalizace jader pro rozmazání (bluring) / zostření (sharpening).

Pokud jeden z koeficientů horizontal nebo vertical je reálné číslo, všechny výpočty budou provedeny jako floats (desetinné), takže filtr bude pomalejší.

Výchozí hodnoty jsou : horizontal = "1 1 1", vertical = "1 1 1" a automatic = false, saturate = true.

YV12Subtract

YV12Subtract (clip1, clip2, int tol, bool "widerange")

Tento filtr vypočítá rozdíl mezi dvěma klipy. Existuje několik způsobů výpočtu tohoto rozdílu, závisejících na hodnotách widerange a tol.

Výchozí hodnoty jsou : tol = -1 and widerange = false.

III) Některá praktická použití (ne moc testované)

Tyto příklady nechtějí vytvářet přesně stejné výsledky jako původní filtry, snaží se je napodobit, navíc jsou o dost pomalejší. Přes řadu dalších funkcí, žádná nová myšlenka.

Poznámky: 
- Jsem příliš líný aktualizovat syntaxi, obzvlášť pokud jde o to jak pracuje mode=2, a jak bylo aktualizováno EdgeMask (nyní už například nepotřebuje Binarize)
- Některé filtry popisované jako 'na vytvoření' už existují (imagereader, úrovně pro sevření, ...).

1) MSharpen

# Sestaví EdgeMask pro clip1, Binarizuje ji a vloží výsledek do clip3
# Aplikuje zostřovací filtr na clip1 a vloží ho do clip2
...
return MaskMerge(clip1, clip2, clip3)

Zostřené hrany klipu clip2 vyšší než prahová hodnota dané do Binarize budou zostřeny a použity pro nahrazení jejich původních hodnot v klipu clip1. Mohli by jste také napsat filtr s oddělenou Look-up table (nejlépe by vypadala jako zvon), nahradit jí Binarize, a měli by jste vážené zostření podle hodnoty hrany: to je HiQ část ve SmartSmoothHiQ

clip2 = clip1.<EdgeEnhancer>(<parameters>)
#U a V plochy nepotřebují filtrování, Y ho potřebuje
#EdgeMask(<...>, "roberts", Y=3, U=-128, V=-128) pro černobílou mapu
clip3 = clip1.EdgeMask(15, 60, "roberts", Y=3, U=1, V=1)
return MaskedMerge(clip1, clip2, clip3)

2) MSoften

Nahraďte EdgeEnhancer prostorovým změkčovačem (kaskádová rozmazání? prostorové změkčení MMX?) a použijte upper=true pro výběr blízkých pixelů v ploše.

3) Redukce duhy (jak se popisuje v tomto vlákně )

Upozornění, ani toto není zázračné řešení

clip2 = clip1 změkčit na maximum (použitím deen("m2d") nebo edeen například)
#Získejte jasovou mapu hran a zvýrazněte hrany roztažením (zahuštěním)
# -> na širší oblasti, které mají být zpracovány
clip3 = clip1.EdgeMask(6, "roberts", Y=3, U=1, V=1).Inflate(Y=3, U=1, V=1)
#Nyní použijte jasovou masku hran (edgemask) jako masku barevnosti
clip3 = YtoUV(clip3, clip3).ReduceBy2().Binarize(15, upper=false, Y=1, U=3, V=3)
#Musíme zpracovat barevnost pixelů blízko hran, ale zachovat netknutou Y plochu
return MaskedMerge(clip1, clip2, clip3, Y=1, U=3, V=3)

4) Supersampled (supervzorkovaný) fxtoon

Netestováno

. Použijte tweak ke ztmavení obrazu nebo použijte plugin, který sníží hodnoty Y
-> clip2
. Sestavte masku hran, Supersamplujte tuto masku, Binarizujte ji vysokou prahovou hodnotou
(sevření zní lépe), zahustěte (inflate) ji klipem -> clip3
. Použijte tmavší pixely klipu clip2 podle hodnot klipu clip3

5) Warpsharp pro tmavý jas

Netestováno

. Použijte warpsharp -> clip2 (nahrazení pixelů)
. Vytvořte omezovací filtr nebo low-luma bypass filtr -> clip3 (mask)

6) Pseudo-deinterlacer (barevnost bude stále problematická)

Netestováno

clip2 = clip1.SeparateFields().SelectEven().<Method>Resize(<parameters>)
clip3 = clip1.<CombingDetector>(<parameters>)
return MaskedMerge(clip1, clip2, clip3, Y=3, U=3, V=3)

(barevnost dokonce ještě problematičtější)

7) Nepravoúhlá překrývání

Ve skutečnosti je toto prováděno lépe funkcemi layer a mask...

#Jednoduchý hack protože ImageReader potřebuje celočíselnou fps...
#Většina zdrojů je nativně v YUY2/YV12
clip = AviSsource("test.avi").ConvertToYV12().assumefps(fps)
#Načtěte obrázek pro překrývání
image = ImageReader("mask.bmp", 0, clip.framecount()-1, 24, use_DevIl=false)
#Jednoduchý způsob: předpokládejme, že černá je průhledná 
#Jakákoliv jiná barva by byla docela komlikovanější*
masktemp = imageYV12.Binarize(17, upper=false, Y=3)
#Nastavíme jasovou masku aby zapadly plochy barevnosti
mask = Mask.FitY2UV()
#Nyní tak máme masku, která nám říká co chceme zachovat...
#Nahradíme obrazem části klipu skryté maskou!
MaskedMerge(clip, image, mask, Y=3, U=3, V=3)
#*řešení: mask = OverlayMask(image, image.BlankClip("$xxxxxx"), 1, 1)

8) Náhrada pozadí

Tento příklad by jistě vypadala lépe v RGB. Abyste se vyhnuly typickým problémům kvůli šumu nebo kompresi, raději použijte rozmazané verze klipu a obrazu.

source = AviSource("overlay.avi").AssumeFPS(24)
#rozmazání (blur) zdroje
clip = source.Blur(1.58).Blur(1.58).Blur(1.58)
#načtěte pozadí pro nahrazení, zachycené z rozmazané sekvence
bgnd = ImageReader("bgnd.ebmp", 0, clip.framecount()-1, 24, use_DevIl=false)
#načtěte nové pozadí
new = ImageReader("new.ebmp", 0, clip.framecount()-1, 24, use_DevIl=false)
#integrovaný filtr pro výstupní masku = (clip~overlay?)
mask = OverlayMask(clip, overlay.ConvertToYV12(), 10, 10)
MaskedMerge(source, new.ConvertToYV12(), mask, Y=3, U=3, V=3)

9) K-mfToon

Potřebuje zahrnout více informací (původní url/příspěvky) ale prozatím si myslím, že původní autor filtru mfToon, mf (mf@onthanet.net) na to nebude reagovat moc vehementně, zatím to stále není adresováno.
Výstup funkce uvnitř K-mfToon.avs by měl být identický s výstupem původního mftoon.avs (také zahrnutý), s dvojnásobnou rychlostí.
Požadavky jsou:
- Pro mfToon:
. načíst pluginy zvané "MaskTools", "warsharp", "awarsharp" 

IV) Na dopracování

Nic, vše závisí na zpětné vazbě

V) Odmítnutí záruk

Tento plugin je vydáván pod GPL licencí. Musíte souhlasit s podmínkami uvedenými v 'Copying.txt' před použitím pluginu nebo jeho zdrojového kódu.

Také se vám doporučuje používat ho ve filantropickém (lidumilném) rozpoložení, t.j. ne ve smyslu "Budu si tohle tajemství držet pro sebe".

V neposlední řadě, velmi malá část všech možných použití každého filtru byla testována (možná 5% - zbývá spousta strávených hodin při ladění ;-). Proto je zpětná vazba velmi vítána (naproti tomu - nedostatek zpětné vazby - je také skutečností...)

VI) Revize

1.5.8 - 8th August 2005

1.5.7

1.5.6

v1.5.5 - 6 November 2004

v1.5.4 - 14 October 2004

1.5.2 - 1.5.3

1.5.1

1.4.16

1.4.15.3

1.4.15.2

1.4.15.1

1.4.15

1.4.14.2

1.4.14.1

1.4.14

1.4.13

1.4.12

1.4.11

1.4.10

1.4.9

1.4.8

1.4.7

1.4.6

1.4.5

1.4.4

1.4.3

1.4.2

1.4.1

1.4.0

1.3.0 (private version)

1.2.0 (private version)

1.1.0 (private version)

1.0.2 (last version - public project dropped):

1.0.1: Initial release

VII) Pro vývojáře

Přeskočte na V) jestliže vás nezajímá vývoj dostupných nástrojů.

The project is a VC++ 6 basic project. Each filter has its own folder which stores the header used by the interface, the source for the function members, the source for processing functions and its header. Let's look at EdgeMask:
- EdgeMask.h is included by the interface to know what the filter 'looks like' (but interface.cpp still holds the definition of the calling conventions and exported functions)
- EM_func.h describes the different processing functions (they should all have the same prototype/parameters):
. Line_MMX and Line_C
. Roberts_MMX and Roberts_C
. Sobel_MMX and Sobel_C
- EM_func.cpp, as all <filter's initials>_func.cpp, stores the implementation of the processing functions, and sometimes their MMX equivalents.
- EdgeMask.cpp implements the class; the constructor select the appropriate processing function (MMX? C? Roberts? Line? Sobel?) and uses it to fill the generic protected function pointer used in GetFrame

Interface.cpp stores the export function and all of the calling functions (AVSValue ... Create_<filter>).

ChannelMode.cpp defines the Channel operating modes. There could be added the equivalent of a debugprintf.

This quick walkthrough won't probably help most developers, as the examples of V) for users, but that's the best I've come with so far. It will improve of course over time depending on the success of the idea, which main drawback, speed, will probably make it scarcely used, if ever. <g>

$English Date: 2005/10/05 18:12:43 $

Český překlad:22.2.2009