opencv基盤 49画像輪郭02モーメント機能 cv2.moments()->(形状解析、物体検出、画像認識、マッチング)

Moments features は、画像解析とパターン認識のための特徴表現方法であり、画像の形状、幾何学的特徴、統計情報を記述するために使用されます。モーメント特徴は、画像内のオブジェクトの認識、形状の検出、画像分類の実行などのタスクに使用できます。

モーメント特徴は、画像ピクセルの高次モーメントを計算することによって特徴を抽出します。これらのモーメントは、画像の中心、スケール、回転、形状などのプロパティを表すことができます。以下に、一般的な画像モーメントの特徴をいくつか示します。

  1. ゼロ次モーメント: 画像の全体的な明るさまたは面積を表し、通常は画像内のピクセル数として表されます。

  2. 一次モーメント: 画像の重心、平均位置、分布を記述します。これらは画像の中心位置を計算するために使用されます。

  3. 中心モーメント: 重心に対する画像領域の分布を表します。中心モーメントは、画像の回転特性と並進特性をキャプチャします。

  4. 正規化されたモーメント: スケールと回転の不変性を得るためにモーメントが正規化されます。正規化されたモーメントは照合と識別に使用できます。

  5. **Hu モーメント: **回転、平行移動、スケール不変の 7 つの基本モーメントに基づいて構築されます。Hu 不変モーメントは、画像マッチングとパターン認識に使用されます。

画像の重心は何ですか?

画像の重心とは、画像の幾何学的中心を表す概念である。2 次元平面上では、画像の重心は画像内のすべてのピクセルの平均位置、つまり画像の重心または幾何学的中心を指します。

バイナリ イメージ (白黒イメージ) の場合、重心は次のように計算できます。

画像内の各ピクセルを座標 (x, y) を持つ点として扱います。各ピクセルについて、その x 座標の合計と y 座標の合計を計算します。
合計を画像内のピクセルの合計数で割って、x 座標と y 座標の平均値を取得します。これが重心の座標です。
重心の座標は、画像の水平方向と垂直方向の平均位置を表します。実際のアプリケーションでは、重心は通常、オブジェクトの位置、形状の中心など、画像の位置情報を記述するために使用されます。マルチチャンネル カラー イメージの場合、各チャンネルの重心を個別に計算できます。

モーメント機能のアプリケーション シナリオ

モーメント特徴には、画像処理やパターン認識の分野で多くの応用シナリオがあり、画像の形状、幾何学的特性、分布を記述するために使用できます。以下に、一般的なモーメント機能のアプリケーション シナリオをいくつか示します。

  1. オブジェクトの認識と分類: モーメント特徴を使用して、画像内のオブジェクトの形状と幾何学的な特徴を抽出し、オブジェクトの認識と分類を行うことができます。モーメントの特徴を比較することで、物体が特定のカテゴリに属する​​かどうかを判断できます。

  2. オブジェクト検出: コンピューター ビジョンでは、オブジェクト検出とは、画像内の特定のオブジェクトの位置を見つけることを指します。モーメント特徴を使用すると、物体の形状と輪郭を検出できるため、物体の位置を特定するのに役立ちます。

  3. 画像マッチング: モーメント特徴を画像マッチングや位置合わせに使用でき、2 つの画像のモーメント特徴を比較することで、画像間の類似性や変換関係を見つけることができます。

  4. 画像圧縮・符号化: 画像の圧縮・符号化にモーメント特徴を利用でき、画像の主要な幾何情報を抽出することで画像データの保存容量を削減できます。

  5. 画像セグメンテーション: 画像セグメンテーションは画像をさまざまな領域に分割することであり、モーメント特徴を使用してさまざまな領域の形状と幾何学的特性を記述することができるため、画像のセグメント化に役立ちます。

  6. 医用画像分析: 医療分野では、モーメント特徴を使用して医用画像内の組織、器官、病変を分析し、形状や幾何学的特徴を抽出できます。

  7. 指紋認識: 指紋画像の幾何学的特徴を抽出して指紋認識と比較を実現することにより、モーメント特徴を指紋認識に使用できます。

  8. リモートセンシング画像解析:リモートセンシング画像において、モーメント特徴を利用して地上物体の形状や分布を抽出し、土地利用や環境モニタリングなどの応用を実現します。

