【LabVIEW】Real-ESRGAN(NCNN版)で画像拡大

Real-ESRGANの【NCNN(コマンドライン版)】をLabVIEWから呼び出して変換が出来るようにプログラムを作成しました。

NCNNをデスクトップアプリとして使用することが出来るGUI版ついては下記の記事を参照ください。Torishima氏(@izutorishima)制作

プログラムの概要

  • Real-ESRGANのNCNN版を使用して画像を高画質化
    ※ソースコードの中にNCNNは含まれていません。GithubからDLしてください。
    https://github.com/xinntao/Real-ESRGAN
  • 変換したい画像をフォルダ単位またはファイルごとを選択することが出来ます。
    選択したフォルダの下位にあるフォルダ内画像を変換しないを選択することも出来ます。
    出力ファイルは選択したフォルダ内に「output」フォルダを作成し出力します。
  • 入力ファイルはBMP、JPEG、JPG、PNG、WebPに対応しています。
    ※NCNNはBMPに対応していないのでLabVIEWで一度PNGに変換しています。
  • 利用モデル、拡大率、保存形式についてはNCNNのヘルプに記載されていた通りの内容になっています。

LabVIEWサンプルファイル配布

LabVIEWファイルをGoogleドライブでダウンロード出来るようにしています。(LabVIEW2019で作成しています。)

https://drive.google.com/file/d/1TMzFk4nhY-8PCvJTEzc8y4vYCVzu-e8x/view?usp=sharing

※ファイルの使用については自己責任でお願いします。

※実行ファイルでの配布を予定はしていません。LabVIEW Community Editionを使用することで実行ファイルの作成が可能です。

プログラムの説明

プログラムの構造としては簡易ステートマシンの構造を採用しています。

タイプ定義で定義をした列挙定数を使用して、ケースストラクチャへ入力を行っています。

画像の拡大出来ます

ステートマシンのケース内容としては概要として下記のようにしています。

  1. 初期化
    フロントパネルをデフォルト値に設定&NCNNファイルパス設定を行います。
  2. 待機(イベント)
    『拡大開始』ボタンが押された場合は、NCNNで画像拡大する処理へ進みます。
    パネルを閉じた場合はプログラムを終了します。
  3. フォルダ&ファイル状態判別
    読み込まれたフォルダとファイルが正常かを確認してから、有効な画像拡張子以外のパスを除去します。
  4. 画像拡大
    NCNNで画像を拡大します。
  5. 終了
    プログラムを終了します。

2.待機のケースではタイムアウトに数値入力をしていないのでプログラムが一時停止するため、ループの速度を制限するための待機関数は入れていません。

初期化ケースについて

画像の拡大出来ます

プログラム開始直後に自動的に実行されるプログラムです。

1.『FP.Center』

プログラムを起動した直後に、フロントパネルウィンドウをメインディスプレイのセンターへ移動させます。

LabVIEWはVIが最後に保存された場合のウィンドウ位置を覚えています。「FP.Center」を入れている理由としては、実行ファイルとして配布をした場合に、開発環境のウィンドウ位置で表示されてしまうのを防ぐためです。

実行ファイルとして配布した場合に「FP.Center」が無いと、画面外にフロントパネルが表示されるということが起きたりします。(デュアルディスプレイや高解像度のディスプレイ環境で開発しているときは注意が必要です。)

2.『Default Vals.Reinit All』

制御器を全てデフォルトの値に戻します。開発環境の場合、デフォルト値以外の値が入っている場合があるので、VIを実行するときは一旦デフォルト値に戻すようにしています。

実行ファイルの場合、不要かもしれませんが初期化という意味合いでデフォルト値に戻すのがよいと思います。

3.『VIリファレンス閉じる』

正直、このプログラムであれば閉じなくても問題ないと思いますが念のため閉じています。プログラムのメモリ使用量が多い場合は閉じておくのをオススメします。

特に何度もリファレンスを開くようなプログラムは必ず閉じること

4.設定ファイルパス作成について

このプログラムでは画像を拡大したときにNCNNのファイルパスを保存するようにしています。毎回、NCNNのパス位置を設定するのが面倒なため。

メインVIまたは実行ファイルと同じフォルダ階層に『config.ini』ファイルを作成して、NCNNのパスを保存しています。

config.iniを作成するにあたって、フォルダパスを取得する必要があります。VIと実行ファイルで動作を変更する必要があるので、条件無効ストラクチャを使用して動作を分けています。

VIの場合はデフォルトケース、実行ファイルの場合はRUN_TIME_ENGINEケース

VIの場合は『現在のVIパス』からパスを取得します。現在のVIパスのままでは「C:\XXX\main.Vi」となっているため、『パスをストリップ関数』を使用してパスを「C:\XXX」に変更します。

実行ファイルの場合はアプリケーションディレクトリパスで直接、「C:\XXX」のパスが取得できます。

作成したconfig.iniのファイルが存在するかを確認します。サブVI内でファイルの有無を確認します。

5.ファイルの有無を確認について

ファイルパスが有効か?ファイルが存在するか?は頻繁に確認するため、まとめてサブVIとして作成をしています。(File&Folder-Check.vi)

