2016年3月16日水曜日

RemoveGrain mode13~mode16

今回はmode13からmode16までです。

これまでのmode1~mode12はRemoveGrainの名にふさわしくいずれもdenoiserでしたが、13~16はdenoiserではなくなんとdeinterlacerです。

インタレ解除においては失われてしまったフィールド情報をいかにして補間するかが重要になるわけですが、補間方法にも線型補間とか三次補間とか色々あります。
上図において失われたフィールド上の点Xを補間する場合、線型(linear)補間なら(F0 + F1) / 2、三次(cubic)補間なら(F0 + F1*3 + F2*3 + F3) / 8を行いますが、他に有名どころではELA(Edge Line Average)法というものがあります。
ELA法は補間自体は線型補間と同様の計算をしますが、参照する2点の組み合わせを上図の場合だと(Fu0,Fl4)、(Fu1,Fl3)、(Fu2,Fl2)、(Fu3,Fl1)、(Fu4,Fl0)の5つのどれか一つから選びます。
これは三次補間のような垂直方向のみのデータの組み合わせでは、エッジ部においてジャギるからです。
もしエッジが斜め方向に走っている場合は参照する点も斜め方向からとらないといけないってわけですね。

RemoveGrainが書かれた当時(2005年頃?もっと前?)、avisynthにはすでにELAを使ったdeinterlacerとしTomsmocompが存在しており、なかなかに高い評価を受けていました。
しかしTomsmocompには「アーティファクトが発生しやすい」という弱点もありました。

で、Kassandro氏はELAにおける参照点として(Fu0,Fl4)か(Fu4,Fl0)が選ばれてしまった場合アーティファクトが特に発生しやすいことから、組み合わせを(Fu1,Fl3)、(Fu2,Fl2)、(Fu3,Fl1)の3つに減らし、さらにTemporalRepairフィルタを併用することで、よりアーティファクトの少ない(しかも高速な)deinterlacerとしてmode13~mode16を実装したのです!

と、ここまで書きましたが現在これを使う人はまずいません。
なぜならアーティファクト低減機能付きELA deinterlacerとして2007年にYadifというフィルタが登場したからです。

Yadifで満足できないならこれを使っても満足できるということはまずありませんので、これでmode13~mode16の解説は終了とします。

目次:
RemoveGrain解説 導入
RemoveGrainの基本事項
RemoveGrain mode1~mode4
RemoveGrain mode5~mode12
RemoveGrain mode13~mode16
RemoveGrain mode17~mode22
RmoveGrain mode23/mode24 及び総評
Repair
Clense
Clense 応用

RemoveGrain mode5~mode12

今回はmode5からmode12までです。

・mode5~mode9
mode1~mode4ではCの近傍の8点N1~N8のうちのどれか2点を選んでclampしていましたが、mode5~mode9ではこの2点をCを通る直線上に限定するようになっています。
つまり、2点(a,b)の組み合わせが(N1,N8)、(N2,N7)、(N3,N6)、(N4,N5)のいずれかに限定されるということです。
mode3やmode4では組み合わせを限定していなかったため、細い直線やその終端が壊れやすかったのが、組み合わせを直線状に限定することで壊れにくくなっています。

具体的な処理内容については言葉で説明するのは非常に難しいため、もうソースコードを読んでもらうしかありません。
よって、ここでは傾向だけを説明します。

ノイズの取れ具合はmode5 < mode6 < mode7 < mode8 < mode9 とmodeが上がるほど強力になりますが、その分映像に与える悪影響(エッジの角が丸まったり、ボケたり)も大きくなります。

そして処理スピードは mode2 > mode9 > mode5 > mode7 > mode6 = mode8 です。

一般に細い線を壊さない処理というものは、YUV4:2:0な映像の色差にフィルタをかける場合に効果を発揮します。(なんせ色差は輝度の4分の1しかありませんから)
よって5~9はmodeU、modeVで指定することがほとんどでしょう。

