# MaskTools

## Abstrato

autor: kurosu e Manao
versão: 1.5.1
download: http://www.geocities.com/manao47/Filters/
categoria: Miscelânea de Plugins
requisitos: YV12 Colorspace

## Tabela dos conteúdos

- I) Sobre MaskTools
  - 1) Versão Simples
  - 2) Descrição
- II) Descrições da Função
- III) Alguns usos práticos
  - 1) MSharpen
  - 2) MSoften
  - 3) Redu ção de Arco-íris
  - 4) Super amostragem de fxtoon
  - 5) Warpsharp para luma escura
  - 6) pseudo-desentrelaçador (croma continua problemático)
  - 7) Sobreposições não retangulares
  - 8) Substituir fundos
  - 9) Kmf-Toon ;-)
- IV) TODO - a fazer
- V) Retratação (não salte essa parte, mas eu não forço a aprender isto)
- VI) Revisões
- VII) Os Ensaios do Desenvolvedor

## I) Sobre MaskTools

### 1) Versão Simples

Depois do processo, você pode precisar manter só parte da produção. Digamos, você tem um clipe suavizado, resultado de uma suavização (blur() por exemplo) em um clipe fonte.

A maioria do ruído da fonte desapareceu, mas assim tem detalhes. Você pode manter só os píxeis filtrados e descartar os que têm grande diferença de cor ou brilho.

Isso é o que faz MSmooth por D. Graft, por exemplo. Agora considere que você grava em uma imagem de píxeis da suavização e quer manter como píxeis brancos e os outros da fonte como píxeis pretos. Você obtém uma máscara. MaskTools que trata da criação, encarecimento e manipulação de tal máscara para cada componente do colorspace YV12.

### 2) Descrição

Este plugin YV12 do Avisynth 2.5 oferece várias funções que manipulam clipes como máscaras:

- Binarize irá "binarizar" o quadro de entrada dependendo de um percentual e um comando.
- CombMask produz uma máscara com áreas que apresenta penteado.
- EdgeMask construirá uma máscara das extremidades de um clipe, pela aplicação de percentual (valores adequados habilitarão ou os desabilitarão).
- Expand expandirá os valores altos em um plano, pondo na produção o máximo valor na vizinhança 3x3 ao redor do píxel de entrada. A função oposta é chamada Inpand.
- FitY2UV/FitY2U/FitY2V redimensiona o plano Y e substitui plano(s) UV/U/V) pelo resultado do redimensionamento (você pode especificar seu filtro redimensionador, até mesmo um que não seja interno do AviSynth); as funções opostas são FitU2Y e FitV2Y.
- Inflate vai 'inflar' os valores altos em um plano, pondo no plano de produção a média dos 8 vizinhos se é mais alta que o valor original, caso contrário, o valor original. A função oposta é chamada Deflate (dedicado a Phil Katz).
- Invert inverte o píxel (i.e. out = 255 - in); isto também pode ser usado para aplicar um efeito 'solarize' ao quadro.
- Logic executa operações lógicas mais típicas (na realidade, as funções C mnemônicas do MMX, ainda estão disponíveis, principalmente por causa dos limites de dimensões de quadro).
- RGBLUT/YV12LUT/YV12LUTxy são tabelas que permitem aplicar rapidamente uma função para cada píxel do quadro.
- MaskedMerge pega 3 clipes e aplica uma pesada fusão entre o primeiro e o segundo clipe, dependendo da máscara representada pelo clipe 3.
- MotionMask cria uma máscara do movimento no quadro.
- OverlayMask compara 2 clipes baseado no percentual de luminância e crominância e produz píxeis próximos ou não (quase igual ao que ColorKeyMask faz).
- YV12Convolution permite convolver o quadro pela matriz de sua escolha.
- YV12Layer é o equivalente ao OverLay (sobrepor).
- YV12Substract é igual a Subtract (subtrair), também trabalha em YV12, mas deve ser um pouco mais rápido (otimizado por MMX).

Além disso, todas as funções têm 3 parâmetros: Y, U e V (menos as funções FitPlane onde obviamente o nome diz o que é processado). Dependendo do seu valor, são aplicadas operações diferentes para cada plano:

