Photo Gallery

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
この記事は DTV Advent Calendar 2015 に登録させて頂きました。


とうとうカレンダーの予約が途切れていたので、即席の小ネタですが…
前回の記事 で触れた、差分を吸収してブレンドする関数の応用ライブラリです。


使い方

DiffMerge(clip1, clip2)

clip1 と clip2 をブレンドし、差分箇所は clip2 が使用されます。


DiffMerge(clip1, clip2, debug=true)

差分のマスクを表示します。


# 透過率コントロールを OFF にする
DiffMerge(clip1, clip2, debug=true, transctrl=false)

# 前回記事でも紹介したマスク生成
a=mt_makediff(clip1, clip2, U=-128, V=-128)
b=mt_makediff(clip2, clip1, U=-128, V=-128)
mt_logic(a, b, mode="or")

この二つは同じ結果になります。


trans_control(mask, padding_range=8, fade_range=0)

trans_control.png

mask_ab+ba.png

trans_control は、画像のようなマスクに対して、透過率の調整を行う関数です。
DiffMerge 関数の内部で使用しているので、同パラメータが DiffMerge からも呼び出せます。
padding_range は、グレーの部分(マスク外領域)の許容値で、明るさの中間値 128 ± padding_range で領域を広げます。
fade_range は、128 ± padding_range ± fade_range で、フェードアウトしながら領域を広げます。



trans_control(mask, deflate=3, expand=8)

deflate はマスク領域を減らします。微量のノイズを差分マスクに含めたくない場合は数値を増やすと効果がありますが、やりすぎると必要なマスクまで削ってしまいます。
expand はマスク領域を拡大します。マスキング漏れを防ぐ意図があります。






数定義

/*

クリップa,bを合成する
差分がある領域はbに置き換わる

clip a 合成対象
clip b 合成対象
float weight <0.25> auto_merge_order の weight
float weight2 <0.1> auto_merge_order の weight2
int thr <10> auto_merge_order の thr
int exc <0> auto_merge_order の exc
int nmax <5> auto_merge_order の nmax
bool transctrl <true> trans_control を使用するか
int padding_range <8> trans_control (輝度の中間値からの許容範囲)
int fade_range <0> trans_control (輝度の中間値からの許容フェード範囲)
int deflate <3> trans_control (領域を減らす)
int expand <6> trans_control (領域を大きくする)
bool debug <false> マスクを表示

*/

function DiffMerge(clip a, clip b, float "weight", float "weight2", int "thr", int "exc", int "nmax", bool "transctrl", int "padding_range", int "fade_range", int "deflate", int "expand", bool "debug") {
weight=default(weight,0.25)
weight2=default(weight2,0.1)
thr=default(thr,10)
nmax=default(nmax,5)
exc=default(exc,0)
transctrl=default(transctrl,true)
padding_range=default(padding_range,8)
fade_range=default(fade_range,0)
deflate=default(deflate,3)
expand=default(expand,6)
debug=default(debug,false)
clip=auto_merge_order(a,b,weight,weight2,thr,exc,nmax)
mask=get_diffmask(a,b,transctrl,padding_range,fade_range,deflate,expand)
return debug?mask:mt_merge(clip,b,mask,luma=true)
}

/*

差分マスク生成

clip a 差分対象
clip b 差分対象
bool transctrl <true> trans_control を使用するか
int padding_range <8> trans_control (輝度の中間値からの許容範囲)
int fade_range <0> trans_control (輝度の中間値からの許容フェード範囲)
int deflate <3> trans_control (領域を減らす)
int expand <6> trans_control (領域を大きくする)

*/

function get_diffmask(clip a, clip b, bool "transctrl", int "padding_range", int "fade_range", int "deflate", int "expand") {
transctrl=default(transctrl,true)
padding_range=default(padding_range,8)
fade_range=default(fade_range,0)
deflate=default(deflate,3)
expand=default(expand,8)
#~ mask1=mt_makediff(a.Vinverse(),b.Vinverse(),U=-128,V=-128) # Vinverse.dll使用で精度が少しUP
#~ mask2=mt_makediff(b.Vinverse(),a.Vinverse(),U=-128,V=-128) # Vinverse.dll使用で精度が少しUP
mask1=mt_makediff(a,b,U=-128,V=-128)
mask2=mt_makediff(b,a,U=-128,V=-128)
return transctrl?trans_control(mask1,padding_range,fade_range,deflate,expand):mt_logic(mask1,mask2,mode="or")
}

/*

マスクのアルファ領域をコントロール

clip c マスク
int padding_range <8> 輝度の中間値からの許容範囲
int fade_range <0> 輝度の中間値からの許容フェード範囲
int deflate <3> 領域を減らす
int expand <6> 領域を大きくする

*/

