周期不定のOPEDを間引こう(24不定編)
24不定編ってことはフレームレート不定編もあるんですかね、しらんけど
お手軽だと思われる24不定の処理方法を書いてみます。
24fps素材を30のインターレースな素材にすることをテレシネというのですがそのテレシネを元に戻す逆テレシネ≠インターレース解除を紹介します。
そもそもテレシネや逆テレシネはなんぞやって方は、いい説明をしているサイトさんがたくさんあるのでこのあたりをみるのがオススメです
にわとり遊び テレシネと逆テレシネについて
エンコ入門 – フィールドを選択して逆テレシネ化 (1) – エンコ
エンコ入門 – フィールドを選択して逆テレシネ化 (2) – エンコ
エンコ入門 – フィールドを選択して逆テレシネ化 (3) – エンコ
ここでは間引くだけなので関係ないんですけれども大体24コマ/秒は厳密には24000/1001と割り切れない値なので24000/1001fps、おおよそ23.976…fpsと24fpsは”別物”と考えてください。そのぐらいの誤差は別にええやろって思うと思わぬフレームドロップまたはフレーム重複、最悪の場合音ずれ等に発展します。逆テレシネも間違えれば音ずれ等が発生します。
またIT()などの逆テレシネプラグインとかits等では簡略化して24となっていることがありますがそちらは例外なのでよーくその辺の仕様を確認してから判断した方がいいです。
AviSynthの導入自体は結構書いてあるのでググりましょう。オススメはAviSynth+の最近のビルドまたはAviSynth NEOの最終ビルドの64Bit版です。最近ではフィルターが重くてメモリが枯渇気味になるので余程の理由がなければ64Bit版の導入をお勧めします。
インストールしてavsPmodで逆テレシネしたいソースが読み込める状態までプラグインを入れてあれば準備完了です。
こちらがスクリプト記述となっています。#から始まる行はコメントアウト部分なので気にしなくて構いません。またスクリーンショット内に記述があってもこちらに書いてない物はここではそこまで関係ない物ですので記述をしていません。
#Src
src=("F:\\犬夜叉 #01 (20200701 CTC).d2v")
audiosrc=("F:\\犬夜叉 #01 (20200701 CTC) PID 112 DELAY -303ms.aac")
MPEG2Source(src)
audiodub(aacfaw(audiosrc))
私はこの場合は、映像デコードにDGIndex+MPEG2DecPlusを、音声デコードはaacfawを使用しています。
MPEG2ソースでしたらDGIndexが安定してデコード出来るのでバイナリをビルドできる方には非常にオススメです。
プレビューが正常に出来ているならば準備はOKですので、逆テレシネしたい部分をTrim関数でカットします。
Trim(43784,46629)
最初及び最終フレームで前後の映像が混ざったインターレースの縞がでてしまった場合はカットするなり残してどうしてもだめそうなら後で切る、等をします。ソースや作業者によって異なる部分ではあるのでお好みで。今回は最終フレームが縞となってしまい、そのままやったところ片フィールドという縦解像度が半分な状態になってしまったので潔くカットしました。
後は録画TS等ではウォーターマーク削除等ありますがここでは関係ないので割愛します。気になる方はググって逆テレシネ前に処理をして置いてください。今回は映像と被らない上に該当部分はクロップしてしまうので処理をしません
犬夜叉 ED1 – アニメのOP/EDの情報
このサイトさんは話数による差分だけではなく、旧作のOPED周期の処理が書いてあるので、参考になると思います。
今回はまんま同じソースの記述が書いてありますので、このまま入力しても良いのですが、書いてない物がメインとなっていきますので、判定及び逆テレシネの方法を書いていきたいと思います。
判定には以下の関数を使用します。下のスクリプトを入力したテキストファイルの拡張子をavsiにしてAviSynthのpluginsフォルダに入れておいてください。(64Bit版ならplugins64へ)
function Pulldown5(clip clip, int "mode" , int "mt",int "th") {
mode=Default(mode,0)
Assert(0<=mode&&mode<=5, "Error. Invaid ModeNumber")
#
mode01=clip.DoubleWeave().Pulldown(2,4)
mode02=clip.DoubleWeave().Pulldown(1,4)
mode03=clip.DoubleWeave().Pulldown(1,3)
mode04=clip.DoubleWeave().Pulldown(0,3)
mode05=clip.DoubleWeave().Pulldown(0,2)
# View
view=ShowFiveVersions( \
mode01.CombCheck().SubTitle("IPPPI (mode=1)",size=96), \
mode02.CombCheck().SubTitle("IIPPP (mode=2)",size=96), \
mode03.CombCheck().SubTitle("PIIPP (mode=3)",size=96), \
mode04.CombCheck().SubTitle("PPIIP (mode=4)",size=96), \
mode05.CombCheck().SubTitle("PPPII (mode=5)",size=96)).\
reduceby2()
clip_merge= mode!=0 ? \
(mode!=1?(mode!=2?(mode!=3?(mode!=4?(mode!=5?(nop()): \
(mode05)):(mode04)):(mode03)):(mode02)):(mode01)):(view)
return clip_merge
/*
Combcheck
Original:http://sasamisi.blog24.fc2.com/blog-entry-301.html
2020-03-13 Change use CombMask from Masktools(v1))
*/
function Combcheck (clip clip) {
clip=mt_merge(Grayscale(clip),ColorYUV(Grayscale(clip),gain_u=100,gain_v=100),CombMask(clip,cthresh=16,mthresh=0,chroma=false),luma=true)
return clip
}
Pulldown5という関数はpotatosubさんのPulldownMerge(PulldownMerge関数 (11/13 17:28更新) – エンコ)などを参考にしました。またCombMaskはこちらから(Ch’s barn: CombMask)、mt_mergeは(Releases · pinterf/masktools)からDLできます。
周期一定でしたら先ほどの映像が出るところまで作業したavsPmodに記述したスクリプトにpulldown5()と次の行に入れてプレビューをみて紫のコーミングノイズが出てないのを番号を選択してあげればおしまいです。が、今回はそうではないので、pulldown5の記述前にフレーム番号を表示させてあげます。
(省略)
Showframenumber(size=64)
pulldown5()
このような形となるので、出ているフレーム番号を参考に間引いていきます。
作業中は
(省略)
Showframenumber(size=64)
/*Trim(0,573).pulldown5(4)+\
Trim(574,677).pulldown5(4)
*/
Trim(678,0)
pulldown5()
みたいな感じでコメントアウト部分を作って(/*ほげほげ*/みたいな感じでコメントアウト出来ます)書いていって周期がずれたところでTrimで切り直して見分けての繰り返しをしていきます。
今回は最終的には以下のような感じになりました。
Trim(0,573).pulldown5(4)+\
Trim(574,677).pulldown5(4)+\
Trim(678,678).onCPU(2).KTGMC("slower").onCUDA(2).selecteven().Assumefps(24000,1001)+\
Trim(679,2041).pulldown5(1)+\
Trim(2042,2257).pulldown5(1)+\
Trim(2258,2258).onCPU(2).KTGMC("slower").onCUDA(2).selecteven().Assumefps(24000,1001)+\
Trim(2259,2546).pulldown5(1)+\
Trim(2548,0).pulldown5(1)
最後のTrimの後ろを0にすると最終フレームを選択したことになります。
Trim(678,678).onCPU(2).KTGMC("slower").onCUDA(2).selecteven().Assumefps(24000,1001)+\
の用に1fだけ別の関数が指定されていますが、これは片フィールドになってしまった部分をこのような形で補完しています。bob化してから片方のフレームを選択してるような形です。今回はKTGMCを仕様していますがTDeintでもQTGMCでもお好みなのを使えば良いと思います。
この場合はまずonCPU(2).KTGMC(“slower”).onCUDA(2)でKTGMCを使用してBob補完をしています。これではフレームが2フレームに水増しされるのでお好みのフレームを取ります。ここで2フレーム拾いたいなら48fpsで処理すべきなのかな?(ここは未検証)、今回は24fpsの不定として処理しますので1フレームだけ選びますSelectEven()で先のフレーム、SelectOdd()で後ろのフレームを選べます。今回はSelectEven()で先のフレームを取りました。
最後にフレームレート指定しているのはKTGMC等のBob補完プラグインでは60fps(ここでは60000/1001を指します)として処理がされますが、今回は24fpsのフレームとして処理をしたいので強制的にフレームレートを指定してあげます。
ちなみに60fpsのままだとフレームレートを混在させることが出来ないAviSynthではエラーとなってしまうので忘れたら出ると思います。
ちなみに、SelectField()みたいに片フィールド補完フィルターもあるのでこういう記述をせず
Trim(574,678).pulldown5(4).selectfield(83)+\
の用にすることも出来ます。正直こちらがお手軽だと思うのでお好みでどうぞ。
これで、逆テレシネ自体は完了ですが、字幕が片フィールドになってしまい、縞が残る場合があるのでこちらを処理します。
こちらもselectfield()でもいいのですが、これではフレーム全体が片フィールド補完になってしまいますのでpointbobを該当フレームだけ適用するのが良いと思います。
Applyrange(524,524,”Pointbob”)でもいいですし
function PointBob2(clip clip, int num, int "thr") {
fc=clip.framecount-1
thr=default(thr,9)
global thr=thr
BOBCLIP=clip.OnCPU(2).KFMDeint(preset="slower",cuda=true,nr=true).OnCUDA(2).SelectOdd().Trim(num,-1)
clip2=clip.Trim(num,-1)
mask=clip2.mt_edge(mode="laplace").mt_binarize().mt_expand()
last=ConditionalFilter(clip2, mt_merge(clip2,BOBCLIP,mask),clip2,"IsCombedTIVTC(thr,thr)", "=", "TRUE")
T2= ConditionalFilter(clip2,BOBCLIP,last,"IsCombedTIVTC(thr,thr)", "=", "TRUE")
T1=clip.Trim(0,num-1)
T3=clip.Trim(num+1,0)
return (num>=fc)?T1++T2:(num>0)?T1++T2++T3:T2++T3
}
の用に1fだけ適用するように改変したPointbob2を使うのも良いと思います。私は後者を使用しています。
最終的にはこのような形になりました。
#ソース読み込み
src=("F:\\犬夜叉 #01 (20200701 CTC).d2v")
audiosrc=("F:\\犬夜叉 #01 (20200701 CTC) PID 112 DELAY -303ms.aac")
MPEG2Source(src)
audiodub(aacfaw(audiosrc))
#CMカット
Trim(43784,46629)
#逆テレシネ
Trim(0,573).pulldown5(4)+\
Trim(574,677).pulldown5(4)+\
Trim(678,678).onCPU(2).KTGMC("slower").onCUDA(2).selecteven().Assumefps(24000,1001)++\
Trim(679,2041).pulldown5(1)+\
Trim(2042,2257).pulldown5(1)+\
Trim(2258,2258).onCPU(2).KTGMC("slower").onCUDA(2).selecteven().Assumefps(24000,1001)++\
Trim(2259,2546).pulldown5(1)+\
Trim(2548,0).pulldown5(1)
#テロップ補完
pointbob2(524)
pointbob2(705)
pointbob2(709)
pointbob2(1170)
pointbob2(1430)
pointbob2(1893)
#片フィールド補完
selectfield(1269)
これで逆テレシネ自体は終了なのでフィルター処理をするなり、このままエンコーダーに投げつけるなりお好みで処理してみてください。
ね?簡単でしょ?(これが一番言いたかった)