2021年01月20日

画像の情報量と評価指標

年末年始に更新しようと思っていたのにいつの間にか1月も下旬ですね…。

深層学習に使うデータセットを準備しているとき、解像度の高い画像からランダムクロップでデータ数を増やしたりするんですが、たまたま真っ黒な背景の部分だけ切り取ってきたりした場合は、あまり学習データとして良くない気がします(実は必要なのかもしれませんが…)。

また、ノイズ除去とかで、劣化画像と原画像のペアを用意する場合、平坦な部分などほとんど違いが感じられない場合もあるので、2枚の画像を比べてどれくらい違っているかの指標も必要かと思います。

前者は画素値の分散を計算して閾値以下のものをはじくといったのでも良いかと思いますが、画像の複雑さとしてはエントロピーを計算するのもいいかなと思いますので、その辺を計算してみます。

後者はMAE(Mean Absolute Error)、MSE(Mean Squared Error)、PSNR(Peak Signal-to-Noise Ratio)などが有名かと思いますが、SSIM(Structural Similarity)というものが最近?はよく使われているようですので、それも試してみることにしました。

1. エントロピー[1]~[4]
画像のエントロピーというと、その画素値がどれくらいの頻度で発生しているかを確率としてみて、単色なら0、全色均等に使われている場合は最大値になるような指標です。ヒストグラムを計算して、合計1になるように正規化して後はlogとって掛け算するだけですね。RGBだけではなく、例えばグレースケール画像は除きたい場合などもあると思うので、HSVでも計算してみました。

2. SSIM[5]~[7]
ガウスでぼかして近傍との分散を計算しないといけないみたいで、計算量が多そうです。OpenCVで実装サンプル[8]がそのままありましたので、使わせていただきました。こちらもRGBとHSVで計算してみました。

実行結果

pix2pix用にDIV2K dataset[9]からランダム切り出しして原画像(左)/JPEG圧縮画像(右)のペアを作っています。JPEGで劣化させた場合はブロックノイズのせいでエントロピーは下がるかな、と思いましたが、画像によるみたいですね。

__000840.jpg
ssim_fig_1.png
論文等でよく見る蝶々の一部ですね。拡大しないとあまり違いが分かりませんが、類似度は高くないようです。

__000480.jpg
ssim_fig_2.png
空の一部?です。割と違っているように見えますが、PSNRもSSIMも高いですね。こちらはJPEG圧縮で減色状態になったのか分散はほぼ一緒ですがエントロピーが結構下がっています。類似度が高くてもエントロピーに差があるので学習に使う、というのもありかもしれません。

深層学習ではロスの計算にL1LossやMSEが良く使われていますが、SSIM使うとどうなるのか試してみようかなと思います。

[1] 平均情報量 Entropy
[2] 平均情報量の性質(3章)(pdf)
[3] 画像のエントロピーをpythonで求めてみた
[4] 医用画像工学実験 -画像の情報量 編- (pdf)
[5] SSIMとは何か?その3
[6] 画質評価アラカルト
[7] Googleが薦める「Jpegの品質は85」を検証する
[8] OpenCV Tutorial Video Input PSNR SSIM
[9] DIV2K dataset
posted by シンドラー at 02:59| Comment(0) | Image Processing | 更新情報をチェックする

2020年11月29日

lightweight GANのテスト

もう11月も終わりなので、今回もテストしただけの更新です。GANは面白いのですが、なかなかうまくいかないことも多いです。メモリがたくさん必要とか学習に時間がかかるという問題もあるので、その辺を改良したのがlightweight GAN[1]です。githubにコードもありますし、pipでインストールできるので使う分には画像をディレクトリにおいて学習するだけなので簡単です。

SDNET2018[2]の画像で異常データだけで学習させた結果は下記のようになっています。SDNET2018は3種類のデータがあるのですが、1種類だけで学習させて最後でちょっとだけ他の2種類も混ぜて学習させました。なのでまだ学習中のようなものですが、それなりにひびが入った画像が生成できているように見えます。

データセットにはひび入っているかな?と素人が見ても分かりにくい画像も混ざっていますので、ひびがはっきり見える画像だけ選別して学習させるともっと良さそうな気もします。

単純にGANで増やしても異常のバリエーションが増えるわけではないみたいですが、データ増強の方法の一つとして考えれば別に問題ない気もしますがどうなのでしょうか。

実行結果
202.jpg

