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.
Este plugin YV12 do Avisynth 2.5 oferece várias funções que manipulam clipes como máscaras:
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:
Um último ponto é a habilidade de algumas funções para processar só uma parte da armação:
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.
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
(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
(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):
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
(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):
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:
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 |
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".
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
(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
(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
(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
(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.
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".
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:
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
(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
(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
(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.
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
(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.
Padrões são: tol = -1 e widerange = false.
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, ...).
# 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)
Substitua EdgeEnhancer por um softener espacial (borrado em cascata? spatialsoftenMMX?) e use upper=true para selecionar píxeis planos próximos.
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)
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
Não testado
. Aplique warpsharp - > clip2 (píxeis de substituição) . Crie um filtro segurando ou um de contorno baixo luma - > clip3 (máscara)
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)
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)
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)
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"
Nada, tudo depende de avaliaçã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...)
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
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