次のような画像があります。
長方形の数、各長方形の中心、および中心を通過する長方形の長い方のエッジに平行な軸間の角度を測定し、水平から反時計回りの角度を測定する必要があります。画像の四角形。中心と反射角度を見つけるのに苦労します。瞬間を介して中心を見つけると、正しい答えが得られません。
私のコード:
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
これは、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
}
この画像になります:
ご覧のとおり、角度はおそらく望んでいるものではありません(参照としてランダムに長い線または小さい線を使用しているため)。代わりに、長方形の長い方の辺を抽出して、手動で角度を計算できます。
回転した四角形の長い方のEdgeを選択し、そこから角度を計算すると、次のようになります。
// 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)));
あなたが探しているはずのこの結果を与える!
編集:参照長方形の中心が画像の外側にあるため、opは彼が投稿した入力画像を使用していないようです。
この入力を使用する(手動で再スケーリングされますが、おそらくまだ最適ではありません):
私はそれらの結果を得ます(青い点は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)
REALの入力画像を見たいのですが、多分結果はもっと良くなるでしょう。
これを行う方法は次のとおりです。
approx = cv2.approxPolyDP(cnt、epsilon、True)は、指定された閉じた輪郭の近似ポリゴンを作成します。ポリゴンのラインセグメントは可変長であるため、正しいグリッドが得られるようにポイントが通常のグリッドからサンプリングされることが期待されているため、モーメントの計算が正しくありません。
問題に対する3つの解決策があります。