function trans_control(clip c, int "padding_range", int "fade_range", int "deflate", int "expand") {
padding_range=default(padding_range,8)
fade_range=default(fade_range,0)
deflate=default(deflate,3)
expand=default(expand,6)
mask=mt_merge(blankclip(c,color=$004d00),blankclip(c,color=$00ff00),c.yrangemask(128-(padding_range+fade_range),fade_range,128+(padding_range+fade_range),fade_range).mt_invert(),luma=true).mt_binarize(U=-0,V=0)
mask=deflate==0?mask:add_deflates(mask,deflate)
mask=expand==0?mask:add_expand(mask,expand)
return mask
}

/*

マスクに指定回数分の deflates 処理を施す

clip c マスク
int limit deflates 回数
int cnt <0> 再起処理用

*/

function add_deflates(clip c, int limit, int "cnt") {
cnt=default(cnt,0)
cnt=cnt+1
c=limit==cnt?c:c.mt_deflate()
return limit==0?c:limit==cnt?c:add_deflates(c,limit,cnt)
}

/*

マスクに指定回数分の expand 処理を施す

clip c マスク
int limit expand 回数
int cnt <0> 再起処理用

*/

function add_expand(clip c, int limit, int "cnt") {
cnt=default(cnt,0)
cnt=cnt+1
c=limit==cnt?c:c.mt_expand()
return limit==0?c:limit==cnt?c:add_expand(c,limit,cnt)
}

/*

FlexibleMerge の Merge 順序を自動選択

clip a 合成対象
clip b 合成対象
float weight <0.25> FlexibleMerge の weight
float weight2 <0.1> FlexibleMerge の weight2
int thr <10> FlexibleMerge の thr
int exc <0> FlexibleMerge の exc
int nmax <5> FlexibleMerge の nmax
int show <0> FlexibleMerge の show
bool rev <false> false=綺麗なフレームを返す, true=汚いフレームを返す

*/

function auto_merge_order(clip a, clip b, float "weight", float "weight2", int "thr", int "exc", int "nmax", int "show", bool "rev") {
weight=default(weight,0.25)
weight2=default(weight2,0.1)
thr=default(thr,10)
nmax=default(nmax,5)
exc=default(exc,0)
rev=default(rev,false)
show=default(show,0)
a=FlexibleMerge(a,b,weight=weight,weight2=weight2,thr=thr,nmax=nmax,exc=exc,show=show)
b=FlexibleMerge(b,a,weight=weight,weight2=weight2,thr=thr,nmax=nmax,exc=exc,show=show)
return ConditionalFilter(interleave(a,b),a,b, \
"AverageChromaV(CombCheck(SelectEven))", (rev?">":"<"), "AverageChromaV(CombCheck(SelectOdd))")
}






出典
にわとり遊び - 2つのソースからノイズの無い部分を選んでブレンドする (FlexibleMerge) その2
メモ置き場 - yの範囲を指定してマスク


関連記事
多少映像に違いがあっても問題なくブレンドするには?
一部のエンコオタクの間で流行っているブレンドエンコードとは?


スポンサーサイト

Tag:DTV AviSynth FlexibleMerge DiffMerge ブレンド エンコード

この記事は DTV Advent Calendar 2015 に登録させて頂きました。


えがき

前回の記事 でご紹介したブレンド技術は、 2 つのクリップの間に 1 フレームの映像の違いも許されないという縛りがありました。
今日はそのあたりを上手く回避して、テロップの違いや作画修正などが認められる場合でもブレンドする方法をご紹介したいと思います。
一例ですので、無理にこの方法に拘る必要はありません。





例によって AviSynth が使える事を前提に進めさせて頂きます。
必須プラグインは Masktools v2 です。



うやるの?

映像の違いがある部分のみマスキングを施し、それ以外の部分のみブレンドしたクリップを表示します。
以下 code と preview で順を追って説明します。

■ ソースの読み込み
a=ImageSource("ClipA.bmp", start=0, end=0).ConvertToYV12(matrix="Rec709")
b=ImageSource("ClipB.bmp", start=0, end=0).ConvertToYV12(matrix="Rec709")

ClipA.png ClipB.png
今回はとりあえず画像で説明します。
違いが分かり易いように、あえて全く違う図形を用意しました。




■ 差分マスク生成
ab=mt_makediff(a,b,U=-128,V=-128)
ba=mt_makediff(b,a,U=-128,V=-128)

ab.png ba.png
a-b 間の、差異がある部分のマスクを生成します。
順序を変えると別のマスクが出来上がるので、両方とも作っておきます。




■ 差分マスクを合成
mask=mt_logic(ab,ba,mode="or")

mask_ab+ba.png
2 つのマスクを合成。
mode パラメータで論理演算を or に設定して、すべての領域をマージします。