- valor = 3 fará o processo atual do filtro,
- valor = 2 copiará o 2º plano do vídeo (se adequado) para produzir o plano correspondente
- valor = 1 não o processará (freqüentemente, deixa isto com o 1º plano do clipe ou lixo - confira você mesmo)
- valor = [-255... 0] encherá o plano produzido com valor- (para ter níveis cinzas, use U=128,V=128)

Um último ponto é a habilidade de algumas funções para processar só uma parte da armação:

- este comportamento é fixo pelos parâmetros (offX, offY) posição do ponto inicial e (w,h) largura e altura da área processada; os filtros devem modificar esses parâmetros de forma que a área processada esteja dentro dos 2 quadros
- no caso de um filtro (menos YV12Layer) usando 2 clipes, eles têm que ter as mesmas dimensões
- em todos os casos, o quadro deve ser pelo menos MOD8 (às vezes MOD16) para habilitar o filtro a usar as funções MMX (e trabalhar à velocidade máxima)

Isto foi planejado para operações modulares e atômicas (ou tão útil quanto possível), não realmente velocidade. Ficou inchado e lento. Eu o deixo decidir se esta declaração é totalmente verdade, ou um pouco menos... Os exemplos em III provavelmente são muito mais rápidos se aplicados com os filtros originais.

## II) Descrições da Função

### Binarize

`Binarize` (clip, int "threshold", bool "upper")
O filtro Binarize permite um percentual básico de um quadro. Se upper=true, um píxel cujo valor é estritamente superior ao percentual será fixado em zero, ou senão para 255. Pelo contrário, se upper=false, um píxel cujo valor é estritamente superior ao percentual será fixado em 255, ou senão em zero.
Os padrões são threshold = 20 e upper = true.

### CombMask

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

Este filtro produz uma máscara que exibe áreas penteadas. Os percentuais trabalham para os outros filtros como: depois de calcular o valor pente, se este está abaixo de thY1, o píxel é fixado em 0, acima de thY2, é fixado em 255 e entre eles é fixado ao valor pente dividido por 256.

O valor pente é (upper_pixel - pixel)*(lower_pixel - pixel). Assim, não é normalizado à gama 0.. 255, porque se fosse, o valor estaria perto de 1 ou 2, não mais. Isso significa que você pode usar percentual mais alto que 255, mesmo que eles não sejam úteis.

Os padrões são thY1 = 10 e thY2 = 10 (assim, uma máscara binária).

### DEdgeMask

`DEdgeMask` (clip, int "thY1", int "thY2", int "thC1", int "thC2", string "matrix", float "divisor", bool "setdivisor")
Este filtro cria uma máscara de extremidade do quadro. O algoritmo de achar extremidades usa um núcleo de convolução e o resultado é então percentualizado com thY1 e thY2 (luma) e thC1 e thC2 (croma). O percentual acontece como (r é o resultado da convolução):

- r <= th1 dá 0.
- th1 < r <= th2 dá r.
- th2 < r dá 255.

Para criar uma máscara binária, você só tem que fixar th1=th2.

A escolha do núcleo de convolução é feita com matrix. A matriz deve ser 3 por 3, cujos coeficientes são inteiros, separados por um só espaço. Conseqüentemente, as strings "-1 -1 -1 -1 8 -1 -1 -1 -1" e "0 -1 0 -1 0 1 0 1 0" darão núcleos respectivamente para o "laplace" e "sobel" do filtro EdgeMask.

Como os coeficientes devem ser inteiros, divisor é usado para refinar o resultado da convolução. Este resultado simplesmente será dividido pelo divisor. Se ele não estiver definido, é padronizado à soma do coeficiente positivo da matriz, permitindo assim uma normalização clássica. Pode ser um flutuante ou um inteiro, sendo que o posterior é mais rápido. setdivisorestá presente só para compatibilidade inversa. Não use.
Os padrões são: thY1 = 0, thY2 = 20, thC1 = 0, thC2 = 20 e matrix = "-1 -1 -1 -1 8 -1 -1 -1 -1".

### EdgeMask

