輪郭に関する更なる関数

目的

このチュートリアルでは
  • 凸性の欠陥とその検出方法について学びます.
  • 点とポリゴン(多角形)の最短距離の計算方法を学びます.
  • 形状のマッチングについて学びます.

理論と実装

1. 凸性の欠陥

凸性の欠陥を見つけるための関数は cv2.convexityDefects() です.使い方は以下のようになります:

hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)

Note

convex hullの計算をする時に凸性の欠陥検出をするためには returnPoints = False とフラグを指定しなければいけません.

返戻値はarray型のデータになり,各行に3つの数値 - [ 始点, 終点, 最も遠い点, 最も遠い点までの近似距離] を指します.以下にその例を示します.まず初めに始点と終点を結ぶ線を引き,最も遠い点に円を描きます.最初の3個の値は cnt のインデックスだという点に注意してください.そのため,点の座標を得るためには``cnt`` から取得しなければいけません.

import cv2
import numpy as np

img = cv2.imread('star.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 127, 255,0)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt = contours[0]

hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)

for i in range(defects.shape[0]):
    s,e,f,d = defects[i,0]
    start = tuple(cnt[s][0])
    end = tuple(cnt[e][0])
    far = tuple(cnt[f][0])
    cv2.line(img,start,end,[0,255,0],2)
    cv2.circle(img,far,5,[0,0,255],-1)

cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

結果は以下のようになります:

Convexity Defects

2. 点とポリゴン(多角形)のテスト

cv2.pointPolygonTest 関数は点と輪郭を結ぶ最短距離を計算する関数です.指定された点が輪郭の外側にあれば負の値,内側にあれば正の値,輪郭上にあれば0を返します.

点(50,50)をテストする場合は以下のようになります:

dist = cv2.pointPolygonTest(cnt,(50,50),True)

第3引数は measureDist のフラフで, True であれば符号付き距離を計算し, False を指定すると+1,-1, 0(それぞれ輪郭の内側,外側,輪郭上)のどれかの値を返します.

Note

距離が必要無ければ第3引数に False を指定してください.なぜなら距離の計算は時間がかかる処理だからです. False を指定すると2,3倍高速になります.

3. 形状のマッチング

cv2.matchShapes() 関数を使うと二つの形状(もしくは輪郭)をマッチングし,モーメントの値を基にして計算した形状の差を表す数値を返します.数値が小さいほど二つの形状が似ていることを表します.異なる計算方法があります.

import cv2
import numpy as np

img1 = cv2.imread('star.jpg',0)
img2 = cv2.imread('star2.jpg',0)

ret, thresh = cv2.threshold(img1, 127, 255,0)
ret, thresh2 = cv2.threshold(img2, 127, 255,0)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt1 = contours[0]
contours,hierarchy = cv2.findContours(thresh2,2,1)
cnt2 = contours[0]

ret = cv2.matchShapes(cnt1,cnt2,1,0.0)
print ret

形状のマッチングを以下の形状を使って試してみます:

Match Shapes

結果は以下のようになります:

  • Matching Image A with itself = 0.0
  • Matching Image A with Image B = 0.001946
  • Matching Image A with Image C = 0.326911

この比較方法だと回転に対して不変なマッチングができていることがわかります.

See also

Hu モーメント(英語) は並進,回転,スケールに対して不変な7個のモーメントです.これらの値は cv2.HuMoments() 関数を使って計算できます.

補足資料

課題

  1. cv2.pointPolygonTest() 関数のドキュメントを読んでください.赤と青で構成された良い画像を見つけられると思います.白い曲線と全画素との距離を表しています.曲線の内側の画素は距離に応じた青色,曲線の外側の画素は赤で描画されています.輪郭線は白で描かれています.そのため,問題は単純です.距離の代替を計算するにはどのように実装すれば良いでしょうか.
  2. Compare images of digits or letters using cv2.matchShapes(). ( That would be a simple step towards OCR )