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.
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.
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
(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
(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
(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 :
2 | -1 |
-1 | 0 |
0 | -1 | 0 |
-1 | 0 | 1 |
0 | 1 | 0 |
-1/8 | -1/8 | -1/8 |
-1/8 | 1 | -1/8 |
-1/8 | -1/8 | -1/8 |
-1/4 | 0 | -1/4 |
0 | 1 | 0 |
-1/4 | 0 | -1/4 |
2 | -1 |
-1 | 0 |
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".
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
(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
(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
(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
(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".
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
(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
(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
(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
(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.
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í, ...).
# 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)
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.
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)
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
Netestováno
. Použijte warpsharp -> clip2 (nahrazení pixelů) . Vytvořte omezovací filtr nebo low-luma bypass filtr -> clip3 (mask)
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ší)
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)
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)
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"
Nic, vše závisí na zpětné vazbě
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í...)
1.5.8 - 8th August 2005
1.5.7
1.5.6
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
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