モーメントの計算: モーメント関数

OpenCV は函数 cv2.moments()画像を取得するモーメント機能を提供します。通常、関数 cv2.moments() を使用して取得された輪郭特徴を「輪郭モーメント」と呼びます。プロファイル モーメントはプロファイルの重要な特徴を説明しており、プロファイル モーメントを使用して 2 つのプロファイルを簡単に比較できます。

関数 cv2.moments() の構文形式は次のとおりです。

retval = cv2.moments( array[, binaryImage] )

  • 配列: 点セット、グレースケール イメージ、またはバイナリ イメージにすることができます。配列が点セットの場合、関数はこれらの点セットを輪郭の頂点として扱い、点セット全体を独立した点として扱うのではなく輪郭として扱います。
  • binaryImage: このパラメータが True の場合、配列内のゼロ以外の値はすべて 1 として扱われます。このパラメータは、パラメータ配列が画像の場合にのみ有効です。

この関数の戻り値 retval はモーメント機能であり、主に次のものが含まれます。

(1) 空間モーメント

  • ゼロモーメント:m00
  • 最初の瞬間: m10、m01
  • セカンドモーメント: m20、m11、m02
  • 3次モーメント:m30、m21、m12、m03
    (2)中心モーメント
  • 二次中心モーメント: mu20、mu11、mu02
  • 3次中心モーメント:mu30、mu21、mu12、mu03
    (3) 正規化中心モーメント
  • 2 次 Hu モーメント: nu20、nu11、nu02
  • 3 次 Hu モーメント: nu30、nu21、nu12、nu03

上記のモーメントは公式に従って計算され、ほとんどのモーメントは比較的抽象的です。しかし、モーメントが一致していれば、2 つの等高線が一致していることは明らかです。ほとんどのモーメントは数式で計算される抽象的な特徴ですが、
0次モーメント「m00」の意味はより直感的であり、等高線の面積を表します。

モーメント特徴関数 cv2.moments() によって返される固有値を使用して、2 つの輪郭が類似しているかどうかを比較できます。たとえば、2 つの等高線がありますが、それらが画像内のどこに現れても、関数 cv2.moments() の m00 モーメントを使用して、それらの領域が一致しているかどうかを判断できます。

位置が変化すると、輪郭の面積や周囲長などの特徴は変化しませんが、位置の変化に応じて高次の特徴が変化します。多くの場合、異なる場所にある 2 つのオブジェクトの一貫性を比較したいと考えます。この問題を解決する方法は、中心モーメントを導入することです。中心モーメントは、平均を減算することによって並進不変性を取得するため、異なる位置にある 2 つのオブジェクトを比較して一致させることができます。明らかに、中心モーメントの並進不変性により、2 つの物体の位置関係を無視できるようになり、異なる位置にある 2 つの物体の一貫性を比較するのに役立ちます。

平行移動の不変性を考慮することに加えて、サイズが一貫していないスケーリングされたオブジェクトの一貫性も考慮します。つまり、画像がスケーリング前後で安定した特徴量を持つことが期待されます。つまり、スケーリングの前後で画像の固有値が同じになるようにします。明らかに、中心モーメントにはこの性質がありません。たとえば、同じ形状でサイズが異なる 2 つのオブジェクトは、異なる中心モーメントを持ちます。

正規化された中心モーメントは、オブジェクトの合計サイズで割ることによってスケール不変になります。上記の計算を通じて、物体の正規化された中心モーメント属性値を抽出します。この属性値は、平行移動不変性だけでなく、スケーリング不変性も持ちます。

OpenCV では、関数 cv2.moments() が上記の空間モーメント、中心モーメント、正規化中心距離を同時に計算します。

例: 関数 cv2.moments() を使用して画像の特徴を抽出します。

コードは以下のように表示されます。