`EdgeMask` (clip, int "thY1", int "thY2", int "thC1", int "thC2", string "detector")
Este filtro cria uma máscara da extremidade do quadro. O algoritmo de achar extremidade usa um núcleo de convolução, e o resultado é então percentualizado com thY1 e thY2 (luma) e thC1 e thC2 (croma). O percentualizado acontece como (r é o resultado da convolução):

- r <= th1 dá 0.
- th1 < r <= th2 dá r.
- th2 < r dá 255.

Para criar uma máscara binária, você só tem que fixar th1=th2.

A escolha do núcleo de convolução é feita pelo detector:

- detector = "roberts" :

  2 | -1
  -1 | 0

- detector = "sobel" :

  0 | -1 | 0
  -1 | 0 | 1
  0 | 1 | 0

- detector = "laplace" :

  -1/8 | -1/8 | -1/8
  -1/8 | 1 | -1/8
  -1/8 | -1/8 | -1/8

- detector = "special" :

  -1/4 | 0 | -1/4
  0 | 1 | 0
  -1/4 | 0 | -1/4

Finalmente, também há dois outros possíveis valores para detector ("cartoon" e "line"), que têm comportamentos não são documentados aqui.

Os padrões são: thY1 = 0, thY2 = 20, thC1 = 0, thC2 = 20 e detector = "sobel".

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

`FitPlane` (clip, string resizer)

`FitPlane tem as seguintes formações:`
- luma para croma: `FitY2U`, `FitY2V`, `FitY2UV`
- croma para luma: `FitU2Y`, `FitV2Y`
- croma para croma: `FitU2V`, `FitV2U`

Você pode assim reproduzir uma máscara criada em um plano particular para outro plano.

### Inpand / Expand / Deflate / Inflate

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

Este filtro permite aumentar / reduzir uma máscara. `Expand` `substituirá o valor de um píxel pelo valor circunvizinho mais alto.` `Inpand ao contrário, substituirá pelo mais baixo valor circunvizinho.` `Inflate` `computará os meios` píxeis `circunvizinho e substituirá o valor deste píxel só se este meio for superior ao valor do píxel original. Deflate fará o mesmo só se o meio for inferior ao valor original.`

O quadro retornado por Expand / Inflate sempre será mais alto que o quadro original. Pelo contrário, o retornado por Inpand / Deflate sempre será mais baixo.

O aumentado / reduzido produzido por Deflate / Inflate é mais suave que o de Expand / Inpand.

### HysteresyMask

`HysteresyMask` (mask_clip1, mask_clip2)

Este filtro cria uma máscara de duas. Teoricamente, a primeira máscara deve estar dentro da segunda, mas pode trabalhar se não for true (entretanto os resultados serão menos interessantes). O princípio do filtro é aumentar as partes que pertencem a ambas as máscaras, dentro da segunda.

Este algoritmo é interessante porque permite obter uma máscara da extremidade com todas as extremidades interessadas, por exemplo, mas sem o ruído. Você constrói para aguçar máscaras, um com muitas extremidades e ruído, o outro com algumas extremidades e quase nenhum ruído. Então, você usa este filtro e deve obter as extremidades, sem o ruído, porque o ruído não estava lá na segunda máscara.

### Invert

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

Este filtro troca o valor do píxel pelo de valor 255.

Binarize(upper=false) pode ser visto (mas não é processado) como

Invert().Binarize(upper=true)

### Logic

`Logic` (mask_clip1, mask_clip2, string "mode")

Este filtro produz uma máscara nova que é o resultado de uma operação binária entre duas máscaras. A operação é escolhida com o parâmetro mode.

- mode="and" : trabalha só com máscaras binárias (só píxeis em 0 ou 255). A máscara de produção é a interseção das duas. Significa que se ambos os píxeis correspondentes forem 255, o píxel resultante será 255, senão 0.
- mode="or" : trabalha só com máscaras binárias. A máscara produzida é a união das duas. Significa que se um dos píxeis correspondentes for 255, o píxel resultante será 255, senão 0.
- mode="xor" : trabalha só com máscaras binárias. A máscara produzida é a diferença entre as duas. Significa que se um (exclusivamente) dos píxeis correspondente é 255, o pixel resultante será 255, senão 0.
- mode="andn" : trabalha só com máscaras binárias. A máscara produzida é a subtração da segunda máscara e da primeira. Significa que se o píxel da primeira máscara é 255 e o segundo é 0, retornará 255, senão 0.
- mode="min" : retorna para cada píxel o valor mínimo entre os dois píxeis das máscaras de entrada. Soma a mode="and", mas para máscaras não binárias.
- mode="max" : retorna para cada píxel o valor máximo entre o dois píxeis das máscaras de entrada. Soma a mode="or", mas para máscaras não binárias.