■ とりあえずブレンドクリップを作成
clip=FlexibleMerge(a,b)

clip_ab+ba.png
この時点では、○と△を無理やりブレンドしているので、乱れた映像になります。



■ ブレンドしたクリップをベースに、マスキング領域を b に置き換える
mt_merge(clip,b,mask,luma=true)

result.png
無理やりブレンドしたクリップの内、マスク領域のみ b に置き換えます。
第 2 引数を a にすることで○のクリップにすることも可能です。
これで、とりあえず目標達成です。




用編

作成したマスクは、意図したマスク外領域にアルファ値(透過率)を含んでいますので、輝度に閾値を設けて階調化します。
こうすれば一々 mt_makediff を二通り生成する必要もありません。
別途 yRangeMask を使用します。

■ マスクのアルファ領域をコントロールする関数定義
function trans_control(clip c, int "padding_range", int "fade_range") {
padding_range=default(padding_range,0)
fade_range=default(fade_range,0)
return mt_merge(BlankClip(c,color=$004D00),BlankClip(c,color=$00FF00),c.yrangemask(128-(padding_range+fade_range),fade_range,128+(padding_range+fade_range),fade_range).mt_invert(),luma=true)
}

■ 使用例
a=ImageSource("ClipA.bmp", start=0, end=0).ConvertToYV12(matrix="Rec709")
b=ImageSource("ClipB.bmp", start=0, end=0).ConvertToYV12(matrix="Rec709")
diff=mt_makediff(a, b, U=-128, V=-128)
trans_control(diff)
return last

mask_trans_control.png



総括として、簡単な差分マスク関数を書きます。

■ 差分マスク関数定義
function get_diffmask(clip a, clip b, int "padding_range", int "fade_range", int "deflate") {
padding_range=default(padding_range,0)
fade_range=default(fade_range,0)
deflate=default(deflate,2)
trans_control(mt_lutxy(a,b,"x y - 128 +",U=-128,V=-128),padding_range=padding_range,fade_range=fade_range)
return add_deflates(mt_binarize(U=-0, V=0), deflate)
}

function add_deflates(clip clip, int limit, int "cnt") {
cnt=default(cnt,0)
cnt=cnt+1
clip=limit==cnt?clip:clip.mt_deflate()
return limit==cnt?clip:add_deflates(clip, limit, cnt)
}

function trans_control(clip c, int "padding_range", int "fade_range") {
padding_range=default(padding_range,0)
fade_range=default(fade_range,0)
return mt_merge(BlankClip(c,color=$004D00),BlankClip(c,color=$00FF00),c.yrangemask(128-(padding_range+fade_range),fade_range,128+(padding_range+fade_range),fade_range).mt_invert(),luma=true)
}


■ 使用例
a=ImageSource("ClipA.bmp", start=0, end=0).ConvertToYV12(matrix="Rec709")
b=ImageSource("ClipB.bmp", start=0, end=0).ConvertToYV12(matrix="Rec709")
mask=get_diffmask(a, b)
clip=FlexibleMerge(a, b)
mt_merge(clip, b, mask, luma=true)
return last



わりに

以上の方法を活用することで、ED など映像に差異があるクリップ同士でも、可能な限りの範囲をブレンドすることが出来ます。
OP でも、油断をしていると作画修正を見逃してミスエンコードしてしまうので、細心の注意を払ってチェックし、修正箇所を見つけたら今回の手法でブレンドしてみてください。



それでは、良いエンコライフをー





出典
にわとり遊び - 2つのソースからノイズの無い部分を選んでブレンドする (FlexibleMerge) その2
メモ置き場 - yの範囲を指定してマスク


関連記事
一部のエンコオタクの間で流行っているブレンドエンコードとは?


Tag:DTV AviSynth FlexibleMerge ブレンド エンコード

この記事は DTV Advent Calendar 2015 に登録させて頂きました。

えがき

録画環境に関しての知識は全然ないので今まで見る専でしたが、エンコネタも OK ということでしたので、無い頭を絞って一筆書きます。
6日目の記事 でブレンドエンコードについて軽く採り上げられていて面白そうだったので、今回はその点にスポットを当てようと思います。





私の知る限り、これまでの DTV エンコードの常識として、ソースファイルを超える画質を出すのは不可能というのが大前提でした。
シャープネスやノイズリダクション等の画質補正で、いくらかマシに“見せる”方法はありますが、どんな処理にも大なり小なり副作用が付き物です。
しかしその前提が揺らぐ技術がとある方のブログで提示され、これまで不可能だったソースの壁を突破(厳密には違いますが)したことで、DTV エンコードの可能性に新しい光が差し込みました。
それは フレーム補完 や waifu2x のように画像を予測生成するようなものではなく、全うな方法で正しい映像を作り出すことが可能なものでした。
この技術を利用するにあたり、必要なものは AviSynth を使える知識と時間です。(メインメモリも多いほうがハッカドール)



