画像認識機械学習エンジニアは,前処理で画像のリサイズをすることが多いだろう.
224や,608などは,界隈では見慣れた数字になっていると思う.
それ故に,無意識に色々リサイズしてしまうのだが,今回,苦しめられたので皆さんのお役に立つかは分かりませんが共有します
起きたこと
あるクラス分類の画像認識Pで,モデルが吐くクラス事後確率と,画像を並列して表示するUIを作成して時のこと.
以下の作業を同時に行っていた.
1,学習済みモデルに対して定性評価するために,リサイズ済み画像で推論を行い,事後確率をグラフにまとめていた.
2,一方でUIに焼き込む際には,リサイズ前の画像に事後確率を焼き込んで,ビデオにするという突貫工事を行なっていた.(こちらはスクリプト内でリサイズしていた)
この際に,事後確率を観察していると,
「んっ??,全然違う値を出力している...」
となった.
モデルも同じで,前処理も同じだ.
試しに入力画像も保存してみるがほぼ同じ...(と思っていた)
原因
原因は,リサイズの手法が異なっていたことだった.
関係ないだろうと思っていたのだが,
1の作業の画像はffmpeg,
2の作業では,opencv
でリサイズしてたのが原因だった.
そして,見た目では同じ画像も,numpy_arrayで出力してみると微妙な違いがあった!
それぞれのリサイズは以下のようにしていた.単純だ...
opencvでのリサイズ
img_resized = cv2.resize(img,(224,224))
ffmpegでのリサイズ
command = f'ffmpeg -i {INPUT} -vodec png -vf scale={size}:{size} -r {FRAME_RATE} {OUTPUT}'
subprocess.call(command,shell=True)
ここで原因となったのは,Interpolateを指定していなかったことだ.
Interpolateとは
画像の補完方式だ.
要は,画像を圧縮するわけだからなくなってしまう情報がある.そこを保管する方式は色々あるのだ.
Opencv の公式ページには以下のように手法が書かれている.
INTER_NEAREST - a nearest-neighbor interpolation
INTER_LINEAR - a bilinear interpolation (used by default)
INTER_AREA - resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method.
INTER_CUBIC - a bicubic interpolation over 4x4 pixel neighborhood
INTER_LANCZOS4 - a Lanczos interpolation over 8x8 pixel neighborhood
ちなみにdefaultはINTER_LINEAR
これが,ffmpegでは,CUBIC
であるのが原因だった.
まとめ
もちろんプロの方だと,自分のようなことは起こさないと思いますが,自分はここで少し苦戦したのでまとめました.