Se um operador lógico for usado com uma máscara não binária, os resultados são imprevisíveis.

Padrão: mode = "and".

### RGBLUT / YV12LUT / YV12LUTxy

`YV12LUT` (clip, string "yexpr", string "uexpr", string "vexpr")
`RGBLUT` (clip, string "yexpr", string "uexpr", string "vexpr", string "AMPFile")
`YV12LUTxy` (clipx, clipy, string "yexpr", string "uexpr", string "vexpr")

Estes filtros aplicam uma função a cada píxel do quadro. Para permitir uma computação rápida, todo possível valor da função é pré-computado e armazenado num tabela. Isso faz os filtros bastante rápidos. `RGBLUT trabalha do mesmo modo como YV12LUT, a não ser por ter um argumento adicional AMPFile.` Ele permite carregar um perfil de cor do photoshop.

Para poder aplicar quase toda possível função, este aqui é determinado por uma string que representa uma expressão em notação de polimento contrário. O princípio desta notação é gravar primeiramente os operandos / parâmetros de um operador / função e então seus operador / função. Conseqüentemente, "3 + 7" se tornam "3 7 +", e "sin(3)" se torna "seno 3". Indo além nas explicações, "3 * 7 + 5" se tornam "3 7 * 5 +", e "(3 + 7) * 5":"3 7 + 5 *." Agora, você entende o recurso principal desta notação: nenhuma necessidade de parênteses.

Computações são líderes em números reais. Números positivos também representam uma verdadeira declaração, enquanto que números negativos representam uma declaração falsa. Na string, o símbolo "x" é o valor do píxel antes do uso da função. Para YV12LUTxy você também tem o símbolo "y" que representa o valor do píxel disposto no segundo clipe. Os símbolos devem ser separados por um único espaço.

Alguns operadores e funções estão implementados:

- +, -, /, *, ^, % são operadores mais, menos, dividir, multiplicar, potência e módulo.
- &, |, °, !& são os operadores lógicos and, or, xor, e not. Se o resultado for true, eles retornam 1.0, senão -1.0.
- <, <=, >, >=, =, != são os operadores de relação menos que, menos ou igual a, mais que, mais ou igual a, igual a, não igual a. Se o resultado for verdade, eles retornam 1.0, senão -1.0.
- cos, sin, tan, acos, asin, atan, exp, log, abs são funções co-seno, seno, tangente, arco-coseno, arco-seno, arco-tangente, exponencial, logaritmo de napierian, valor absoluto.
- ? permite fazer um teste de condição. É operador ternário, o primeiro operando sendo a condição, o segundo o valor se a condição é verdade, o terceiro se falso.

Alguns exemplos:

* A binarização do quadro com um percentual em 128: "x 128 < 0 255?". É traduzido como: "(x < 128)? 0 : 255".
* Levels(il, gamma, ih, ol, oh) (dê uma olhada no filtro Levels): il de "x - il de ih - / gamma ^ oh ol - *". É traduzido como "(((x - il) / (ih - il)) ^ gamma) * (oh - ol)".

Padrões são: Yexpr = Uexpr = Vexpr = "x" (portanto, o filtro não faz nada).

### MaskedMerge

`MaskedMerge` (base_clip, overlay_clip, mask_clip)

Este filtro aplica o clipe overlay_clip no base_clip, considerando o clipe mask_clip. Mais precisamente, com bc, oc e mc os valores de três píxeis assumidos base_clip, overlay_clip e mask_clip respectivamente, o resultado será:

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

128 está aqui para reduzir o erro devido ao arredondamento da divisão de inteiro.

Assim, se a máscara for 255, o píxel será do overlay_clip, se a máscara for 0, o píxel será do base_clip, e será misturado entre ambos os clipes.

### MotionMask

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