基本的なGANでSDNET2018の画像生成をしたときはあまりうまくいかなかったので、画像を用意して動かすだけでこれだけ生成できるのは凄いと思います。

[1] https://github.com/lucidrains/lightweight-gan
[2] https://digitalcommons.usu.edu/all_datasets/48/
posted by シンドラー at 16:29| Comment(0) | Machine Learning | 更新情報をチェックする

2020年10月15日

EDARのテスト

2カ月に1回更新になってしまっている今日この頃です。最近GANの勉強していますが面白いですね。今回はGANではなく通常?のネットワークです。

動画を見ていると結構ノイズが入っているので、動画のノイズ除去を試してみることにしましたが、非力なPCでは動画を扱うのは厳しいので、静止画像のノイズ除去を行うネットワークを試してみることにします。mp4のエンコードアルゴリズムは調べていないですが、画像を見る限りjpegと同じようなノイズが載っているような気がしますので、EDAR[1]を使ってみることにしました。

ConvとResidual Blockを重ねただけの分かりやすい構成ですが、結構きれいにノイズが取れる気がします。

1. データセットの準備
高画質な動画を探してきて、ffmpegを使って元の動画像と同じビットレートの動画に変換したもの(教師画像)と、そのビットレート×0.3に下げた動画像(入力画像)を用意して、1動画から2000枚のペア画像を切り出して、さらに320x240の画像に分割して枚数を増やしました。EDARは48x48のパッチサイズで切り出しますので、320x240からランダムクロップ+ランダム回転(90度毎)で実際には学習します。元が4K動画とかなので400万枚ぐらいの画像になっていますね…。

2. EDARの改造
元のプログラムは教師画像のみを与えて、10~40%ぐらいのクオリティでjpeg圧縮した画像を入力画像にして学習するようになっていたので、改造して入力画像と教師画像をディレクトリから読み出すようにしました。また、テスト(動画のノイズ除去)は動画を渡したいので、OpenCV、ffmpeg、pydubを使って、入力動画→動画と音声に分割→動画から画像を切り出し→ノイズ除去→動画に結合→音声を結合→出力動画ができるようなプログラムを作成しました。

実行結果

サンプルとして、あまり良くないかもしれませんが[2]の灯台画像を使用させていただきました。

jpegexample_06.png
圧縮画像(圧縮50%, 20%, 10%のはずですがサイトの画像なので違うかもしれません)

edar_org_450.png
[1]で用意されていた450エポック学習済みの重みを用いた場合

edar_20.png
自前で用意した画像で20エポック学習したものを用いた場合

[2]の無圧縮原画像と比べると芝生の辺りの高周波成分はちょっと潰れてしまっていますが、10%まで圧縮してブロックノイズが結構載っていても復元できているような気がします。

次は同じようなFusion-Netを試すか、CycleGANでノイズ除去とかも試してみたいところです。

[1] https://github.com/developer0hye/EDAR
[2] 深層学習を使用した JPEG イメージのデブロック
posted by シンドラー at 22:23| Comment(0) | Machine Learning | 更新情報をチェックする

2020年08月23日

PyTorchのC++での利用

油断すると月1更新をさぼってしまいますね。今回はWindows上でC++使ってPyTorchを利用するテストです。以前試したTensorflowをWindows上のC++で動かすのは結構大変(今は簡単になっているかもしれませんが)だったのですが、PyTorchは簡単ですね。

1. ダウンロード・解凍
[1]からダウンロードします。図の通り、PyTorch 1.6.0、C++/Java、CUDA 10.2版を使用しました。CUDA10.02とcuDNN(必要?)は事前にインストールしています。

pytorch_cpp_002.png

解凍するとincludeなどライブラリとして必要なものが入っています。

2. サンプルコードのビルド
基本的には[2]の通りにやっていけば問題ないかと思います。DCGANのサンプルを動かしてみます。今回はCMakeとVisual Studio 2019を使用します。まずはtestフォルダにdcganというフォルダを作成し、dcgan.cppとCMakefile.txtを作成します。

CMake-GUIを起動して上記のフォルダを指定すると、Torch_DIRの指定が必要になります。libtorch/share/cmake/Torchを指定するといいようです。

pytorch_cpp_001.png

後はVisual Studioを起動してビルドすれば実行できるはずです。

3. 別プロジェクトでのテスト