・mode10
mode10はclampを行わず、N1~N8のうち最も近い値(C-Nxの絶対値が最も低いもの)にCを置き換えたものを出力します。
一見簡単に思えますが、実はこの処理はmode1~mode9のどれよりも比較の回数が増えるため、処理スピードはmode6 > mode10です。
しかもノイズの取れ具合はmode1と同程度と、もはや何のためにあるのかよくわかりません。

これが効果的な映像とは果たして…?

・mode11/mode12
mode11とmode12は3x3のconvolution filterです。
使用するカーネルは[1, 2, 1, 2, 4, 2, 1, 2, 1]で、これは内蔵フィルタのBlur(1.0)に相当しますがより速くて正確です。
オリジナルのほうのドキュメントの該当部分を読んでみると(処理内容があらかじめ理解できているとドキュメントも理解できるようになりました…なんという本末転倒…)
「mode12はmode11よりもさらに速いよ」ってなことが書かれていますが、tp7氏はどちらも同じ処理にしてしまっています。
そりゃ出力が同じなら、速い方しか要らんよね…なんで遅い方をわざわざ残してたんでしょ?

目次:
RemoveGrain解説 導入
RemoveGrainの基本事項
RemoveGrain mode1~mode4
RemoveGrain mode5~mode12
RemoveGrain mode13~mode16
RemoveGrain mode17~mode22
RmoveGrain mode23/mode24 及び総評
Repair
Clense
Clense 応用

RemoveGrain mode1~mode4

まずはmode1からmode4の説明です。

・mode1
mode1ではN1からN8までの8点のうちの最小値minNと最大値maxNを求め、clamp(C, minN, maxN)を出力します。
このように、ポツポツと不連続なドット状ノイズが出ているような画像にかけると、ノイズ以外の部分にはほぼ影響を出さずにノイズだけ消すことができます。
ちなみにこの処理はtrbarry氏のundotフィルタと同じものです。

・mode2
mode2ではN1からN8までの8点のうちの2番目に小さい値min2Nと2番目に大きい値max2Nを求め、clamp(C, min2N, max2N)を出力します。
1よりもちょっと大きなノイズも取れますが、エッジの終端部分が少し壊れます。


・mode3
mode3ではN1からN8までの8点のうちの3番目に小さい値min3Nと3番目に大きい値max3Nを求め、clamp(C, min3N, max3N)を出力します。
mode2よりもさらに大きなノイズが取れますがエッジの終端により大きな影響を与えます。また、細い線が結構壊れます。

・mode4
mode4ではN1からN8までの8点のうちの4番目に小さい値min4Nと4番目に大きい値max4Nを求め、clamp(C, min4N, max4N)を出力します。
少し考えればわかると思いますが、これはN1~N8とCの9点におけるmedian(中央値)と同じです。
つまりmode4はごく一般的な3x3のメディアンフィルタです。
1~3に比べて結構ボケるし、エッジの角が丸くなったりしますので注意が必要です。使用の際はエッジマスク等の併用を常に考える必要があります。

ちなみに処理スピードはmode1 > mode4 >= mode2 = mode3 です。

目次:
RemoveGrain解説 導入
RemoveGrainの基本事項
RemoveGrain mode1~mode4
RemoveGrain mode5~mode12
RemoveGrain mode13~mode16
RemoveGrain mode17~mode22
RmoveGrain mode23/mode24 及び総評
Repair
Clense
Clense 応用

RemoveGrainの基本事項

RemoveGrainのシンタックスは以下の通りです。

RemoveGrain(clip clip, int "mode", int "modeU", int "modeV", bool "planar")

今回はまず、フィルタの具体的な処理内容以外のことについて解説します。

RemoveGrainにおける基本事項


