Так вы можете сделать это с помощью функции minAreaRect openCV. Он написан на 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
}
в результате этого изображения:
, как вы можете видеть, углы, вероятно, не то, что вы хотите (потому что они случайно использовать больше или меньше строки в качестве ссылки). Вы можете вместо этого извлечь более длинные стороны прямоугольников и вычислить угол вручную.
Если вы выбираете более длинный край повернутых прямоугольников и вычислить угол от него это выглядит следующим образом:
// 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)));
дает этот результат, который должен быть то, что вы ищете!
EDIT: Похоже, оп не использует входное изображение, которое он отправил, потому что ссылки прямоугольник центры будут лежать вне образа.
Используя этот вход (вручную пересчитаны, но, вероятно, до сих пор не является оптимальным):
я получаю эти результаты (синие точки являются эталонные прямоугольные центры предусмотрено цит):
Сравнение эталонных данных с обнаружениями:
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, хотя, возможно, результат будет еще лучше.
извлечение контуров с помощью findContours и функция использования minAreaRect для вычисления RotatedRect – Micka
проверить мой ответ [здесь] (http://stackoverflow.com/questions/33860019/opencv-filter-blobs-by-width-and-height/33860887# 33860887). вы найдете пример реализации C++, который указал @Micka. – sturkmen
Для прямоугольников решение Micka является оптимальным, поскольку в более общем случае вы также можете посмотреть метод на основе PCA: http://docs.opencv.org/master/d1/dee/tutorial_introduction_to_pca.html#gsc.tab=0 –