mojimoji 関数: テキストの移動と拡大縮小
SubtitleとAnimateを組み合わせてテキストを移動させるでは、Subtitle と Animate を組み合わせて、テキストを移動させたり、拡大縮小させたりする方法を紹介しました。
その方法では引数の指定が面倒だったので、今回、これを関数化してみました。名付けて、mojimoji 関数。
ダウンロード
mojimoji 関数のダウンロード(2008-04-08 更新)
シンタックス
mojimoji
mojimoji(clip input, string moji, int start, int end, int x1, int y1, int "x2", int "y2", int "size",
\ string "font", int "text_color", int "halo_color", int "size2", int "lsp")
mojimojiOvr
mojimojiOvr(clip input, string moji, string "fx", string "fy", string "fopacity", string "fzoom",
\ int "size", string "font", int "text_color", int "halo_color", int "x", int "y", float "opacity")
パラメータ
共通
- input: ビデオクリップ。
- moji: 表示するテキスト。
- size: テキストの標準サイズ。
- font: 使用するフォント。
- text_color: テキストの色。
- halo_color: テキストの縁の色。
mojimoji のみ
- start: 開始フレーム。
- end: 終了フレーム。
- x1: start 時点におけるテキストの x 座標。
- y1: start 時点におけるテキストの y 座標。
- x2: end 時点におけるテキストの x 座標。
- y2: end 時点におけるテキストの y 座標。
- size2: end 時点におけるテキストのサイズ。拡大縮小時のみ指定。
- lsp: 行間の高さ。Subtitle の同名パラメータに相当。
mojimojiOvr のみ
- fx: Overlay フィルタの ol_x_offset を定義した ConditionalReader 形式のファイル。
- fy: Overlay フィルタの ol_y_offset を定義した ConditionalReader 形式のファイル。
- fopacity: Overlay フィルタの ol_opacity_offset を定義した ConditionalReader 形式のファイル。
- fzoom: 文字サイズを定義した ConditionalReader 形式のファイル。
- x: テキストの x 座標。fx を使わず、位置を固定したい場合に指定。
- y: テキストの y 座標。fy を使わず、位置を固定したい場合に指定。
- opacity: 不透明度。fopacity を使わず、不透明度を固定したい場合に指定。
mojimoji.avs 内で設定可能な global 変数
mojimoji.avs の中で、以下の global 変数の値を設定/変更することができます。
# デフォルト値の指定
global mojimoji_text_color = $000000 # フォントの色
global mojimoji_halo_color = $EFEFEF # 文字の縁、および、文字を重ねるクリップの背景色
global mojimoji_font = "MS Pゴシック" # フォント
global mojimoji_size = 18 # フォントの大きさ
global mojimoji_lsp = 0 # 複数行表示時の行間の大きさ(-1 なら常に 1 行として扱う)
global mojimoji_mask_tolerance = 10 # マスクの許容度(大きくするほど、より多くの色を透過色とみなす)
font_color, halo_color, font, size, lsp を省略した場合には、上の 4 つの値がそれぞれ適用されます。最後の mojimoji_mask_tolerance は同じ色とみなす許容範囲を指定する。ColorKeyMask の tolerance パラメータに相当。
使用例
mojimoji
# 関数定義ファイルのインポート
Import("mojimoji.avs")
# ソースクリップ
BlankClip(100, 320, 240, fps=15, color=mojimoji_halo_color)
# 右から左へ
mojimoji(" ∧∧\n ┃ ┏━┃ (,,゚∀゚) ┃┃\n ━┏┛ ┏━┃ ━━/ つ━━┛ .┃┃\n ━┏┛ ┛ ┃ ~( ,ノつ ┛┛\n ┛ ┛ (/ .┛┛", 0,24, 320,80, -320,80)
# 下から上へ
mojimoji(" ∧∧\n ┃ ┏━┃ (,,゚∀゚) ┃┃\n ━┏┛ ┏━┃ ━━/ つ━━┛ .┃┃\n ━┏┛ ┛ ┃ ~( ,ノつ ┛┛\n ┛ ┛ (/ .┛┛", 25,49, 0,240, 0,-240)
# 拡大
mojimoji(" ∧∧\n ┃ ┏━┃ (,,゚∀゚) ┃┃\n ━┏┛ ┏━┃ ━━/ つ━━┛ .┃┃\n ━┏┛ ┛ ┃ ~( ,ノつ ┛┛\n ┛ ┛ (/ .┛┛", 50,98, 150,120, -400,-40, 1, size2=64)
zoome動画: mojimoji.avs サンプル動画 1: mojimoji - niiyan X zoome
mojimojiOvr
# 関数定義ファイルのインポート
Import("mojimoji.avs")
# ソースクリップ
BlankClip(100, 320, 240, fps=15, color=mojimoji_halo_color)
# mojimojiOvr 関数
mojimojiOvr("キタ━(゚∀゚)━!", "xoffset.txt", "yoffset.txt", "opacity.txt", "zoom.txt")
※注: "xoffset.txt", "yoffset.txt", "opacity.txt", "zoom.txt" は、サンプルとして mojimoji.avs に同梱されています。
zoome動画: mojimoji.avs サンプル動画 2: mojimojiOvr - niiyan X zoome
関連記事
更新履歴
- 2005-10-22: 初版。
- 2007-10-23: ZIP 形式で圧縮したものに差し替え。内容は変更なし。
SubtitleとAnimateを組み合わせてテキストを移動させる
2008-04-08 追記: この方法には問題があります。詳しくは、Subtitle フィルタにとって -1 は魔法の値を参照してください。
にーやんのブログ :: Project N: 024 - 文字雨(Animateフィルタを使う)のように、Subtitle フィルタと Animate フィルタを組み合わせれば、テキストを移動させたり、拡大縮小したりすることができます。簡単な例をあげながら、これをもう少し説明したいと思います。
# ソースクリップ
BlankClip(200, 320, 240, fps=29.97)
BlankClip フィルタを使って空のクリップ(200frames, 320x240, 29.97fps)を作成します。今回は、これをソースクリップとして使用します。
font = "MS Pゴシック" # フォント
size = 36
text_color = color_lightpink # フォントの色($FFB6C1)
halo_color = color_hotpink # 文字の縁の色($FF69B4)
フォントの色や大きさなどを指定しておきます。フィルタの中で直接指定してもOKです。その場合は、下記のスクリプトの font, size, text_color, halo_color となっているところを変更します。
color_lightpink と color_hotpink は、AviSynthで使用出来る色のプリセットです。プリセット値は、AviSynth と一緒にインストールされる colors_rgb.avsi(plugins フォルダの中にあります)の中で設定されています。colors_rgb.avsi は、オートローディング機能で、自動的に読み込まれます。10 進数か 16 進数を使って指定してもかまいません。
# 右から左へ移動
Animate(0, 29, "Subtitle",
\ "キタ━(゚∀゚)━!",320,100,0,29,font,
\ "キタ━(゚∀゚)━!",-200,100,0,29,font)
Subtitle フィルタの引数のうち、x だけが変化していることに注意してください。0 フレームのときは x = 320、29 フレームのときは x = -200 の位置に配置されます。日本語(2バイト文字)なので、それに対応しているフォントを指定する必要があります。
# 下から上へ移動
Animate(30, 59, "Subtitle",
\ "萌えーっ!!",70,240,30,59,font,size,text_color,halo_color,
\ "萌えーっ!!",70,-50,30,59,font,size,text_color,halo_color)
今度は y の値だけが変化しています。
# 拡大
Animate(60, 89, "Subtitle",
\ "萌えーっ!!",160,120,60,89,font,1,text_color,halo_color,
\ "萌えーっ!!",-40,80,60,89,font,96,text_color,halo_color)
size を変化させることで、テキストの拡大や縮小も可能です。ただし x と y を固定にすると、左上から右斜め下へと拡大(縮小の場合は、その逆)するように見えてしまいます。これを防ぐために、x と y の値も変化させています(適当)。
Subtitle フィルタには、テキストの配置に関する align という引数もあります。今回は align は使用しませんでしたが、これを組み合わせてみてもいいかもしれません。
# 左上から右下へ移動
Animate(90, 159, "Subtitle",
\ "/⌒ヽ ちょっと通りますね",-200,0,90,159,font,16,$FFFFFF,$000000,
\ "/⌒ヽ ちょっと通りますね",350,150,90,159,font,16,$FFFFFF,$000000)
Animate(90, 159, "Subtitle",
\ "/ ´_ゝ`)",-210,18,90,159,font,16,$FFFFFF,$000000,
\ "/ ´_ゝ`)",340,168,90,159,font,16,$FFFFFF,$000000)
Animate(90, 159, "Subtitle",
\ "| /",-210,36,90,159,font,16,$FFFFFF,$000000,
\ "| /",340,186,90,159,font,16,$FFFFFF,$000000)
Animate(90, 159, "Subtitle",
\ "| /| |",-208,54,90,159,font,16,$FFFFFF,$000000,
\ "| /| |",342,204,90,159,font,16,$FFFFFF,$000000)
Animate(90, 159, "Subtitle",
\ "// | |",-216,72,90,159,font,16,$FFFFFF,$000000,
\ "// | |",334,222,90,159,font,16,$FFFFFF,$000000)
Animate(90, 159, "Subtitle",
\ "U .U",-222,90,90,159,font,16,$FFFFFF,$000000,
\ "U .U",328,240,90,159,font,16,$FFFFFF,$000000)
x と y の両方を変化させることで、斜め方向への移動も可能です。
# 上から下へ移動
Animate(160, 199, "Subtitle",
\ "萎え . . . orz",70,-50,160,199,font,36,color_olivedrab,
\ "萎え . . . orz",70,240,160,199,font,36,color_olivedrab)
これは下から上への移動の逆です。
FadeOut(30)
最後はフェードアウト。
これを 1 つの AVSファイルにまとめて、MPEG-1 形式の動画に変換してみました。
あまりなめらかとは言えないかもしれませんが、一応、動いています。
Project N: 024 - 文字雨(Animateフィルタを使う)
関数化することによって、1 行で文字の縦書き(みたいなの)が可能になりました。
しかし、これだけでは不十分です。なぜなら、縦書き文字列を動かす(動いているように見せる)ためには、以下のように一部のパラメータの値を変化させたコマンドを、いちいち書かなければならないからです。
# Import("tategaki.avs") # インポートする場合
bg = BlankClip(width=320, height=240)
bg.tategaki(4, 0, 0, 0, "A", "B", "C", "D", "E")
tategaki(4, 10, 1, 1, "A", "B", "C", "D", "E")
tategaki(4, 20, 2, 2, "A", "B", "C", "D", "E")
return last
上のスクリプトをよく見ると、使っている関数は自作の tategaki 関数だけで、y, start, end の 3 つの値だけが一定の割合で変化していることがわかります。
AviSynth には、このようにパラメータが連続的に変化する同一のフィルタ(関数)を評価するメタフィルタがあります。それは、Animate フィルタです。
Animate フィルタの書式と引数
Animate(clip clip, int start_frame, int end_frame, string filtername, start_args, end_args)
- start_frame: 開始フレーム。
- end_frame: 終了フレーム。
- filtername: 評価するフィルタ(または関数)。
- start_args: start_frame 時の filtername の引数。
- end_args: end_frame 時の filtername の引数。
start_frame と end_frame の中間のフレームでは、引数は補間されます。
Animate フィルタを使ってみる