・参照サンプルの配置
RemoveGrainはmode=1からmode=24までの24種類のフィルタを一つにまとめたものですが、これらは全て処理対象となるサンプルとその近傍8点を参照するspatial(空間軸)フィルタです。
図にするとこんな感じ。
中央のCが処理対象となるサンプルで、N1~N8はその周囲のサンプルです。
次回から説明するすべてのmodeにおいて、処理対象となるプレーンの上下左右の画像端1ラインを除くすべてのサンプルに対して処理を行います。
なお画像端の1ラインはそのままコピーされます。

・mode、modeU、modeV
RemoveGrainではYプレーン、Uプレーン、Vプレーンそれぞれに異なったmodeでフィルタをかけることができます。
RemoveGrain(mode=10, modeU=2, modeV=5)なら、Yプレーンはmode10、Uプレーンはmode2、Vプレーンはmode5のフィルタがかかります。
modeは1~24までの24種類がありますが、それ以外に-1(なにもしない)と0(そのままコピー)もあります。
-1の場合、フィルタリング後のデータを書き出すために用意されたメモリには何も手を加えられませんので、どのような出力になるかは誰にもわかりません(avisynthは確保したメモリのゼロクリア等はしません)。
0ならば、フィルタ前のデータがそのままフィルタ後のメモリにコピーされます。
mode、modeU、modeVのデフォルト値はmode=1、modeU=mode、modeV=modeUです。
よって、もしYのみにフィルタをかけたい場合は、RemoveGrain(mode=1~24のどれか, modeU=0)とします。

・planar
本家RemoveGrainはYV12とYUY2/RGB(一応)をサポートしていましたが、RGToolsではYUY2やRGBのサポートはなくなり、代わりに全てのplanar format(YV24, YV16, YV12, YV411, Y8)をサポートするようになりました。
YUY2なクリップに対してフィルタをかけたいなら事前にConvertToYV16()をかけ、フィルタ後にConvertToYUY2()で元に戻しましょう。
RGBにかけたいならPlanarToolsでも使ってください。
planarパラメータはもともと本家RemoveGrainではSSE2Toolsを利用したYUY2/RGBサポートのために用意されていたものですが、RGToolsでは単にavisynth2.5用に書かれたユーザースクリプトへの互換性のためだけに用意されたもので、これをtrueにしてもいいことはまったくありません。
よってこのパラメータは一切弄らないようにしましょう。

・clamp()
modeの内容を説明するにあたり、clamp(x, a, b)という表現を使用することになると思います。
clamp(x, a, b)はxがa以下の場合はa、xがb以上の場合はb、a < x < b の場合はxの値そのままの意味になります。(なお常にa <= bの関係が成り立つものとします)
この処理はclippingとかsaturateなどと呼ばれることもありますが、ここではとりあえずclampで統一します。

では次からいよいよmodeの説明にはいります。

目次:
RemoveGrain解説 導入
RemoveGrainの基本事項
RemoveGrain mode1~mode4
RemoveGrain mode5~mode12
RemoveGrain mode13~mode16
RemoveGrain mode17~mode22
RmoveGrain mode23/mode24 及び総評
Repair
Clense
Clense 応用

RemoveGrain解説 導入

RemoveGrainはkassandroことRainer Wittmann氏が書いた有名なavisynthプラグインです。
Didée氏のscriptなんかではほぼ確実に使われていたりと使用頻度は極めて高いプラグインなのですが、その使い方は自分にとって極めて難解なものでした。

難解な理由その1: ドキュメントが極めて読みにくい。
RemoveGrainのドキュメントはすべて英語で書かれています。
まあ英語だけならある程度気合いを入れれば読めないことはないのですが、なんと改行がほとんどありません。

