はじめに
画像から物体を検出したり、認識したりする際に、画像の特徴量を数値化することが重要になります。
OpenCVのcv2.moments
関数はそのためのツールで、画像のモーメント(重心、面積など)を計算することができます。
本投稿ではcv2.moments
関数の使い方と応用例を紹介します。
モーメントとは
モーメントとは、画像の統計的な特徴量のことです。
例えば、物体の重心座標(x, y)、面積、回転角度などがモーメントから求められます。
モーメントは物体の不変特徴量なので、同じモーメントを持つ場合は同一の物体であると判断できます。
cv2.moments関数
モーメントはcv2.moments
関数を使って、簡単に計算することができます。cv2.moments
関数の引数と戻り値について説明します。
引数
名称 | 説明 |
---|---|
入力画像(必須) | モーメントを計算する入力画像。データ型はnp.int32 または np.float32です。 |
binaryImage(オプション) | True の場合、ゼロ以外のすべての画素値は 1 として扱われます。 このパラメータは画像のみに使用されます。 (デフォルト:False) |
戻り値
戻り値はディクショナリー型で、以下のようなモーメントの値となります。
{ 'm00': 0次の積率モーメント(輪郭などが囲む領域の面積), 'm10': x方向の1次の積率モーメント(輪郭の重心におけるx座標の期待値), 'm01': y方向の1次の積率モーメント(輪郭の重心におけるy座標の期待値), 'm20': x方向の2次の中心モーメント(輪郭の重心からのx軸方向の分散), 'm11': xy方向共分散(輪郭の重心からのx方向とy方向の分散の共分散), 'm02': y方向2次モーメント(輪郭の重心からのy方向の分散), 'm30': x方向3次モーメント, 'm21': xy方向2次共分散:輪郭の重心からのx軸方向とy軸方向の2次モーメントの共分散, 'm12': yx方向2次共分散:輪郭の重心からのy軸方向とx軸方向の2次モーメントの共分散, 'm03': y方向3次モーメント }
各モーメントの値は以下のように解釈されます。
m00
: 0次モーメントは、画像の面積に相当します。m10
とm01
: 1次モーメントは、画像の重心のx座標とy座標を表します。m20
、m11
、m02
: 2次モーメントは、画像の回転角度を求めるのに使用されます。- その他のモーメントは、より高次の特徴量を表します。
これらのモーメントから、以下のような画像の特徴量が計算できます。
- 面積: 0次の積率モーメント
m00
が面積となります。
面積 =m00
- 重心座標: 1次の積率モーメント
m10
、m01
から次の式で重心座標が計算できます
(x, y) = (m10
/m00
,m01
/m00
) - 楕円の長半径と短半径: 0次、2次のモーメントから、楕円の長半径と短半径が求められます。
x方向半径 = sqrt(4 *m20
/m00
)
y方向半径 = sqrt(4 *m02
/m00
) - 画像の回転角: 2次のモーメントから画像の回転角度を求められます。
回転角 = 0.5 *atan2(2 *m11
,m20
-m02
) - Huモーメント: 2次、3次のモーメントから、物体の形状を表す7つのHuモーメント(不変モーメント)が計算できます。これらは、スケール、平行移動、回転に対して不変な特徴量です。
特に重心座標と面積は、物体検出や認識などの多くのアプリケーションで重要な役割を果たします。
モーメントを利用することで、画像の基本的な統計量を簡単に得ることができます。
オプションのbinaryImage=True
を指定した場合、入力画像はあらかじめ2値化されている必要があります。2値画像のモーメントを計算することで、より単純化された形状の特徴量が得られます。
使い方
以下にサンプルコードを示します。
import cv2 import math # 画像を読み込む img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE) # 2値化する ret, thresh = cv2.threshold(img, 127, 255, 0) # モーメントを計算する M = cv2.moments(thresh) # 面積を出力 area = M['m00'] print('面積: ', area) # モーメントから重心座標を計算する cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) print('重心座標: ({}, {})'.format(cx, cy)) # モーメントから回転角度を計算する angle = math.degrees(0.5 * math.atan(2 * M['m11'] / (M['m20'] - M['m02']))) print('回転角度: {} degrees'.format(angle))
このコードでは、まず画像をグレースケールで読み込んで二値化(閾値127で二値化)しています。
2値画像からcv2.moments
関数でモーメントMを計算し、そのモーメントから重心座標(cx, cy)を求めています。
グレースケールで画像を読み込む方法と、二値化について下記を参考にしてください。
【Python・OpenCV】基礎を解説! 画像の読み込み方法(cv2.imread)
【Python・OpenCV】二値化による閾値処理を行うには(cv2.threshold)
おわりに
OpenCVのcv2.moments
関数とモーメントの活用方法についてご紹介しました。モーメントからは、画像の面積、重心座標、楕円の長短半径など、様々な特徴量が計算できることが分かりました。
これらのモーメント特徴量は、物体検出・認識、トラッキングなどのさまざまなプロセスで利用できます。
モーメントは画像の基礎的な統計量を表すシンプルな指標ですが、上手く活用すれば強力な性能を発揮してくれます。
単体で使うよりも、他の手法と組み合わせて使うことで、より高度な画像解析が可能になります。例えばモーメントから得られる重心座標を特徴点として使い、他の局所特徴量と組み合わせれば物体認識の精度が向上します。
画像処理の能力を高めるためには、色々な手法を組み合わせて使うことが重要です。モーメントもその有力な選択肢の1つとなるでしょう。
ご質問や取り上げて欲しい内容などがありましたら、コメントをお願いします。
最後までご覧いただきありがとうございました。
参考リンク
OpenCV: moments
Calculates all of the moments up to the third order of a polygon or rasterized shape.
■(広告)OpenCVの参考書としてどうぞ!■