どちらかというと学習済みデータを使った推論をC++側でやりたいことが多いと思いますので、今回はOpenGLのプログラムのテクスチャ貼替をやってみました。libtorchを動かすために必要なincludeファイルやlibファイルは、上記のCMakeで生成されたプロジェクトのものを参考にします。

学習済みモデルの使い方としては、モデルの構築とパラメータ読込み、forwardを使って推論して、結果を取り出すということです。

モデルの構築(略)とパラメータ読込み(最初に1回)
pytorch_cpp_003.png

画像生成
pytorch_cpp_004.png

実行結果


16枚の28x28の手書き文字画像を生成してテクスチャとして貼り付けています。これぐらいのサイズなら余裕でリアルタイムで動きますね。

[1] https://pytorch.org/
[2] https://pytorch.org/tutorials/advanced/cpp_frontend.html
posted by シンドラー at 14:06| Comment(0) | Machine Learning | 更新情報をチェックする

2020年06月17日

PIFuHDのテスト

Twitterを見ていたら、PIFuHD[1]というものが流れてきましたので、試してみることにしました。Google Colaboratory上で動かせるようになっていてありがたいですね。サンプルそのまま動かして生成された.objの中身を見てみると、テクスチャ座標は出力されていませんでした。せっかくなので前回の手法でテクスチャを付けられないか試してみることにします。

1. UV展開
bff[2]を使用させていただきました。出力されたモデルをそのまま使うと警告が出てずっと終わらなかったので、MeshLab[3]のFilter→Cleaning and Repairingで適当にクリーニングして出力したものをbffにかけると、今度はすんなりUV展開できました。今回コマンドラインから実行したのですが、--normalizeUVsというオプションを付けないと1枚に収まらなかったような気がします。

PIFuHD_001.png

確認として[4]のUVマップ確認画像を使用させていただきました。

2. Mitsuba2[5]用のXML出力
こんなこともあろうかと?前回作成したXML出力のプログラムでは、目標画像を半透明表示する機能を追加して位置合わせができるようにしていました。カメラの位置も学習させるといいかと思いましたが、Mitsuba2だとPerspectiveCameraのパラメータに*が付いていなかったので、学習できないかもしれない(未確認)ので今回は手動です。

PIFuHD_002.png

一応レンダリングすると下記のような感じです。

PIFuHD_003.png

3. Mitsuba2で環境マップとテクスチャの学習
後はほぼ前回のhead.htmlと同様の処理ですが、違う点としてはテクスチャの学習だけではなく、環境マップも同時に学習しています。

# 微分したいパラメータを除いて、すべてのパラメータを破棄する
params.keep(['material_000.reflectance.data','my_envmap.data'])

実行結果

1000回学習した結果は下記のような感じです。まだ誤差は下がっているようなのでもうちょっと回しても良かったかもしれません。自前のGPU1枚しかない環境なのでSPP数を上げることができず、あまりきれいには学習できていません。後、視野角が小さい方が画像とモデルの一致率が高かったので、結構小さくしています。そのせいで環境マップの利用領域がものすごく狭くなっているので、こちらは殆ど学習できていません。
PIFuHD_005.jpg

学習後のテクスチャです。ジーパンっぽいところは分かりますが、他はほぼ白ですね。
PIFuHD_006.jpg

MeshLabで確認すると、手の部分も色がおかしいので、なかなか難しいです。環境マップも同時に学習しているので、肌色はそちらが学習してしまったのかもしれません。
PIFuHD_004.png

というわけで、前後2枚の写真があれば解像度は微妙ですがテクスチャ付きのモデルも作れそうかなといった感じでした。

以下Mitsuba2のコード
mitsuba2_pifuhd.html

[1] AIで1枚の人物写真から高精細3Dモデル作成 Facebookなど開発 - ITmedia
[2] Boundary First Flattening
[3] MeshLab
[4] UVマップ確認用テクスチャーの制作 - リカのきままなブログ
[5] Mitsuba 2
posted by シンドラー at 21:35| Comment(0) | Machine Learning | 更新情報をチェックする

2020年06月08日

Zoom配信の前処理について

新型コロナウイルスの影響でオンライン会議などが増えましたね。Zoomを使った会議などにそのままカメラを使うのも面白くないので、OpenCVで前処理をしてから配信を試してみることにしました。今回はFaceRig→OpenCV(C++)→OBS Studio→Zoomという流れです。 OBS StudioはPythonのScriptが使えますので、多分OpenCV(C++)は必要ないのですが、使い慣れた環境でやりたかったので間に挟みました。