import cv2
import numpy as np
o = cv2.imread('moments.bmp')
cv2.imshow("original",o)
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,
 cv2.RETR_LIST,
 cv2.CHAIN_APPROX_SIMPLE)
n=len(contours)
contoursImg=[]
for i in range(n):
 temp=np.zeros(o.shape,np.uint8)
 contoursImg.append(temp)
 contoursImg[i]=cv2.drawContours(contoursImg[i],contours,i,255,3)
 cv2.imshow("contours[" + str(i)+"]",contoursImg[i])
print("观察各个轮廓的矩(moments):")
for i in range(n):
 print("轮廓"+str(i)+"的矩:\n",cv2.moments(contours[i]))
print("观察各个轮廓的面积:")
for i in range(n):
 print("轮廓"+str(i)+"的面积:%d" %cv2.moments(contours[i])['m00'])
cv2.waitKey()
cv2.destroyAllWindows()

この例では、まず関数 cv2.moments() を使用して各輪郭の特徴を抽出し、次にステートメント
cv2.moments(contours[i])['m00']) を使用して各輪郭モーメントの領域情報を抽出します。 。

操作の結果は次のようになります。

观察各个轮廓的矩(moments):
轮廓0的矩:
 {'m00': 14900.0, 'm10': 1996600.0, 'm01': 7800150.0, 'm20': 279961066.6666666, 'm11': 1045220100.0, 'm02': 4110944766.6666665, 'm30': 40842449600.0, 'm21': 146559618400.0, 'm12': 550866598733.3334, 'm03': 2180941440375.0, 'mu20': 12416666.666666627, 'mu11': 0.0, 'mu02': 27566241.666666508, 'mu30': 1.52587890625e-05, 'mu21': 2.09808349609375e-05, 'mu12': 6.198883056640625e-05, 'mu03': 0.000244140625, 'nu20': 0.05592841163310942, 'nu11': 0.0, 'nu02': 0.12416666666666591, 'nu30': 5.630596400372416e-16, 'nu21': 7.742070050512072e-16, 'nu12': 2.2874297876512943e-15, 'nu03': 9.008954240595866e-15}
轮廓1的矩:
 {'m00': 34314.0, 'm10': 13313832.0, 'm01': 9728019.0, 'm20': 5356106574.0, 'm11': 3774471372.0, 'm02': 2808475082.0, 'm30': 2225873002920.0, 'm21': 1518456213729.0, 'm12': 1089688331816.0, 'm03': 824882507095.5, 'mu20': 190339758.0, 'mu11': 0.0, 'mu02': 50581695.5, 'mu30': 0.0, 'mu21': 0.0, 'mu12': 0.0, 'mu03': 0.0, 'nu20': 0.16165413533834588, 'nu11': 0.0, 'nu02': 0.042958656330749356, 'nu30': 0.0, 'nu21': 0.0, 'nu12': 0.0, 'nu03': 0.0}
轮廓2的矩:
 {'m00': 3900.0, 'm10': 2696850.0, 'm01': 273000.0, 'm20': 1866699900.0, 'm11': 188779500.0, 'm02': 19988800.0, 'm30': 1293351277725.0, 'm21': 130668993000.0, 'm12': 13822255200.0, 'm03': 1522248000.0, 'mu20': 1828125.0, 'mu11': 0.0, 'mu02': 878800.0, 'mu30': 0.0, 'mu21': 0.0, 'mu12': 0.0, 'mu03': 0.0, 'nu20': 0.1201923076923077, 'nu11': 0.0, 'nu02': 0.05777777777777778, 'nu30': 0.0, 'nu21': 0.0, 'nu12': 0.0, 'nu03': 0.0}
观察各个轮廓的面积:
轮廓0的面积:14900
轮廓1的面积:34314
轮廓2的面积:3900

ここに画像の説明を挿入

輪郭の面積を計算する:contourArea関数

opencvには別途輪郭面積を計算する機能もありますcontourArea函数

関数 cv2.contourArea() は、輪郭の面積を計算するために使用されます。この関数の構文は次のとおりです。