start_frame と end_frame のときに、それぞれ上の図の位置に文字が来るようにしてみます。このとき、start_frame では y = 0、end_frame では y = 170 です。
# Import("tategaki.avs") # インポートする場合
bg = BlankClip(width=320, height=240)
Animate(bg, 0, 29, "tategaki", 4,0,0,0,"A","B","C","D","E", 4,170,29,29,"A","B","C","D","E")
return last
start_frame = 0, end_frame = 29 とすると、スクリプトは上記のようになります。
Animate(0, 29, "tategaki", bg,4,0,0,0,"A","B","C","D","E", bg,4,170,29,29,"A","B","C","D","E")
Animate フィルタは、このように記述することもできます。
サンプル動画
上記のスクリプトを、MPEG-1 形式の動画に変換してみました(30 フレーム以降をカットし、音声なしにしてあります)。
文字が上から下へと移動していると思います。ようやく形が見えてきました。
CopyFieldCond関数(2): フィルタ適用前のフィールドと置換可能に
CopyFieldCond 関数を少しいじってみました。
前回のスクリプトは CopyField 関数の拡張版ということで、あるフィールドを別のフィールドに置き換えるものでした。今回の修正で、フィルタ適用後のあるフィールドをフィルタ適用前の別のフィールドに置き換えることができるようになりました・・・たぶん。
そもそも前のバージョンがちゃんと動くかどうかもわからない状態なので、今回のも意図したとおりに動作しない可能性があります。よって動作無保証です。
CopyFieldCond関数(改)
function CopyFieldCond(clip clip, string logfile, bool "debug", bool "show_result", string "filter")
{
# デフォルト値などの指定
debug = default(debug, false) # debugのデフォルトはfalse
show_result = default(show_result, false) # debugのデフォルトはfalse
filter = default(filter, "") # filterのデフォルトは""
global FreezeThis = -1 # これは変更しないこと
global video = clip.SeparateFields() # フィールド分離
# filter指定があればfilterを適用してフィールド分離、さもなければvideo
filtered = (filter != "") ? Eval("clip." + filter).SeparateFields() : video
# debug==true&show_result==falseの場合: フレーム番号の表示
video = ((debug == true) && (show_result == false)) ?
\ video.ScriptClip("Subtitle(String(current_frame))") : video
# ScriptClip: フレームごとに評価
copy = video.ScriptClip("FreezeFrame(current_frame, current_frame, FreezeThis)")
# ConditionalFilter/ConditonalReader: FreezeThisが-1より大きいならcopyから取る
ConditionalFilter(video, copy, filtered, "FreezeThis", ">", "-1")
ConditionalReader(logfile, "FreezeThis", false)
# debug==true&show_result==falseの場合: フレーム番号の表示
((debug == true) && (show_result == true)) ?
\ ScriptClip("Subtitle(String(current_frame))") : last
# debug==trueの場合: 各フィールドを選択
even = ((debug == true) && (show_result == false)) ? video.SelectEven() :
\ ((debug == true) && (show_result == true)) ? SelectEven() : NOP
odd = ((debug == true) && (show_result == false)) ? video.SelectOdd() :
\ ((debug == true) && (show_result == true)) ? SelectOdd() : NOP
# debug==trueなら2画面分割表示、さもなければWeave
(debug == true) ? StackVertical(even, odd) : Weave()
}
使用例1: 通常モード(フィルタなし)
CopyFieldCond("CopyFields.txt")
前回と同じ。
使用例2: デバッグモード(フィルタなし/フィールド入れ替え前)
CopyFieldCond("CopyFields.txt", true) # または debug=true
前回と同じ。
!デバッグモード(フィルタなし/フィールド入れ替え前)
大きい画像
使用例3: デバッグモード(フィルタなし/フィールド入れ替え後)
CopyFieldCond("CopyFields.txt", true, true)
!デバッグモード(フィルタなし/フィールド入れ替え後)
大きい画像
「show_result=true」なら入れ替え後の状態を表示(debug=true 時のみ)。
使用例4: 通常モード(フィルタあり)
CopyFieldCond("CopyFields.txt", filter="GreyScale()") # filter=でフィルタ指定
使用例5: デバッグモード(フィルタあり/フィールド入れ替え前/フィルタ適用前)
CopyFieldCond("CopyFields.txt", true, filter="GreyScale()")
使用例2と同じ。
使用例6: デバッグモード(フィルタあり/フィールド入れ替え後/フィルタ適用後)
CopyFieldCond("CopyFields.txt", true, true, "GreyScale()")
!デバッグモード(フィルタあり/フィルタ適用後)
大きい画像
(追記)フィルタ(filter)はフィールド分離前のクリップに適用されます。
CopyFieldCond関数: ConditionalFilterを利用したCopyField拡張版
昨日あたりから、2ちゃんねる DTV 板の Avisynth スレッドで、「あるフィールドを別のコピーしたフィールドに入れ替える方法」に関する話題が出ていたので、HowToApplyFilterToManySingleFrames を使って CopyField 関数の拡張版を作ってみました。
HowToApplyFilterToManySingleFrames は、ConditionalFilter と ConditionalReader を使って、たくさんの単一フレームにフィルタをかけるテクニックです(AviSynth 開発者の sh0dan 氏が提案したもの)。にーやんのブログ :: HowToApplyFilterToManySingleFrames でも紹介していますので、参考にしてください。
CopyFieldCond関数
function CopyFieldCond(clip clip, string logfile, bool "debug")
{
# デフォルト値などの指定
global video = clip.SeparateFields() # フィールド分離
global FreezeThis = -1 # これは変更しないこと
debug = default(debug, false) # debugのデフォルトはfalse
# debug==trueの場合: フレーム番号の表示と各フィールドの選択
video = (debug == true) ? video.ScriptClip("Subtitle(String(current_frame))") : video
even = (debug == true) ? video.SelectEven() : NOP
odd = (debug == true) ? video.SelectOdd() : NOP
# ScriptClip: フレームごとに評価
copy = video.ScriptClip("FreezeFrame(current_frame, current_frame, FreezeThis)")
# ConditionalFilter/ConditonalReader: FreezeThisが-1より大きいならcopyから取る
ConditionalFilter(video, copy, video, "FreezeThis", ">", "-1")
ConditionalReader(logfile, "FreezeThis", false)
# debug==trueなら2画面分割表示、さもなければWeave
(debug == true) ? StackVertical(even, odd) : Weave()
}
使い方
1.ログファイル(例: CopyFields.txt)を作成。ログファイル内には、以下の 2 行を記述。
type int
default -1
2.CopyFieldCond を debug モードで使用。debug モードでは、フィールド別に上下 2 画面表示になり、各フィールドの番号が表示されます。
# 例
AviSource("foo.avi") # ソース
AssumeFrameBased().ComplementParity() # フィールドオーダーの指定
CopyFieldCond("CopyFields.txt", true) # debug=trueならdebugモード
3.「コピー先フィールドNo コピー元フィールドNo」の形式で、ログファイルに追記していく。
# 例
type int
default -1
2 4
4 6
4.debug モードを解除。
AviSource("foo.avi") # ソース
AssumeFrameBased().ComplementParity() # フィールドオーダーの指定
CopyFieldCond("CopyFields.txt") # または CopyFieldCond("CopyFields.txt", false)
使用例
- オリジナル:

- debug モード:

- フィルタ適用後:
補足
簡単な動作テストはしていますが、いつものように動作無保証です。ログファイルを作成する手間などを考えると、あまり実用的とは言えないかもしれません。
範囲指定も可能です(正常に動作するかどうかは別にして)。範囲指定したい場合は、ログファイルに次のように記述します。
# 1~2フィールドを3フィールド目に置き換える
R 1 2 3
# 4~5フィールドを5~6フィールドに置き換える
I 4 5 5 6
オリジナルの CopyField 関数は、アーカイブ: 旧AviSynthのぺーじにあります。徐々にではありますが、このページにあるユーザー定義関数についても、AviSynth Wiki へ移行させていきたいと考えています。
(追記)にーやんのブログ :: CopyFieldCond関数(2): フィルタ適用前のフィールドと置換可能にに新しいバージョンを掲載しています。