数行読むだけでも息が詰まってくる上に、すぐにどこまで読んだのかわからなくなってしまうことの連続でいつも10分経たぬうちに挫折してしまいます。
まったく読みづらいったらありゃしねえ…。
RTFM(Read The Fine/F○○kin' Manual)なんて言葉がありますが、ここまでF○○kin'なマニュアルも珍しいんじゃないかと思います。

難解な理由その2: コードが極めて読みにくい。
「マニュアルがダメならソースコードを読んで理解すればいいじゃない」
そんな風に考えていた時期が俺にもありました。
CやPythonを少し覚えてちょぼちょぼとは書けるようになった頃だったと思います。
しかしその考えが甘かった。

RemoveGrainのバイナリパッケージにはRemoveGrain,Repair,DenoiseSharpen,RSharpenという4種類のDLLがCPUアーキテクチャやMSVCRTのスタティックリンク等の別に合計で13個(!)入っているわけですが、これらをビルドするためのソースコードはなんと約8900行からなるRemoveGrain.cppというたった一つのファイルしかありません。
いや、普通は複数のファイルで一つのバイナリなのに、一つのファイルで複数のバイナリっておかしいやろ…はじめて中身を覗いたときはそりゃもうびっくりしましたよ。

数行おきに現れる#ifdef~#elif~#endif、inline asm、そしてCPPマクロの嵐。
もはや狂気を感じるレベルです。
まあ、自分が書いたコードも(特に数年くらい前のやつとか)いま見直すと結構アレなんですが、このレベルになるともう、わざと書こうと思っても書けるものではありません。
実はわたくし、ドイツ人というものになんというかちょっとネガティブな偏見を持っているのですが、そのうちの半分くらいはこのRemoveGrainのドキュメントとコードに起因するものだったりします。

その後の展開
で、RemoveGrainのドキュメントとコードの解読はすっかり諦めていたわけですが、そのうちにFiresledge(cretindesalpes)氏がDitherPackage用に改造したりVapourSynthに移植されたりといったことが起こり、avisynthのほうでもtp7氏がRgToolsとしてrewrite版を出したおかげで大変わかりやすいソースコードが手に入るようになりました。
でもあいかわらずドキュメントは…。
で、自分用の備忘録も兼ねて解説でも書いてみようかなーとか思ったわけです。

tp7氏のRGToolsにはRemoveGrain、Repair、Clense、FowerdClense、BackwordClense、VerticalCleanerの計5つのフィルタが入っていますが、これらはすべてKassandro氏が書いたもののrewrite versionです。
解説はRGToolsのRemoveGrainをもとに行いますので、オリジナル(Kassandro版)とは違うところもあるかもしれません。

では次回よりRemoveGrainの解説を行います。

目次:
RemoveGrain解説 導入
RemoveGrainの基本事項
RemoveGrain mode1~mode4
RemoveGrain mode5~mode12
RemoveGrain mode13~mode16
RemoveGrain mode17~mode22
RmoveGrain mode23/mode24 及び総評
Repair
Clense
Clense 応用

2016年3月5日土曜日

yadifmod2

前回yadifmodを書き直したものを公開しましたが、結局yadifそのものもavs2.6用に書き直すことにしました。

というわけでできたのがyadifmod2です。

yadifmod2

バイナリはここ

YadifMod2 = Yadif + YadifMod

とあるように、edeintなしならyadif、edeintありならyadifmodになります。

2016年3月1日火曜日

YadifMod for Avisynth2.6 / Avisynth+

tritical氏のyadifmodをAvisynth2.6/Avisynth+用に書き直してみました。

ソースコード:
yadifmod26

バイナリ(32bit/64bit同梱):
https://github.com/chikuzen/yadifmod26/releases

tritical版はSIMDはMMXしかありませんでしたが、今回SSE2とAVX2に対応させました。
それなりに速くはなったようです。

なおバイナリにyadifmod.dllとyadifmod_avx.dllの2種類がありますが、AVXマシン(SandyBridge以降だっけ?)はyadifmod_avx.dllを、
Nehalemとかの場合はyadifmod.dllを使ってください。

追記:これとは別にyadifとyadifmodを統合したyadifmod2もリリースしました。