Este filtro cria uma máscara do movimento do quadro. Como os outros filtros que criam máscaras, o movimento é computado, é percentualizado por dois percentuais. Este filtro também conferirá mudança de cena e se detectar uma, não produzirá nenhuma máscara.

A detecção de mudança de cena é feita computando a soma de diferenças absolutas do quadro com o prévio. Esta soma é pesada e comparada para thSD. Se for mais que thSD, uma mudança de cena é detectada.

O movimento é computado do mesmo modo como NoMoSmooth, significando que para cada píxel, computaremos a soma absoluta das diferenças entre o píxel e seu vizinho com o do quadro prévio. O valor resultante é dividido por 9 para normalizar o resultado entre 0 e 255.

Este algoritmo só dá uma aproximação do movimento. Trabalhará bem nas extremidades de um objeto, mas não em seu interior.

Padrões são: thY1= 20, thY2 = 20, thC1 = 10, thC2 = 10 e thSD = 10.

### YV12Convolution

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

Este filtro computa o produto de convolução entre o quadro e o núcleo definido pela multiplicação do horizontal pelo vertical. Estas duas strings representam vetores. Eles têm que ter um número inteiro diferente ou números reais, separado por espaços únicos. total é um fator de normalização que é dividido pelo resultado do produto. Se automatic estiver fixado em 'true', o total é a soma dos coeficientes da matriz. Significa que desse jeito, o brilho global do quadro não é tocado. Saturate permite escolher o comportamento do filtro quando o resultado for um número negativo.

- saturate = true : valores negativos são zerados.
- saturate = false : valores negativos são invertidos.

Se total não estiver definido, é fixado à soma dos coeficientes do núcleo de convolução, permitindo assim uma boa normalização para borrar / aguçar os núcleos.

Se um dos coeficientes horizontal ou vertical é um real número, todas as computações serão feitas com flutuantes, assim o filtro será mais lento.

Padrões são: horizontal = "1 1 1", vertical = "1 1 1" e automatic = false, saturate = true.

### YV12Subtract

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

Este filtro computa a diferença entre os dois clipes. Há vários modos de computar esta diferença, dependendo dos valores de widerange e de tol.

- widerange = true : nós computamos a diferença (n) entre os dois clipes e retornamos r = 128 + 128 * pow(n / 255,1 / tol). Se tol < 0, 1 / tol se torna 0.5.
- widerange = false :
  - tol < 0 : nós computamos a diferença absoluta (n) entre os dois clipes e devolvemos r = n / 2 + 128.
  - tol >= 0 : nós computamos a diferença absoluta (n) entre os dois clipes e devolvemos 0 se n é mais baixo que tol, senão n - tol.

Padrões são: tol = -1 e widerange = false.

## III) Alguns usos práticos (não testados extensivamente)

Estes não produzirão os mesmos resultados exatos como nos filtros originais que eles tentam imitar, além de serem mais lentos. Apesar das numerosas funções adicionais, nenhuma idéia mais nova.

Notas:
- Eu estou com muita preguiça para atualizar a sintaxe, especialmente considerando como mode=2 trabalha e como EdgeMask foi atualizado (agora maiores necessidades de um Binarize por exemplo)
- Alguns filtros eu descrevo como 'para criar' já existe (imagereader, níveis para segurar, ...).

#### 1) MSharpen

    # Construa EdgeMask do clip1, Binarize isso e armazene o resultado no clip3
    # Aplique qualquer filtro aguçador ao clip1 e salve no clip2
    ...
    return MaskMerge(clip1, clip2, clip3)

As extremidades aguçadas do clip2 maior que o percentual dado a Binarize será aguçado e substituirá seu valor original no clip1. Você também pode escrever um filtro com uma tabela particular (melhor se parecer com um sino), substitua Binarize por ele e tenha um aguçar pesado, dependendo do valor de extremidade: essa é a parte HiQ no SmartSmoothHiQ.

    clip2 = clip1.<EdgeEnhancer>(<parameters>)
    # Planos U e V não precisam filtragem, Y precisa
    # EdgeMask(<...>, "roberts", Y=3, U=-128, V=-128) para mapa cinza
    clip3 = clip1.EdgeMask(15, 60, "roberts", Y=3, U=1, V=1)
    return MaskedMerge(clip1, clip2, clip3)

