2009-01-03
■ [実験][AviSynth][編集][補助]AviSynthで差分合成する

内容としては「 ダンスの背景飛ばし……? - にわかな奴の砂場 - ニコニコ部」の応用となる訳ですが、AviSynth標準フィルタだと何かと使い辛いので関数を書いてみたりしたので、拙作をぺたり。自分用のローカルライブラリですが、公開する事で何かの役に立つかもしれませんので。
mylib.avs
#####
### AviSynth用ローカル関数
#
#
# EARTHSOFTDV : AviUtl用のPV3/4のDVファイルローダを使って読み込む為の関数.
# ※WarpSharpパッケージが必要.(cf.http://www.avisynth.info/?warpsharp%A5%D1%A5%C3%A5%B1%A1%BC%A5%B8)
#
LoadAviUtlInputPlugin("C:\Program Files\EARTH SOFT\PV3 3.x\AviUtl\EARTH SOFT DV.aui", "EARTHSOFTDV")
#
# DiffMask : 2つのクリップの差分から生成した白黒256階調のクリップ(RGB32)を返す.
# ※VerticalCleanerが必要.(cf.http://www.avisynth.info/?niiyan%2F2008-02-27)
#
# s1, s2 … 差分抽出用のクリップ.同じ解像度である事が必要.
# tolerance … 差分の許容誤差.内部的にはColorKeyMask()のパラメータとして利用.
#
function DiffMask (clip s1, clip s2, int "tolerance") {
s1 = IsYUY2(s1) ? s1 : ConvertToYUY2(s1)
s2 = IsYUY2(s2) ? s2 : ConvertToYUY2(s2)
tolerance = default(tolerance, 0)
e = Overlay(s1, s2, mode="difference").ColorYUV(off_y=-128).ConvertToRGB32()
e = ColorKeyMask(e, $000000, tolerance)
e = e.ShowAlpha().VerticalCleaner().VerticalCleaner().Greyscale()
return e
}
#
# MaskedLayer : 前景にアルファチャネルを適用し,背景と重ねたクリップ(RGB32)を返す.
#
# bg … 背景となるクリップ.
# fg … 前景となるクリップ.アルファチャネルが適用される.
# mask … アルファチャネルとなるクリップ.基本的に白黒256色.
# ※3クリップとも同一の解像度である事が必要.
#
function MaskedLayer (clip bg, clip fg, clip mask) {
bg = IsRGB32(bg) ? bg : ConvertToRGB32(bg)
fg = IsRGB32(fg) ? fg : ConvertToRGB32(fg)
mask = IsRGB32(mask) ? mask : ConvertToRGB32(mask)
fg = Mask(ResetMask(fg), mask)
res = Layer(bg, fg, op="add")
return res
}
使用例

キュンキュンメガネと大正リボンを同時に付けてみると言う。これは以下のようなAviSynthスクリプトで合成しています。
#
# 大正リボンのクリップにキュンキュンメガネのクリップを合成してみる
# ※ColorItが必要.(cf.http://www.avisynth.info/?%B1%C7%C1%FC%B8%FA%B2%CC#bce2e312)
#
#外部スクリプトのインポート.同フォルダに置くか,或いはフルパス指定
Import("mylib.avs")
#大正リボンのクリップ
ribon=EARTHSOFTDV("ribon.dv")
#キュンキュンメガネのクリップ
megane=EARTHSOFTDV("megane.dv")
#セピアサングラスのクリップ
sepisan=EARTHSOFTDV("sepisan.dv")
#メガネとセピサンの差分からマスク作成
mask=DiffMask(megane, sepisan)
#穴が埋まるまでマスクを膨張させる
mask=mask.Morpher(type="dilate").Morpher(type="dilate").Morpher(type="dilate").Morpher(type="dilate").Morpher(type="dilate").VerticalCleaner()
#穴が埋まったらマスクを収縮させる.ついでにエッジぼかし
mask=mask.Morpher(type="erode").Morpher(type="erode").Morpher(type="erode").Morpher(type="erode").Morpher(type="erode").Blur(1)
#目元を合成
MaskedLayer(ribon, megane, mask).ConvertBackToYUY2()
リボンの動画にメガネの動画の目元部分だけを重ねる為、メガネとセピアサングラスの動画差分を利用してマスクを作っていますが、そのままだと穴ぼこだらけで使えないので、ColorItプラグインのフィルタMorpher()で穴を埋めています。
こんな感じ。で、後はこのマスクをメガネ動画のアルファチャネルとして適用し、リボンの動画と重ねてめでたく完成。1アングル作る為に3本録らなきゃいけないので時間も保管容量もバカになりません。それに加えて合成処理の遅い事と言ったら、8000フレームの処理が大体30分くらい。全自動なんで放っておけばいい訳でもありますが。
複数のアクセサリを合成する場合は同様の手順を重ねればいいだけですが、重ねて不自然の無い順番を探すのは結構めんどくさいです。*1
nukIM@S-2使えばいいんじゃね?
Exactly.
コメントを書く
