2016年1月20日水曜日

mt_yrangemask

お久しぶりです。

potatosubさんのブログ読んでたら、yrangemaskなるフィルタを使っているのに気づきました。

わたくし、このフィルタはこれまで知らなかったんですが、ちょっと気になったことがあったので実験してみました。

#test.avs
LoadPlugin("yrangemask.dll")
LoadPlugin("masktools2.dll")

#1920x1080のグラデーション画像10000フレーム
BlankClip(length=10000, width=1920, height=1080, pixel_type="YV12")
mt_lutspa(mode="relative", expr="x 256 *", chroma="128")

#yrangemask(16, 4, 80, 16, true)
mt_yrangemask(16, 4, 80, 16, true)

function mt_yrangemask(clip clip, int "min_y", int "fade_min_y", int "max_y", int "fade_max_y", bool "invert")
{
    assert(clip.IsPlanar(), "clip is not planar format")
    min = default(min_y, 0)
    max = default(max_y, 0)
    assert(min >= 0 || min < 256 || max < 256, "Specify in the range from 0 to 255")
    assert(min <= max, "min_y must be less than or equal to max_y")
    fmin = default(fade_min_y, 0)
    fmax = default(fade_max_y, 0)
    assert((fmin + fmax) <= (max - min), "'fade_min_y + fade_max_y' should be less than or equal to 'max_y - min_y'")

    min = string(min - 1)
    max = string(max + 1)
    fmin = string(fmin + 1)
    fmax = string(fmax)
    invert = default(invert, false)

    #expr = 255 / (x < max - fmax ? fmin / (x - min) : (fmax + 1) / (max - x))
    #expr = invert ? 255 - expr : expr
    expr = "255 / (x < " + max  + " - " + fmax + " ? " + fmin + " / (x - " + min + ") : (" + fmax + " + 1) / (" + max + " - x))"
    expr = (invert ? "255 - " : "") + expr

    return clip.mt_lut(mt_polish(expr), chroma="0")
}
で、
$ for i in {1..3}; do avs2pipemod -benchmark test.avs; done

     yrangemask   mt_yrangemask 
 1   303.556fps    889.047fps
 2   300.232fps    890.155fps
 3   301.298fps    891.027fps
------------------------------------
avg  301.695fps    890.076fps

やはり気のせいではなかったようです。

mt_lutは起動時にあらかじめxが0から255までの256パターンの計算を行いLUT(ルックアップテーブル)を作るため、実行中の処理スピードは式がどれだけ複雑になっても変わりません。
LUTのサイズは256バイトですから、L1キャッシュに収まるため高速です。
逆ポーランド記法もmt_polishを使えば覚えなくて済むので、積極的に使ってみることをお勧めします。

追記:2016/01/21 mt_lutの式を簡略化 & invert=trueの場合をちょっと高速化