retval =cv2.contourArea(輪郭 [, 方向性] ))

式中の戻り値retvalは面積値となります。

式には 2 つのパラメータがあります。

  • 輪郭は輪郭です。
  • Oriented はブール値です。True の場合、戻り値には輪郭が時計回りか反時計回りかを示すプラス/マイナス記号が含まれます。このパラメータのデフォルト値は False で、返される retval が絶対値であることを意味します。

コード例: 関数 cv2.contourArea() を使用して、各輪郭の面積を計算します。


import cv2
import numpy as np
o = cv2.imread('moments.bmp')
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,
 cv2.RETR_LIST,
 cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow("original",o)
n=len(contours)
contoursImg=[]
for i in range(n):
 print("moments["+str(i)+"]面积=",cv2.contourArea(contours[i]))
 temp=np.zeros(o.shape,np.uint8)
 contoursImg.append(temp)
 contoursImg[i]=cv2.drawContours(contoursImg[i],
 contours,i,(255,255,255),3)
 cv2.imshow("moments[" + str(i)+"]",contoursImg[i])
cv2.waitKey()
cv2.destroyAllWindows()

操作結果:

moments[0]面积= 14900.0
moments[1]面积= 34314.0
moments[2]面积= 3900.0

上記のm00で取得したものと同じであり、グラフィック表示も同じであることがわかります。
ここに画像の説明を挿入

コード例: 上記に基づいて、面積が 15,000 を超える等高線を除外します。

コードは以下のように表示されます。

import cv2
import numpy as np
o = cv2.imread('moments.bmp')
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,
 cv2.RETR_LIST,
 cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow("original",o)
n=len(contours)
contoursImg=[]
for i in range(n):

 temp=np.zeros(o.shape,np.uint8)
 contoursImg.append(temp)
 contoursImg[i]=cv2.drawContours(contoursImg[i],
 contours,i,(255,255,255),3)
 if cv2.contourArea(contours[i]) > 15000:
  print("moments[" + str(i) + "]面积=", cv2.contourArea(contours[i]))
  cv2.imshow("moments[" + str(i)+"]",contoursImg[i])
cv2.waitKey()
cv2.destroyAllWindows()

ステートメント「if cv2.contourArea(contours[i])>15000:」を使用して面積値をフィルターし、ステートメント「cv2.imshow("contours[" + str(i)+ "]", contoursImg[ i])」と表示されます。

操作結果:

moments[1]面积= 34314.0

ここに画像の説明を挿入

輪郭の長さ (周囲) を計算します: arcLength 関数

関数 cv2.arcLength() は輪郭の長さを計算するために使用され、その構文形式は次のとおりです。

retval = cv2.arcLength( 曲線、閉じた )

式の戻り値retvalは輪郭の長さ(周囲長)です。

上の式には 2 つのパラメータがあります。

  • 曲線は輪郭です。
  • Closed は、輪郭が閉じているかどうかを示すブール値です。値が True の場合、輪郭が閉じていることを意味します

例: 平均よりも長い画像の輪郭を表示します。

import cv2
import numpy as np
#--------------读取及显示原始图像--------------------
o = cv2.imread('moments.bmp')

#--------------获取轮廓--------------------
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,
 cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)
#--------------计算各轮廓的长度之和、平均长度--------------------
n=len(contours) # 获取轮廓的个数
cntLen=[] # 存储各轮廓的长度
for i in range(n):
 cntLen.append(cv2.arcLength(contours[i],True))
 print("第"+str(i)+"个轮廓的长度:%d"%cntLen[i])
cntLenSum=np.sum(cntLen) # 各轮廓的长度之和
cntLenAvr=cntLenSum/n # 轮廓长度的平均值
print("轮廓的总长度为:%d"%cntLenSum)
print("轮廓的平均长度为:%d"%cntLenAvr)

操作結果:

第0个轮廓的长度:498
第1个轮廓的长度:782
第2个轮廓的长度:254
轮廓的总长度为:1534
轮廓的平均长度为:511

コードサンプルの元の画像

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/hai411741962/article/details/132180950