2015-12-12 54 views
6

を用いて画像内の矩形の中心及び角度を検出:各矩形の中心と測定値との間の角度、Iは矩形の数を知る必要がある以下のようにI画像を有するOpenCVの

Sample image containing many rectangle contours

矩形の長辺に平行な軸が中心を通り、水平から反時計回りの角度を測定します。画像中の矩形の数を見つけました。反射の中心と角度を見つけるのに打ち勝ちました。私は正しい答えを与えていないのです。

マイコード:ここで

import cv2 
import numpy as np 
import sys 

img = cv2.imread(str(sys.argv[1]),0) 
ret,thresh = cv2.threshold(img,127,255,0) 
contours,hierarchy = cv2.findContours(thresh,1,2) 



for contour in contours: 
    area = cv2.contourArea(contour) 
    if area>100000: 
     contours.remove(contour) 




cnt = contours[0] 

epsilon = 0.02*cv2.arcLength(cnt,True) 
approx = cv2.approxPolyDP(cnt,epsilon,True) 

print 'No of rectangles',len(approx) 


#finding the centre of the contour 
M = cv2.moments(cnt) 

cx = int(M['m10']/M['m00']) 
cy = int(M['m01']/M['m00']) 

print cx,cy 
+3

findContoursで等高線を抽出し、関数minAreaRectを使用してRotatedRectを計算します – Micka

+0