1. FaceRigの使用
Steamで購入しました。Webカメラでもいいです。FaceRigの配信を他アプリから使用するためには、FaceRigのVirtual Camera Driverをインストールする必要があります[1]。FaceRigを起動してブロードキャストすればいいです。

2. OpenCV(C++)
前処理は何でも良かったのですが、今回はOpenCV 4.3.0 + CUDA 10.2 + CuDNN 7.6.5でDNNを使用して顔検出して笑い男を貼り付けるよくあるやつを試してみました。DNNを使った顔検出[2]とマスク処理[3]と笑い男画像[4]を使用/参考にさせていただきました。FaceRigのバーチャルカメラは普通のWebカメラのように認識できますので、VideoCaptureでOpenすれば画像を取得できます。

3. OBS Studio
最初はDirectShowを使ったりGStreamerを使ったりしてOpenCVからZoomに配信できないかなと調べてみたのですが、なかなか難しそうだったのでOBS Studio[5]を使うことにしました。使い方は[6]を参考にさせていただきましたが、こちらもVirtual Cameraのプラグインをインストールする必要があります。cv::imshowで表示したウィンドウをOBS Studioでキャプチャして、VirtualCamのOBS-Cameraに配信します。

4. Zoom
最終的にOBS-Cameraから画像が流れてきますので、Zoomのビデオにはこれを選択します。

実行結果


一応頭の上に確信度を表示していますが、一般外国人男性のアバターだとかなりの確信度で顔検出できていますね。思い付きで試しただけなどで顔隠し以外の前処理が思いつかないですね…。

[1] ZoomでFaceRig使ってバーチャル参加する方法
[2] OpenCV 4.1 DNNによる顔検出
[3] OpenCV 2.0 でマスク処理してみた。
[4] 笑い男マーク
[5] OBS Studio
[6] OBSをバーチャルカメラとして出力してZoomやTeamsで映像ソースとして認識させる方法
posted by シンドラー at 01:24| Comment(0) | Image Processing | 更新情報をチェックする

2020年05月14日

Mitsuba2のテスト その5

テクスチャの学習ができるということで、今回は画像や写真を用意して、それっぽい見た目にできるかどうか試してみることにしました。以前使ったheadモデルをレンダリングした結果が、2次元の参照画像に近づくようにテクスチャを更新していくというものです。

mitsuba2_update_texture_004.png mitsuba2_update_texture_003.png
     (左)レンダリング画像           (右)参照画像

参照画像は、FaceRigの画像を使用させていただきました。目的外利用の気もしますので、問題があればお知らせください。

手順としては、以前は普通にレンダリングしたものを参照画像にして、テクスチャを白に初期化して学習していくという流れでしたので、参照画像を差し替えただけです。画像は普通にjpgをPILを使って読込み、numpyのarrayに変換しました。

実行結果

mitsuba2_update_texture_005.png

きちんと学習できていることが確認できました。更新後のテクスチャは下記のようになっています。
mitsuba2_update_texture_006.png

MeshLabで確認すると、ボディペイントに失敗した人みたいになっています。

mitsuba2_update_texture_001.png mitsuba2_update_texture_002.png

以下コード全体です。
head.html


posted by シンドラー at 22:45| Comment(0) | Rendering | 更新情報をチェックする

2020年04月25日

Mitsuba2のテスト その4

Mitsuba2のシーンファイルはXMLを使用していて、視点の調整などがちょっと面倒です。他のレンダラも同じような感じだったので、昔Appleseed Renderer用のXMLを出力するプログラムを作っていたので、それを参考にMitsuba2用のXMLを出力するものを作ってみました。

モデルの注意点として、shapeタグはobj, ply, serializedなどに対応していますが、1つのオブジェクトに複数マテリアルが含まれる場合は、serialized形式でないと駄目なようです[1]。serializedを使えばいいのかもしれませんが、以前他のレンダラ用に、マテリアルごとにobjを分割するプログラムを書いていたので、ちょっとファイルが増えてしまいますが、今回は分割して対応することにしました。

もう一つはテクスチャのアルファチャンネルの取り扱いで、普通にテクスチャを割り当てただけでは、透明度が反映されません。Mitsuba2では、BSDFにOpacity maskが用意されており、これを使うことで透明度を反映させることができました[2]。

mitsuba2_miku_004.png
[2]より引用

