.. _Contours_More_Functions: 輪郭に関する更なる関数 ****************************** 目的 ====== このチュートリアルでは * 凸性の欠陥とその検出方法について学びます. * 点とポリゴン(多角形)の最短距離の計算方法を学びます. * 形状のマッチングについて学びます. 理論と実装 ================ 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() 結果は以下のようになります: .. image:: images/defects.jpg :alt: Convexity Defects :align: center 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 形状のマッチングを以下の形状を使って試してみます: .. image:: images/matchshapes.jpg :alt: Match Shapes :align: center 結果は以下のようになります: * Matching Image A with itself = 0.0 * Matching Image A with Image B = 0.001946 * Matching Image A with Image C = 0.326911 この比較方法だと回転に対して不変なマッチングができていることがわかります. .. seealso:: `Hu モーメント(英語) `_ は並進,回転,スケールに対して不変な7個のモーメントです.これらの値は **cv2.HuMoments()** 関数を使って計算できます. 補足資料 ===================== 課題 ============ #. **cv2.pointPolygonTest()** 関数のドキュメントを読んでください.赤と青で構成された良い画像を見つけられると思います.白い曲線と全画素との距離を表しています.曲線の内側の画素は距離に応じた青色,曲線の外側の画素は赤で描画されています.輪郭線は白で描かれています.そのため,問題は単純です.距離の代替を計算するにはどのように実装すれば良いでしょうか. #. Compare images of digits or letters using **cv2.matchShapes()**. ( That would be a simple step towards OCR )