File&Folder-CheckサブVI内では、入力されたファイルパスが有効かどうかと、ファイルが存在するかどうかを確認することが出来ます。

ファイルが存在しないかパスが無効な場合はダイアログとして表示させるかを決めることも出来ます。

このプログラムに限らず、読み込んだファイルや書き込んだファイルの位置が問題ないかを確認するための機能は必要です。

6.iniファイルの作成または読み込み

5.のファイルパスでファイルが存在するのかを確認しました。ファイルが無い場合と有る場合とで処理を分ける必要があります。

ファイルが存在しない場合はiniファイルを新規で作成し、セクションとキーを書き込みます。

ファイルが存在する場合は、存在したiniファイル(configファイル)のキーに記載されているNCNNのファイルパスを読み込みます。

NCNNのファイルパスを読み込んだ後、ファイルパスの位置にNCNNが存在するのかを確認します。

NCNNがiniファイルのキーに記載されている位置に存在する場合は、そのままフロントパネルのNCNNファイルパスの制御器へパスを書き込みます。もし存在しないのであれば「空パス」を書き込みます。

後々に存在しないファイルの位置を参照してプログラムを実行されないようにするためのエラー対策としてNCNNが存在するかどうかを確認してから制御器へファイルパスを書き込んでいます。

待機ケース

待機のケース内部にイベントケースを配置しています。イベントケースとしては下記を設定しています。

  • タイムアウト
  • 拡大開始ボタン(値変更)
  • パネルを閉じる?

タイムアウトイベント

タイムアウトイベントについてはタイムアウトするまでの待機時間に数値を入力していないため、タイムアウトイベントが発生しません。

タイムアウトしないため他のイベントが発生するまで、イベントケース前で動作が一時停止しています。

拡大開始ボタン(値変更でイベント)

iniファイルから読み込んだNCNNのファイルパスとフロントパネルの制御器に入力されているファイルパスが違う場合は、使用するNCNNのファイルパスを上書き(変更)します。

iniファイルに記載されているNCNNパスから変更をしたい場合もあるため。

使用されるNCNNファイルパスが確定したら、iniファイルに新しいファイルパスを書き込みます。

併せて、ファイルパスが正しいかどうかの確認も行います。もし、ファイルパスが正しくない場合はダイアログを表示するようにしています。

本来ならiniファイルを書き込むよりも前にファイルの存在有無を確認した方がパフォーマンスとしては良くなります。

7.イベントの移動について

NCNNのファイルパスに問題が無ければ次のイベント『フォルダ&ファイル状態判別』へ移動します。ファイルパスに問題がある場合は再度『待機』に戻ります。

NCNNのファイルパスが正しくないと画像変換を実行する時にエラーが発生するため、ファイルパスが正しくない場合は次のイベントへ進まないようにする必要があります。

8.NCNN設定データ&フォルダ&ファイルパスについて

NCNNの設定データについてはテキストリンクをクラスタにしています。

クラスタデータにすることで、ワイヤーの本数を減らすことが出来ます。また、Real-ESRGANのオプションが増えた場合の対応が楽になるはず。

LabVIEWの基本機能のフォルダまたはファイルパス制御器です。フォルダパスまたはファイルパスのどちらでも読込が出来るようにしています。

パネルを閉じる?イベント

待機状態の時にウィンドウの「×」を押した場合にフィルタイベントの「パネルを閉じる?」イベントになります。

ダイアログとして「プログラムを終了するか?」を「はい」と「いいえ」で確認します。終了する場合は終了シーケンスへ移動し、終了しない場合は、パネルを閉じる動作を破棄して待機イベントに移動します。

ファイル&フォルダ状態の判別ケース

読み込んだ『ファイル&フォルダパス』がファイルかフォルダかを判別した後に状況に合わせて、画像パスの作成を行います。

9.ファイル&ディレクトリ情報&再帰ファイルリスト

フォルダ&ファイルパスで入力したパスを『ファイル&ディレクトリ情報』関数へ入力することで『フォルダパス』か『ファイルパス』かを判別することが出来ます。フォルダパスの場合に「True」が出力されます。

フォルダの場合はTrueケースにある『再起ファイルリスト』を使用することでフォルダ内にあるファイルのパス全てを配列で出力することが出来ます。

全てのファイルパスなので、フォルダ内にある下位のフォルダパスやNCNNで取り扱うことが出来ない拡張子のファイルパスも含まれています。

10.初期化配列&置換で配列へ変換

ファイルパスの場合は『ファイル&ディレクトリ情報』からFalseが出力されるため、Falseケースで動作します。

Trueケースでは『再起ファイルリスト』関数を使用したことでケースストラクチャの出力トンネルがファイルパス配列になっています。

定数のままではケースストラクチャの出力トンネルにあるファイルパス配列へ接続できないため、定数を配列へ変換する必要があります。

初期化配列で、要素1個だけのファイルパス配列を作成し、配列置換でファイルパス配列の要素をファイルパス定数の値に置換します。

これで、ファイルパス定数をファイルパス配列へ変換することが出来ました。