emitterに関しては、環境マップとしては1個しか設置できませんが、shapeにemitterを持たせて光源として扱うことはできます。今回、環境マップと、constant光源を試してみました。他にもareaやpointも指定できます[3]。

実行結果

あぴみくさんのモデルを使用させていただきました。GUI上で視点の変更や光源の種類などを設定して、XMLを出力・そのデータをMitsuba2でレンダリングして表示するツールを作ってみました。

mitsuba2_miku_001.png
自前でレンダリングしたもの(ほぼテクスチャ色+Phong)

mitsuba2_miku_000.png
環境マップ+ガンマ補正

mitsuba2_miku_002.png
constant光源

mitsuba2_miku_003.png
constant光源+ガンマ補正

また横道にそれて微分可能レンダリングのテストが進んでないですね…。

[1] https://mitsuba2.readthedocs.io/en/latest/generated/plugins.html#multiple-shapes
[2] https://mitsuba2.readthedocs.io/en/latest/generated/plugins.html#opacity-mask-mask
[3] https://mitsuba2.readthedocs.io/en/latest/generated/plugins.html#emitters
posted by シンドラー at 21:53| Comment(0) | Rendering | 更新情報をチェックする

2020年04月13日

Mitsuba2のテスト その3

続きです。まずは[1]の後半部分(環境マップの学習)です。これは前回のものができていればほぼそのままなので特に問題なかったです。

実行結果等
mitsuba2_bunny.html

環境マップの学習もいいですが、テクスチャマップの学習を試してみたいと思いました。サンプルデータとして、Pytorch3Dのcow_meshモデルを使用させていただきました。

1. xmlファイルの書き換え
[1]のbunny.xmlをコピーして、cow_mesh.xmlに書き換えます。今回、テクスチャを使いたかったので、[2]を参考に、shapeの部分を下記のように書き換えました。

変更前
  <shape type="ply">
    <string name="filename" value="bunny.ply"/>
    <bsdf type="conductor"/>
  </shape>
変更後
  <texture type="bitmap" id="myImage">
    <string name="filename" value="cow_texture.png"/>
  </texture>

  <bsdf type="diffuse" id="myMaterial">
    <ref name="reflectance" id="myImage"/>
  </bsdf>

  <shape type="obj">
    <string name="filename" value="cow.obj"/>
    <ref id="myMaterial"/>
  </shape>
conductorが金属反射っぽいですが、もしかするとここにテクスチャを設定できたかもしれません。

2. 学習パラメータの変更
  # 微分可能なシーンパラメータを探す
  params = traverse(scene)
  print(params)
上記でパラメータ一覧を確認できます。今回、マテリアルの画像データ(myMaterial.reflectance.data)を学習パラメータとしました。他は特に変更していないかと思います。

実行結果等
mitsuba2_cow.html

一応予定通り、見えている部分のテクスチャだけ学習できています。ノイズも学習しているっぽいので、もうちょっとレイの数を増やした方が良さそうです。視点を色々変えて描画すればテクスチャ全体の学習もできそうですので、次回ぐらいに試してみたいと思います。

[1] 最新物理ベースレンダラー Mitsuba2を触ってみる (3) 微分可能レンダリング編
[2] Mitsuba Documentation Version 0.5.0 (pdf)
posted by シンドラー at 21:21| Comment(0) | Rendering | 更新情報をチェックする

2020年04月12日

Mitsuba2のテスト その2

[1]を参考にさせていただき、微分可能レンダリングを試そうとしたのですが、OptiXでエラーが出ました。試しにOptiXのSDK-precompiled-samplesのプログラムを動かしてみたのですが、エラーが出て動きませんでした。色々試してみましたが結局駄目っぽかったので、グラフィックドライバを入れなおしたら動くようになりました。後はexrとかtbbなどaptで古いライブラリをインストールしていると、ninjaでビルドした時にリンクエラーが出て困りました。

今回は[1]の前半の、反射率の最適化を試しました。jupyter notebook上で行っているので、ファイルに出力するのではなくmatplotlibで表示して確認しました。Bitmapクラスの使い方が良くわからなかったのですが、適当にnumpyに変換してreshapeしたらうまくいったようです。

実行結果等
10_inverse_rendering.html

今回はOptiXのエラーであまり進みませんでしたが、次回後半の方を試してみたいと思います。

[1] 最新物理ベースレンダラー Mitsuba2を触ってみる (3) 微分可能レンダリング編
posted by シンドラー at 23:17| Comment(0) | Rendering | 更新情報をチェックする