リットとデメリット

メリット ─ トンでもなく画質が良い。ファイルサイズを大幅に削減出来る。画質調整をする必要性が減る。
デメリット ─ エンコードに時間がかかる。ソースそのものが綺麗になるので、画質調整の余地(楽しみ?)が減る。



くみ

この技術を利用するにあたり、条件が 1 つあります。
それは、映像の内容が同一であり、且つエンコードプロセスが同一ではないソースファイルを 2 つ以上用意する 事です。
つまり 同じアニメを 2 週以上に亘って録画したものの OP 映像であるとか、同じアニメの同じ話数を複数の放送局から録画したものがこれに該当します。

現在の日本の一般的な放送規格では、たとえ全く同じ映像が流れていたとしても、その時々によってノイズの乗り方が変化します。ブレンド技術はその隙を突いたもので、2 つ以上のソースからノイズ部分を補い合う形で、単一ソースでは実現不可能な画質を実現することが可能になりました。
これは単純な Merge や Overlay とは一線を画する技術です。

blend_process_map.png






手近にあった 2 本の録画データを使って、比較検証します。
今回の検証対象は、コーミング量/SSIM/PSNR/ファイルサイズ とし、ブレンド前・後の数値を出します。

ファイル①: 学○都市アスタリスク #8 (CBC) OP
ファイル②: 学○都市アスタリスク #9 (CBC) OP

コーミング量採取方法
LoadPlugin("MaskTools.dll")

AVISource("asterisk_cbc_09.raw.avi").ConvertToYV12()
WriteCombLog("asterisk_cbc_09.raw.avi.log")

return last

function WriteCombLog(clip clip, string file) {
global file=file
ScriptClip(clip, """
frame=LPad(String(Current_Frame),"0",StrLen(String(FrameCount)))
comb=LPad(String(CombCheck().AverageChromaV()),"0",10)
line=string("-")
value=frame+line+comb
WriteFile(last, file, "value",append=true)
"""
)
}

function LPad(string a, string b, int cnt){
a=strlen(a)<cnt?b+a:a
return strlen(a)<cnt?lpad(a,b,cnt):a
}

function Combcheck (clip clip, int "thr") {
thr=default(thr,10)
clip=mt_merge(Grayscale(clip),ColorYUV(Grayscale(clip),gain_u=100,gain_v=100),CombMask(clip,thY1=thr,thY2=thr),luma=true)
return clip
}


ファイルサイズ採取方法(品質固定)
x264 --preset Medium --ssim --psnr --output %out% %src% 2>%out%.log


SSIM/PSNR採取方法(ビットレート固定)
x264 --preset Medium --bitrate 6000 --qcomp 1.0 --no-mbtree --ssim --psnr --output %out% %src% 2>%out%.log


検証結果


















ファイル コーミング量 ファイルサイズ SSIM(Y) PSNR(Avg)
ファイル①
130.4182803
69,234,880
0.9732863
44.076
ファイル②
130.4626961
69,458,405
0.9734497
44.037
①+②
129.1796893
62,503,931
0.9795467
45.100


コーミング量は、コーミング 0 の状態で 128.0 という数値が出るので、差し引いて計算すると 約 52% の削減
ファイルサイズは 約 10% の削減
SSIM と PSNR も良くなっていますが、条件次第で幅は変わりそうです。ただ余程のことが無い限り成績が逆転することは無いと思います。

以上の結果になりました。とても驚異的です。



わりに

今回は 2 本のソースでのブレンドをご紹介しましたが、同じ要領で 4 本、8 本と掛け合わせていくと、更にノイズが減り、不純物の少ない良質な映像が生まれます。
一度ブレンドした映像を見てみると、あまりの綺麗さに、癖になってやめられません(汗)

今回ご紹介した記事によって、ノイズの有無が如何に画質やファイルサイズに影響しているかが分かって頂けたかと思います。
ブレンドエンコードに関して、エンコerの皆様に少しでも興味を持っていただけたら幸いです。

私は、ブレンドエンコードをする人が増えてくれると嬉しいと思っているので、もしこの記事が宣伝に良いと思っていただけたら Tweet などで知人に紹介して貰えると嬉しいです。



それでは、良いエンコライフを!






関連記事
ブレンドによる効果の程は?画像を使ってNRとの違いを検証
多少映像に違いがあっても問題なくブレンドするには?



※使用している画像は著作権フリーです

Tag:DTV AviSynth FlexibleMerge ブレンド エンコード



WHAT'S NEW?

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。