Pythonで画像処理を実装する時に様々なライブラリがありますね。ネット上のサンプルコードなどを見ていると、それぞれの仕様を確認せずに混在して使っている人も多いように見えます。動けば良いという事であればそれまでなのですが、トラブルによる無駄な時間を削減したいという事であれば、あえて使用するライブラリを絞り込んで、その仕様を十分に理解するのも良いと考えています。(急がば廻れ的な考えです)
そこで私は基本的にOpenCVとNumPyだけでコーディングするようにしています。もちろん時と場合によってはscikit-imageやPillowも使いますが、基本的にこの2つのライブラリの経験値を重点的に上げる事で品質向上と全体工期の短縮を図っている感じですね。
さて、native版のOpenCVでは画像データの保持にcvMatクラスを使っています。これは名前の通り行列を扱うクラスですが、2次元画像は2次元行列と同じデータ構造で表現できますね。NumPyも同様です。こちらはN次元行列を扱う代数計算用のライブラリですが、多次元データの扱いやすさから画像データを格納するデータ形式としても優れていると思います。これらの理由によると思われますがPython版のOpenCVは、画像データをNumPyオブジェクトとして扱っているのでしょう。
しかし、ここで一つ大きな問題が。
OpenCVとNumPyで次元表現が何故か逆なのです。(まぁ理由は想像つきますが割愛します。行列をどれだけ重視したかという感じでしょう)
元画像をOpenCVのresize関数で縦横半分 にしたいとします。この時、リサイズ後の画像サイズをcv2.resize関数のdsize引数に指定しますが、縦横の指定順がNumPyと逆になります。
import numpy as np import cv2 src = cv2.imread('figure1.png') h, w, _ = src.shape # これは誤り dst_shape = (h // 2, w // 2) dst = cv2.resize(src, dsize=dst_shape) cv2.imwrite('figure2.png', dst) # こちらが正しい dst_shape = (w // 2, h // 2) dst = cv2.resize(src, dsize=dst_shape) cv2.imwrite('figure3.png', dst)



Pythonで画像処理を実装し始めた当初に何度かハマったのがこの問題で、特に像をリサイズする際に問題になりました。しかも今でも油断すると間違える…。特に画像サイズ情報をtupleで保持している時などに、それをそのまま使ってしまってハマることが多い気がします。
この一件以来、自分の中では次元表現は全てNumPy形式で統一するようにしてOpenCV関数呼び出し時に変換するようにしました。