私の答えを確認してください[ここ](http://stackoverflow.com/questions/33860019/opencv-filter-blobs-by-width-and-height/33860887# 33860887)。 @Mickaが指摘した方法のサンプルC++実装が見つかります。 – sturkmen

+2

矩形の場合Mickaの解決策は最適です。より一般的なケースとして、PCAベースの方法も参照できます:http://docs.opencv.org/master/d1/dee/tutorial_introduction_to_pca.html#gsc.tab=0 –

答えて

8

これは、openCVのminAreaRect機能を使用して行う方法です。これはC++で書かれていますが、おそらくOpenCV関数だけが使用されているので、簡単にそれを適応させることができます。

この画像になる
cv::Mat input = cv::imread("../inputData/rectangles.png"); 

    cv::Mat gray; 
    cv::cvtColor(input,gray,CV_BGR2GRAY); 

    // since your image has compression artifacts, we have to threshold the image 
    int threshold = 200; 
    cv::Mat mask = gray > threshold; 

    cv::imshow("mask", mask); 

    // extract contours 
    std::vector<std::vector<cv::Point> > contours; 
    cv::findContours(mask, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); 

    for(int i=0; i<contours.size(); ++i) 
    { 
     // fit bounding rectangle around contour 
     cv::RotatedRect rotatedRect = cv::minAreaRect(contours[i]); 

     // read points and angle 
     cv::Point2f rect_points[4]; 
     rotatedRect.points(rect_points); 

     float angle = rotatedRect.angle; // angle 

     // read center of rotated rect 
     cv::Point2f center = rotatedRect.center; // center 

     // draw rotated rect 
     for(unsigned int j=0; j<4; ++j) 
      cv::line(input, rect_points[j], rect_points[(j+1)%4], cv::Scalar(0,255,0)); 

     // draw center and print text 
     std::stringstream ss; ss << angle; // convert float to string 
     cv::circle(input, center, 5, cv::Scalar(0,255,0)); // draw center 
     cv::putText(input, ss.str(), center + cv::Point2f(-25,25), cv::FONT_HERSHEY_COMPLEX_SMALL, 1, cv::Scalar(255,0,255)); // print angle 
    } 

enter image description here

あなたが見ることができるように(彼らはランダムに参照として長く以下の行を使用しているため)、角度があなたが望むものはおそらくありません。 代わりに、長方形の長い辺を抽出し、角度を手動で計算することができます。

あなたが回転しrectsの長辺を選択し、そこから角度を計算する場合は、次のようになります。この結果を与える

// choose the longer edge of the rotated rect to compute the angle 
     cv::Point2f edge1 = cv::Vec2f(rect_points[1].x, rect_points[1].y) - cv::Vec2f(rect_points[0].x, rect_points[0].y); 
     cv::Point2f edge2 = cv::Vec2f(rect_points[2].x, rect_points[2].y) - cv::Vec2f(rect_points[1].x, rect_points[1].y); 

     cv::Point2f usedEdge = edge1; 
     if(cv::norm(edge2) > cv::norm(edge1)) 
      usedEdge = edge2; 

     cv::Point2f reference = cv::Vec2f(1,0); // horizontal edge 


     angle = 180.0f/CV_PI * acos((reference.x*usedEdge.x + reference.y*usedEdge.y)/(cv::norm(reference) *cv::norm(usedEdge))); 

、あなたが探しているものであるべきです!

enter image description here

EDIT:参照矩形センターは、画像の外にあるしまうためopが、彼は掲載入力画像を使用していないように見えます。この入力(手動で再スケーリングが、おそらくまだ最適ではない)を使用して

enter image description here

enter image description here

を、私はそれらの結果を(ブルードットはOPによって提供される基準矩形中心である)を取得

リファレンスを検出と比較する:

reference (x,y,angle) detection (x,y,angle) 
(320,240,0)    (320, 240, 180) // angle 180 is equal to angle 0 for lines 
(75,175,90)    (73.5, 174.5, 90) 
(279,401,170)   (279.002, 401.824, 169.992) 
(507,379,61)    (507.842, 379.75, 61.1443) 
(545,95,135)    (545.75, 94.25, 135) 
(307,79,37)    (306.756, 77.8384, 37.1042) 

私は実際の入力イメージを見たいと思っていますが、おそらく結果はさらに良くなります。

+0

長辺に平行な軸と水平とのなす角度を見つける方法を教えてください。それは私が打ち負かす部分です。エッジを縮退させて長いエッジを見つけ、手動で角度を計算する必要がありますか? –

+0

コードと結果が更新されました。それは非常に簡単です。それがあなたを助けるなら、upvoteに自由に落ちなさい。 – Micka

+0

ありがとう。たくさん助けてくれました。私は瞬間を使うと四角形の中心を正しく取得できません。 これらは矩形の実際の中心との角度 (X、Y、角度) (320,240,0) (75,175,90) (279401170) (507,379,61) (545,95,135) (あります307,79,37) 瞬間を使って輪郭の中心を見つけると、それは私に別の答えを与えます。なぜそうですか? –

2

は、あなたがそれを行うことができる方法である。各パターンを検出するために

  1. 連結成分標識(あなたのケースでは長方形)
  2. パターンを分離
  3. (オプション)パターンがすべての長方形でない場合は、形状インデックスを使用してそれらを区別する
  4. 主成分分析(PCA)を使用して主軸を計算すると、探している角度が得られます。
+2

コードスニペットで回答を改善することができます。また、ここには矩形だけがあるので、 'minAreaRect'で十分でしょう。 – Miki

1

approx = cv2.approxPolyDP(cnt、epsilon、True)は、特定の閉じた輪郭の近似されたポリゴンを作成します。ポリゴンの線分は可変長であり、正確な中心を与えるために点を通常のグリッドからサンプリングすると予想されるため、モーメントの計算が正しく行われません。多角形近似のためのメソッドを呼び出す前に、元の輪郭の

  1. 利用モーメント:

    はあなたの問題には3つの解決策があります。

  2. それぞれの閉じた輪郭内の領域のマスクを生成し、生成されたマスクのモーメントを使用して中心を計算するには、drawContoursを使用します。
  3. サンプルは、閉じた多角形の各線分に沿った単位距離を指し示し、得られた点の集合を使用してモーメントを自分で計算します。これはあなたに同じ中心を与えるはずです。
関連する問題