#### 2) MSoften

Substitua EdgeEnhancer por um softener espacial (borrado em cascata? spatialsoftenMMX?) e use upper=true para selecionar píxeis planos próximos.

#### 3) Redução de arco-íris (como descrito aqui neste artigo

Aviso, isto não é uma solução milagrosa

    clip2 = clip1 soften at maximum (using deen("m2d") or edeen for instance)
    # Pegue luma edgemap e aumente as extremidades com inflating
    # -> áreas mais largas a serem processadas
    clip3 = clip1.EdgeMask(6, "roberts", Y=3, U=1, V=1).Inflate(Y=3, U=1, V=1)
    # Agora, use luma edgemask como máscara de croma
    clip3 = YtoUV(clip3, clip3).ReduceBy2().Binarize(15, upper=false, Y=1, U=3, V=3)
    # Nós temos que processar píxeis croma próximos das extremidades, mas manter intato o plano Y
    return MaskedMerge(clip1, clip2, clip3, Y=1, U=3, V=3)

#### 4) Super amostragem de fxtoon

Não testado

    . Use tweak para escurecer o quadro ou fazer um plugin que reduz valores de Y - > clip2
    . Construa máscara de extremidade, Supersample esta máscara, Binarize isto com um alto percentual (segurando melhor o som), Inflate - > clip3
    . Aplique os píxeis mais escuros de clip2 que dependem dos valores de clip3

#### 5) Warpsharp para luma escura

Não testado

    . Aplique warpsharp - > clip2 (píxeis de substituição)
    . Crie um filtro segurando ou um de contorno baixo luma - > clip3 (máscara)

#### 6) pseudo-desentrelaçador (croma continua problemático)

Não testado

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

(croma até mais problemático)

#### 7) Sobreposições não retangulares

Na realidade, isto é controlado melhor por camada e máscara...

    # Simples corte porque ImageReader precisa de um fps inteiro...
    # A maioria das fontes é nativa em YUY2/YV12
    clip = AviSsource("test.avi").ConvertToYV12().assumefps(fps)
    # Carregue o quadro para ser sobreposto
    image = ImageReader("mask.bmp", 0, clip.framecount()-1, 24, use_DevIl=false)
    # Modo simples: assumir preto é transparente
    # Qualquer outra cor seria bem mais complicado *
    masktemp = imageYV12.Binarize(17, upper=false, Y=3)
    # Nós fixamos a máscara luma para ajustar os planos croma
    mask = Mask.FitY2UV()
    # Agora que nós temos a máscara que nos conta o que queremos manter...
    # Substitua por imagem as partes do clipe mascarado por mask!
    MaskedMerge(clip, image, mask, Y=3, U=3, V=3)
    # * solução: mask = OverlayMask(image, image.BlankClip ($xxxxxx "), 1, 1)

#### 8) Substituir fundos

Este exemplo fica claramente melhor em RGB. Para evitar problemas típicos devido a ruído ou compressão, você usa melhor versões borradas do clipe e quadro.

    source = AviSource("overlay.avi").AssumeFPS(24)
    # borre a fonte
    clip = source.Blur(1.58).Blur(1.58).Blur(1.58)
    # carregue o fundo para substituir, capturado da seqüência borrada,
    bgnd = ImageReader("bgnd.ebmp", 0, clip.framecount()-1, 24, use_DevIl=false)
    # carregue novo fundo
    new = ImageReader("new.ebmp", 0, clip.framecount()-1, 24, use_DevIl=false)
    # filtro integrado para produzir a máscara = (clip~overlay?)
    mask = OverlayMask(clip, overlay.ConvertToYV12(), 10, 10)
    MaskedMerge(source, new.ConvertToYV12(), mask, Y=3, U=3, V=3)

#### 9) K-mfToon

Eu preciso incluir mais info (urls/posts original) mas por ora eu penso que o autor do mfToon, mf (mf@onthanet.net) original não reagirá muito violentamente a isto, enquanto ainda não está enviado.
A produção da função no K-mfToon.avs deve ser idêntica à do mftoon.avs original (também incluída), com duas vezes a velocidade.
As exigências são:
- Para mfToon:
. carregar os plugins "MaskTools", "warsharp", "awarsharp"

