これはなに
入力された画像がRGB-orderかBGR-orderかを判定するモデルを作った話です。ただの悪ノリです。
自然画像であれば見分けがつくでしょうが、例えばただの真っ赤な画像があったとき、元が赤か青かなんて50%でしか当たらないので解けません。でもAIは最強なのでなんとかしてくれると信じて学習させます。
なぜつくったか
Pythonで画像処理をする際に、OpenCVやPillowを使用して画像を読み込むケースは多いかと思います。
特に何もせずOpenCVでRGB画像を読み込むと画像のチャンネルはBGR-orderになり、Pillowで読み込むとRGB-orderになります。
そのため、OpenCVを使用して学習したモデルをPillowを使ったコードに適用すると思った性能を発揮しなかったり、前処理としてデータセットの平均RGB値を画素から引こうと思って間違った計算をしてしまったりすることがあります。
これらは、処理しようとしている画像がRGBかBGRか判定できれば防げるはずです!なので入力された画像がRGB-orderかBGR-orderかを判定するモデルを作りましょう
学習方法
単純な教師あり学習をします。ある画像に対して、それがRGB-orderなら0、BGR-orderなら1というラベルを与えて、モデルに2値分類させればOKです。
1枚の画像からオンラインでRGB-order/BGR-orderに変換することができるのでデータセットは適当なもので良いです。普段私は超解像用のデータセットを使用することが多いのでDIV2Kデータセットを使用しました。評価は真面目にやっていませんがBSD100データセットを使用しました。
実装
repo: https://github.com/S-Nakamur-a/channel-order
pytorch lightningを使用しました。半精度学習が1行追加でできたり、バッチサイズをよしなにやってくれたり、ちょっと面倒な部分を簡単に出来るようにしてくれているのが好きです。
モデルはefficientnet_pytorchからEfficientNetを持ってくるだけにしました。
optimizerはAdam+StepLRです。全く真面目にチューニングしていません。
結果
Urban100のLR画像100枚に対して、RGB-order / BGR-orderの2種類を作成し、両方共を正しくRGB / BGR判定できた場合のみを正解としたとき、precisionは67%でした。
正解できたパターン例はこんな感じです
思ったより精度低いな...と思って間違いケースを見てみたのですが、白黒画像だったり下の画像のように人間にも判別できなかったりするようなものだったので納得です。いくつか「これはギリギリ判定できないか...?」というものも混じっていたのでまだ学習の余地はありそうです。
ちなみにvalidation accuracyは85%ほどだったのですが、学習時のaccuracyは「ランダムでRGB/BGRを変化させた画像1枚に対してRGB/BGRを当てられれば正解」で定義していたのでちょっと意味合いが違います。
考察
特に考察することもないんですが、まぁ出来ないものは出来ないよな、という気持ちと、空とか木とか人とか写ってるとやっぱり出来るんだなという気持ちです。
自己教師学習はデータセットの準備が簡単だから良いなぁという気持ちや、物体・テクスチャを認識した上でその自然な色合いを記憶する必要があるところがrotation classificationやJigsawのような自己教師で特徴表現学習するやつにちょっと似ているところがあるなという気持ちにもなりました。
結論
こんなモデルを作るより、チャンネル順序まで含めて型がある言語を使うか、自分でクラスを定義したほうがずっと健全だと思います。
僕は個人開発ではRGBImageとBGRImageというクラスを定義してOpenCVやPillowは隠蔽することでココらへんのミスを極力減らしています。ちょっと面倒なので良い方法を募集中です