作成したファイルパスの配列データのファイル拡張子を読み取って、画像データのパスだけを抜き取るためにForループを使用して処理を行います。

Forループのファイルパス出力は『指標付け+条件』の組み合わせに設定をすることで、条件に合った(指定拡張子のファイル)のみをファイルパスとして出力をするように設定しています。

11.ファイルパスから拡張しを取得&BMPファイルをPNGへ変換

Forループにファイルパス配列を指標付けで入力します。入力したファイルパスから『ファイル拡張子を取得』関数を使用してファイルパスの拡張子を取得します。

ファイルパスの拡張子が、「BMP」の場合だけBMPからPNGへファイルを変換します。サブVI内で画像変換処理を実施。NCNNがBMPを標準で読み込めないため、変換が必要です。

それ以外の場合は、「ファイル拡張子を取得」から取得した拡張子を、そのままケースストラクチャから出力します。

サブVI『BMP to PNG』の内部はLabVIEWにあるピクチャ関数を使用してBMPのファイルを読み込んでからPNGで再保存しています。

元のBMPファイルは削除せずに同一のフォルダにPNGファイルを作成するようにしています。

併せてBMPのファイルパスからPNGへ拡張子を変換したファイルパスを出力するようにしています。

12.指定拡張子以外のファイルを除外

再帰ファイルリスト関数を使用すると、フォルダ内にある全てのファイルパスが作成されます。

画像ファイル以外のファイルパスも含まれる可能性があるので、NCNNが取り扱える拡張子以外のファイルパスは除外する必要があります。

NCNNで扱える拡張子は【JPG、JPEG、PNG、WEBP】になります。入力されたファイルの拡張子が指定拡張子に該当するかを比較関数『等しい?』を使用して判別します。

比較関数『等しい?』は定数と配列の組み合わせで接続することが可能です。出力結果はブール配列になります。

出力されたブール配列を『配列要素のOr』へ入力することで、何れかの拡張子に該当している場合、Trueとして出力されます。

再帰ファイルリストは指定したフォルダの下位にあるフォルダパスも含まれているため、必要に応じて、下位フォルダにある画像ファイルも変換に含めるかどうかを選択することが出来ます。

下位のフォルダにある画像ファイルを変換しない場合は、選択したフォルダパスとファイルパスからファイルを除外(ストリップ)したパスを比較することで同一のフォルダパスか比較することが出来ます。

同一のフォルダであれば、Trueが出力されます。

ファイルの拡張子のブールとフォルダパスのブールが両方Trueの場合のみをTrueとして出力するために論理のAND関数を使用します。

AND関数から出力されるブールをForループの条件端子へ入力することで、拡張子とフォルダパスの条件を満たしたファイルパスだけを出力することが出来ます。

13.配列の要素数が0の場合はダイアログを表示

ファイルパスを除外した場合に該当するファイルが「0」の可能性もあるので、エラー処理的な意味で入れてあります。要素0の場合は、待機状態へ戻るようになっています。

画像拡大ケース

ファイルパスを生成した後、NCNNを使用して画像の拡大作業を行います。

同時に複数の画像を変換するのは難しいのでForループを使用して1つずつ変換していきます。

13.NCNNのコマンドを生成

NCNNの設定データと画像ファイルパスに基づいて、NCNN用のコマンドを作成するためのサブVIです。

NCNNの設定

上図のようなNCNN設定の場合には下記コマンドを作成します。※コマンドの意味についてはNCNNのヘルプファイルを参照ください。

生成されるコマンド

realesrgan-ncnn-vulkan.exe -i C:\NCNN\002.jpg -o C:\NCNN\output\002.jpg -n realesr-animevideov3 -s 4 -f jpg

画像の拡大出来ます

NCNNのコマンドを生成するサブVIの中身になります。

コマンドを最初から文字列連結で組み合わせる方法もありますが、コマンド毎に半角スペースを入れる必要があったり、後で仕様追加がされたときにでも容易に変更が出来るように文字配列で構成しています。

あと、文字列連結よりもコマンドを作るのが容易な気がしたため。

配列が完了した後にForループを使用して、配列ないの文字列を連結して一つの文字列にしています。

最終的にサブVIからはNCNNが保存されているフォルダパスとコマンド、変換される画像のファイルパスが出力されます。

生成されたコマンドからNCNNを実行してファイルを生成します。

NCNNはコマンドプロンプトから実行する形式のファイルなので、LabVIEWにある『システム実行』関数を使用してコマンドプロンプトを呼び出します。

システム実行のコマンドラインへ「cmd」と入力することでコマンドプロンプトを呼び出せます。

標準入力に生成したコマンドを入力し、作業ディレクトリにNCNNのあるフォルダパスを入力します。

作業ディレクトリに指定のフォルダパスを入力していないとデフォルトフォルダが「C:\」になっています。

終了ケース

最後に終了ケースについてですが、『パネルを閉じる』のイベントを実行したときに指定されているケースです。実際はこのケースが実行される前にWhileループは停止をして、実行ファイルの場合は「LabVIEW終了」が実行されます。

以上が、LabVIEWを使用してReal-ESRGAN(NCNN版)を実行する方法になっています。