## IV) TODO - a ser feito

Nada, tudo depende de avaliação.

## V) Retratação

Este plugin é liberado sob a licença GPL. Você tem que aceitar as condições em 'Copying.txt' antes de usar o plugin ou seu código fonte.
Você fica avisado também para usar isto em um estado de mente filantrópica, ou seja, "eu não manterei este segredo só para mim".
Último mas não menos, uma muito pequena parte de todos os possíveis usos de cada filtro foi testada (talvez 5% - ainda um par de horas gasto para depurar). Então, avaliação é muito_ bem vinda (o oposto, falta de avaliação - também é verdade...)

## VI) Revisões

1.5.1

- Complete rewritting of the documentation ( a huge thanks to Wilbert ).
- DEdgeMask now supports a float divisor. However, if the divisor is integer, it *should* be faster.
- DEdgeMask now has back its parameter "setdivisor", but it's only for backward compatibility with some scripts.
- YV12LUTxy : it's a new filter, implementing the idea presented by Didee on the previous post. The "y" symbol has the value of the collocated pixel in the second clip.

1.4.16

- Bugfixes : Logic "min" & "max" modes weren't properly working, it's corrected.
- Bugfixes : Logic & Subtract weren't using MMX & iSSE optimizations, due to a very silly bug. It's Corrected.

1.4.15.3

- RGBLUT added : works the same as YV12LUT ( except R, G and B replace Y, U and V ).
- In addition, you can specify an AMP file ( arbitrary color mapping file format from photoshop ).

1.4.15.2

- Bug finally solved on YV12LUT. Silly programming bug, as always...
- In YV12LUT, logical and relationnal operators added ( <, <=, >, >=, ==, !=, &, !&, |, ° ( xor ) )
- In YV12LUT, a ternary operator added : ? ( works as in C )

1.4.15.1

- In YV12LUT, another bug which was still preventing it from working fine. Hopefully, it should really work now.

1.4.15

