opencvで開いた図形と閉じた図形を検出する方法。
これらは、私が検出したい単純なサンプル形状です。 findContours
とapproxPolyDP
を使用して長方形を検出し、ベクトル間の角度を確認しました。
開いた形状を検出したいのですが、approxPolyDP
関数には閉じた形状のブール値がtrueに設定されています。また、返されたポイントとisCounterConvex
にcontourArea
のチェックがあります制限。
これらの種類の画像をどのように検出するかについてのアイデア。
画像で findContours() を使用し、findContours()関数に渡された階層を調べて、輪郭が閉じているかどうかを判断します。 2番目の図から、最初の画像と比較してどの輪郭にも子輪郭がないことが明確です。このデータは、画像トポロジーに関する情報を含むオプションの出力ベクトルである階層パラメーターから取得します。輪郭の数と同じ数の要素があります。
ここでは、階層を次のように使用します
vector< Vec4i > hierarchy
ここでi番目の輪郭
hierarchy[i][0] = next contour at the same hierarchical level
hierarchy[i][1] = previous contour at the same hierarchical level
hierarchy[i][2] = denotes its first child contour
hierarchy[i][3] = denotes index of its parent contour
輪郭iについて、次、前、親、またはネストされた輪郭がない場合、hierarchy[i]
の対応する要素は負になります。詳細は findContours() 関数を参照してください。
したがって、値hierarchy[i][2]
をチェックすることで、輪郭が閉じているかどうかを判断できます。つまり、輪郭がhierarchy[i][2] = -1
であり、子がなく、開いている場合に輪郭を表します。
さらにもう1つ、findContours()関数では、すべての輪郭を取得して2レベルの階層に編成するCV_RETR_CCOMPを使用する必要があります。
これを実装するC++コードを次に示します。
Mat tmp,thr;
Mat src=imread("1.png",1);
cvtColor(src,tmp,CV_BGR2GRAY);
threshold(tmp,thr,200,255,THRESH_BINARY_INV);
vector< vector <Point> > contours; // Vector for storing contour
vector< Vec4i > hierarchy;
findContours( thr, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
for( int i = 0; i< contours.size(); i=hierarchy[i][0] ) // iterate through each contour.
{
Rect r= boundingRect(contours[i]);
if(hierarchy[i][2]<0) //Check if there is a child contour
rectangle(src,Point(r.x-10,r.y-10), Point(r.x+r.width+10,r.y+r.height+10), Scalar(0,0,255),2,8,0); //Opened contour
else
rectangle(src,Point(r.x-10,r.y-10), Point(r.x+r.width+10,r.y+r.height+10), Scalar(0,255,0),2,8,0); //closed contour
}
結果:
提示された問題は正しいですが、@ Harisの有用な回答は、 findContours() を使用して閉じた輪郭を識別するための一般的な解決策として解釈すべきではありません。
1つの理由は、塗りつぶされたオブジェクトには内部輪郭がないため、_hierarchy[i][2] = -1
_が返されるためです。
塗りつぶされたオブジェクトの輪郭には、輪郭階層に子または親がありません。つまり、最上位にあります。したがって、塗りつぶされたオブジェクトの閉じた輪郭を検出するには、少なくとも追加のテストが必要になります:if(hierarchy[i][2] < 0 && hierarchy[i][3] < 0)
。
@Harisの回答はこの点を斜めにしたかもしれないと思いますが、opencvの使い方を学んでいる私のような人々にとっては、明確にする価値があると思いました。
答えは画像、具体的には輪郭がいくつプリセットされているか、他のオブジェクト、ノイズなどがあるかどうかによって異なります。閉じた輪郭の内側で開始された単一の輪郭塗りつぶしの単純なケースでは、画像全体に波及しません。 ;外で始めた場合、それは真ん中に入りません。したがって、どちらの場合も、白い領域をいくつか保持します。