- New Filter : HysteresyMask. It will allow you to build a new edge mask from two edge masks, one only having a few edges ( but we're sure they indeed are edges ), the other having two much edges ( due to a too low thresholding for example ). Look in the documentation to have further explanations.

1.4.14.2

- Several bugfixes concerning the behavior of negative values for Y, U and V ( edgemask, dedgemask, motionmask, combmask, logic )
- Several bugfixes concerning the use of offX / offY / w and h ( filters than can use it are : maskedmerge, binarize, expand, YV12subtract, yv12lut )
- In YV12LUT, a bug prevented to use it with some filter. It should work now.
- In YV12Convolution, float coefficients can be used now. If none is used, all the processing will take place with integer, so it will be faster than if you use a float. Moreover, if
  there is the possibility of overflow ( giving a result over 255 or under 0 ) during computation, a slower but safe function will be used to saturate computation to 0 and 255.

1.4.14.1

- Bugfix in YV12LUT to allow the use of negative numbers

1.4.14

- Bugfix : In YV12Layer, a useless test could prevent the filter to work. The test has been removed
- Bugfix : In DEdgeMask, threshold weren't taken into account. They are now
- Bugfix : Logic filter is now fully functionnal, in C and MMX
- Added : documentation to Logic filter
- Added : two modes for Logic : "Min" and "Max" ( C, MMX, iSSE )
- Added : In DEdgeMask, the possibility to set the normalization factor
- Corrected : documentation.

1.4.13

- Bugfix : One more, in the MotionMask ( the last row was not correctly computed )
- Optimizations : MaskedMerge gives now the same output in MMX and C, so MMX optimizations for it are back by default.
- Added : In EdgeMask, you now can use the laplace kernel. See the documentation on that filter
- Added : 'New' filter, DEdgeMask, which allows you to choose your kernel ( at a cost : speed )

1.4.12

- Behavior modifications : MotionMask and EdgeMask now also computes pixels on the borders mainly by extending the mask to these pixels.
- Bugfix : Inflate / Inpand / Expand / Deflate, when using negative parameters for y,u and v, some weird problems could occur.
- Added functionnality : In YV12LUT, the function abs is now defined.

1.4.11

- Bugfix : EdgeMask, MMX optimizations give different results. They are disabled by default. To activate them, use usemmx = true. They'll be used only with mod 16 resolution
- Bugfix : EdgeMask : first and last lines weren't always computed.
- Bugfix : MaskedMerge : MMX optimizations darken slightly the picture. They are disabled by default. To activate them, use usemmx = true. They'll be used only with mod 16 resolution.

1.4.10

- Bugfix : first and last lines were not correctly computed with inflate / deflate
- Invert is no longer a filter of the Masktools, it has been moved inside AviSynth.

1.4.9

- New filter : CombMask. As usual, read further for more documentation

1.4.8

- YV12Convolution now supports negative coefficients in the matrix. It allows to use the filter has an edge detecter.
- YV12Convolution has now a new parameter : bool saturate, which, if set to true, or if there is a possibility of getting out of the range [0..255] during calculation, clips each pixel into that range ( which means it's slightly slower )
- A new filter : LUT. Read further for more information on how to use it.

1.4.7

- Rename MotionDetection to MotionMask. I know it's kind of silly, but it's a lot more logical that way.
- Add the check of the width for the use MMX in MotionMask
- Slightly modify MMX optimizations in Binarize.
- Add a new filter : YV12Convolution. It allows you to convole the picture by a matrix of (almost) any size. Look further in the readme to learn how to use it

1.4.6

- Made the scenechange detection in MotionDetection iSSE optimized ( meaning you need an Athlon XP / Pentium IV ). It works with an Athlon XP, it is not tested with
  an Pentium IV, it is possible to disable it by using usemmx = false in the paremeters of the filter.
- Optimized the calculation of the motion, without using MMX ( just by avoiding to do 3 times the same calculations... ). So the filter should be more or less three times faster.

1.4.5

- Added MotionDetection filter, no MMX / assembler optimizations for it yet. Look further in the Readme to learn how to use it. It takes the idea of Sansgrip's filter (NoMoSmooth) and outputs the motion mask directly in the correct colorspace for the MaskTools.

1.4.4

- Reactivated MMX optimizations for MaskedMerge
- Came back to Kurosu's optimizations for Invert

1.4.3

- Made some MMX optimizations ( binarize, invert )
- Corrected some MMX optimizations ( which means mostly 'disabled some MMX optimizations' ). It should now work with P4.

1.4.2

- Fixed bugs concerning the inpand / expand / inflate / deflate functions

1.4.1

- Fixed the dreadly bug "multiple instances of a filter with different functions needed"

1.4.0

- Added an experimental LUT filter. Not tested, debug later.

1.3.0 (private version)

- Made usable the FitPlane function (still an overload of work when only one plane has to be resized) which was previously undocumented; therefore, added FastFitPlane functions (corresponding FitPlane ones should be useless now, except for the resizers settings)
- Allowed the specification of a processing area for many filters; however, this should not produce any noticable speed increase.
- Cleaned YV12Layer (in particular the unusable "Darken"/"Lighten" modes)
- Added OverlayMask, a function that compares 2 clips, and outputs a mask of the parts that are identical (slow and far from perfect).

1.2.0 (private version)

- YV12Layer: no more useless RGB32 conversion! Approximately the same as Arithmetic (except a third clip is not used), so that one is gone...
- YV12Substract: hey, why only a C version? Masks are really an underused feature of AviSynth |-[

1.1.0 (private version)

- Older inflate/deflate are renamed expand/inpand while newer functions replace them
- Logic and Arithmetic functions added (shouldn't produce the expected results because of no debugging)
- Edgemask now takes 4 thresholds (2 for luma and 2 for chroma). They are used for: setting to 0 or leaving as is a value depending on first threshold, setting to 255 or leaving as is a value depending on the second one.

1.0.2 (last version - public project dropped):

- Fix the shift for edgemask using sobel and roberts (misplaced MMX instruction)
- MaskMerge now works (mask cleared before being used... check with MaskMerge(clip3,clip3) for instance)

1.0.1: Initial release

## VII) Os Ensaios do Desenvolvedor

Volte ao V) se você não está interessado em desenvolver as ferramentas disponíveis.
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>

`$Date: 2006/03/26 18:11:53 $ Portuguese translation by RoLon`