vlambda博客
学习文章列表

c++ opencv计算两个旋转矩形框交并比的方法

两个旋转矩形框的交集intersection有以下几种情况:




See pics/intersection.png for the scenarios we are testingTest the following scenarios:1 - no intersection2 - partial intersection, rectangle translated3 - partial intersection, rectangle rotated 45 degree on the corner, forms a triangle intersection4 - full intersection, rectangles of same size directly on top of each other5 - partial intersection, rectangle on top rotated 45 degrees6 - partial intersection, rectangle on top of different size7 - full intersection, rectangle fully enclosed in the other8 - partial intersection, rectangle corner just touching. point contact9 - partial intersetion. rectangle side by side, line contact



采用c++ opencv计算两个旋转矩形的交并比,代码如下:


test.cpp

#include <opencv2/opencv.hpp>#include <iostream>
using namespace cv;using namespace std;
// 画旋转矩形void DrawRotatedRect( const RotatedRect &rot_rect, const Scalar &color, int thickness, int lineType, Mat &out_image){ Point2f* vertices = new cv::Point2f[4]; rot_rect.points(vertices); for (int j = 0; j < 4; j++) cv::line(out_image, vertices[j], vertices[(j + 1) % 4], color, thickness, lineType);
return;}
int main(){ cv::Mat image = cv::Mat::zeros(Size(1000,1000),CV_8UC3); RotatedRect rot_rect1; rot_rect1.center = cv::Point2f(200, 200); rot_rect1.size = cv::Size(200, 150); rot_rect1.angle = 10;
RotatedRect rot_rect2; rot_rect2.center = Point2f(300, 200); rot_rect2.size = Size(200, 100); rot_rect2.angle = 20;
DrawRotatedRect(rot_rect1,cv::Scalar(255,0,0),2,8,image);  DrawRotatedRect(rot_rect2,cv::Scalar(255,0,255),2,8,image); cv::imwrite("image.png",image);
std::vector<Point2f> intersections; int interType = cv::rotatedRectangleIntersection(rot_rect1, rot_rect2, intersections); // cv::RectanglesIntersectTypes // enum RectanglesIntersectTypes { // INTERSECT_NONE = 0, //!< No intersection // INTERSECT_PARTIAL = 1, //!< There is a partial intersection // INTERSECT_FULL = 2 //!< One of the rectangle is fully enclosed in the other // }; // if(interType == cv::RectanglesIntersectTypes::INTERSECT_NONE) // { // }
double iou_score; if(intersections.size()<3) { iou_score = 0.0; return 0; }
std::vector<cv::Point2f> order_pts; // 找到交集区域,对轮廓的各个点进行排序 cv::convexHull(intersections, order_pts, true); double area = cv::contourArea(order_pts); float rect_area1 = rot_rect1.size.width*rot_rect1.size.height; float rect_area2 = rot_rect2.size.width*rot_rect2.size.height; iou_score = static_cast<float>(area/(rect_area1+rect_area2-area));
  std::cout<<"iou score = "<<iou_score<<std::endl; return 0;}

运行结果:

 ./test iou score = 0.247474



使用的opencv中的函数:

1. rotatedRectangleIntersection计算交集

用来计算两个旋转矩形框的相交多边形,返回的结果vertices是多边形的点坐标,最多返回8个点的坐标。

【注】:

返回的结果不是顺时针或者逆时针的顺序(并不是所有情况下都是,而是某些小部分情况下)。所以在使用cv::contourArea计算面积的时候先对其进行排序。

/** @brief Finds out if there is any intersection between two rotated rectangles.If there is then the vertices of the interesecting region are returned as well.
Below are some examples of intersection configurations. The hatched pattern indicates theintersecting region and the red vertices are returned by the function.
![intersection examples](pics/intersection.png)
@param rect1 First rectangle@param rect2 Second rectangle@param intersectingRegion The output array of the verticies of the intersecting region. It returnsat most 8 vertices. Stored as std::vector\<cv::Point2f\> or cv::Mat as Mx1 of type CV_32FC2.@returns One of cv::RectanglesIntersectTypes */CV_EXPORTS_W int rotatedRectangleIntersection( const RotatedRect& rect1, const RotatedRect& rect2, OutputArray intersectingRegion);


2. convexHull计算点集组成的凸包

/** @example convexhull.cppAn example using the convexHull functionality*/
/** @brief Finds the convex hull of a point set.
The function cv::convexHull finds the convex hull of a 2D point set using the Sklansky's algorithm @cite Sklansky82that has *O(N logN)* complexity in the current implementation. See the OpenCV sample convexhull.cppthat demonstrates the usage of different function variants.
@param points Input 2D point set, stored in std::vector or Mat.@param hull Output convex hull. It is either an integer vector of indices or vector of points. Inthe first case, the hull elements are 0-based indices of the convex hull points in the originalarray (since the set of convex hull points is a subset of the original point set). In the secondcase, hull elements are the convex hull points themselves.@param clockwise Orientation flag. If it is true, the output convex hull is oriented clockwise.Otherwise, it is oriented counter-clockwise. The assumed coordinate system has its X axis pointingto the right, and its Y axis pointing upwards.@param returnPoints Operation flag. In case of a matrix, when the flag is true, the functionreturns convex hull points. Otherwise, it returns indices of the convex hull points. When theoutput array is std::vector, the flag is ignored, and the output depends on the type of thevector: std::vector\<int\> implies returnPoints=false, std::vector\<Point\> impliesreturnPoints=true. */CV_EXPORTS_W void convexHull( InputArray points, OutputArray hull,  bool clockwise = false,   bool returnPoints = true );


参考opencv源码下的

/modules/imgproc/test/test_intersection.cpp


#include "test_precomp.hpp"
namespace opencv_test { namespace {
#define ACCURACY 0.00001
// See pics/intersection.png for the scenarios we are testing// Test the following scenarios:// 1 - no intersection// 2 - partial intersection, rectangle translated// 3 - partial intersection, rectangle rotated 45 degree on the corner, forms a triangle intersection// 4 - full intersection, rectangles of same size directly on top of each other// 5 - partial intersection, rectangle on top rotated 45 degrees// 6 - partial intersection, rectangle on top of different size// 7 - full intersection, rectangle fully enclosed in the other// 8 - partial intersection, rectangle corner just touching. point contact// 9 - partial intersetion. rectangle side by side, line contact
static void compare(const std::vector<Point2f>& test, const std::vector<Point2f>& target){ ASSERT_EQ(test.size(), target.size()); ASSERT_TRUE(test.size() < 4 || isContourConvex(test)); ASSERT_TRUE(target.size() < 4 || isContourConvex(target)); for( size_t i = 0; i < test.size(); i++ ) { double r = sqrt(normL2Sqr<double>(test[i] - target[i])); ASSERT_LT(r, ACCURACY); }}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_1){ // no intersection 没有交集 RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 12.0f); RotatedRect rect2(Point2f(10, 10), Size2f(2, 2), 34.0f);
vector<Point2f> vertices; int ret = rotatedRectangleIntersection(rect1, rect2, vertices);
CV_Assert(ret == INTERSECT_NONE); CV_Assert(vertices.empty());}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_2){ // partial intersection, rectangles translated RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); RotatedRect rect2(Point2f(1, 1), Size2f(2, 2), 0.0f);
vector<Point2f> vertices; int ret = rotatedRectangleIntersection(rect1, rect2, vertices);
CV_Assert(ret == INTERSECT_PARTIAL);
vector<Point2f> targetVertices(4); targetVertices[0] = Point2f(1.0f, 0.0f); targetVertices[1] = Point2f(1.0f, 1.0f); targetVertices[2] = Point2f(0.0f, 1.0f); targetVertices[3] = Point2f(0.0f, 0.0f); compare(vertices, targetVertices);}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_3){ // partial intersection, rectangles rotated 45 degree on the corner, forms a triangle intersection // 交集区域是三角形 RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); RotatedRect rect2(Point2f(1, 1), Size2f(sqrt(2.0f), 20), 45.0f);
vector<Point2f> vertices; int ret = rotatedRectangleIntersection(rect1, rect2, vertices);
CV_Assert(ret == INTERSECT_PARTIAL);
vector<Point2f> targetVertices(3); targetVertices[0] = Point2f(1.0f, 0.0f); targetVertices[1] = Point2f(1.0f, 1.0f); targetVertices[2] = Point2f(0.0f, 1.0f); compare(vertices, targetVertices);}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_4){ // full intersection, rectangles of same size directly on top of each other // RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); RotatedRect rect2(Point2f(0, 0), Size2f(2, 2), 0.0f);
vector<Point2f> vertices; int ret = rotatedRectangleIntersection(rect1, rect2, vertices);
CV_Assert(ret == INTERSECT_FULL);
vector<Point2f> targetVertices(4); targetVertices[0] = Point2f(-1.0f, 1.0f); targetVertices[1] = Point2f(-1.0f, -1.0f); targetVertices[2] = Point2f(1.0f, -1.0f); targetVertices[3] = Point2f(1.0f, 1.0f); compare(vertices, targetVertices);}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_5){ // partial intersection, rectangle on top rotated 45 degrees // 8个点 RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); RotatedRect rect2(Point2f(0, 0), Size2f(2, 2), 45.0f);
vector<Point2f> vertices; int ret = rotatedRectangleIntersection(rect1, rect2, vertices);
CV_Assert(ret == INTERSECT_PARTIAL);
vector<Point2f> targetVertices(8); targetVertices[0] = Point2f(-1.0f, -0.414214f); targetVertices[1] = Point2f(-0.414214f, -1.0f); targetVertices[2] = Point2f(0.414214f, -1.0f); targetVertices[3] = Point2f(1.0f, -0.414214f); targetVertices[4] = Point2f(1.0f, 0.414214f); targetVertices[5] = Point2f(0.414214f, 1.0f); targetVertices[6] = Point2f(-0.414214f, 1.0f); targetVertices[7] = Point2f(-1.0f, 0.414214f); compare(vertices, targetVertices);}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_6){ // 6 - partial intersection, rectangle on top of different size RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); RotatedRect rect2(Point2f(0, 0), Size2f(2, 10), 0.0f);
vector<Point2f> vertices; int ret = rotatedRectangleIntersection(rect1, rect2, vertices);
CV_Assert(ret == INTERSECT_PARTIAL);
vector<Point2f> targetVertices(4); targetVertices[0] = Point2f(-1.0f, -1.0f); targetVertices[1] = Point2f(1.0f, -1.0f); targetVertices[2] = Point2f(1.0f, 1.0f); targetVertices[3] = Point2f(-1.0f, 1.0f); compare(vertices, targetVertices);}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_7){ // full intersection, rectangle fully enclosed in the other RotatedRect rect1(Point2f(0, 0), Size2f(12.34f, 56.78f), 0.0f); RotatedRect rect2(Point2f(0, 0), Size2f(2, 2), 0.0f);
vector<Point2f> vertices; int ret = rotatedRectangleIntersection(rect1, rect2, vertices);
CV_Assert(ret == INTERSECT_FULL);
vector<Point2f> targetVertices(4); targetVertices[0] = Point2f(-1.0f, 1.0f); targetVertices[1] = Point2f(-1.0f, -1.0f); targetVertices[2] = Point2f(1.0f, -1.0f); targetVertices[3] = Point2f(1.0f, 1.0f); compare(vertices, targetVertices);}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_8){ // intersection by a single vertex // 一个角点 RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); RotatedRect rect2(Point2f(2, 2), Size2f(2, 2), 0.0f);
vector<Point2f> vertices; int ret = rotatedRectangleIntersection(rect1, rect2, vertices);
CV_Assert(ret == INTERSECT_PARTIAL); compare(vertices, vector<Point2f>(1, Point2f(1.0f, 1.0f)));}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_9){ // full intersection, rectangle fully enclosed in the other // 两个角点 RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); RotatedRect rect2(Point2f(2, 0), Size2f(2, 123.45f), 0.0f);
vector<Point2f> vertices; int ret = rotatedRectangleIntersection(rect1, rect2, vertices);
CV_Assert(ret == INTERSECT_PARTIAL);
vector<Point2f> targetVertices(2); targetVertices[0] = Point2f(1.0f, -1.0f); targetVertices[1] = Point2f(1.0f, 1.0f); compare(vertices, targetVertices);}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_10){ // three points of rect2 are inside rect1. RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); RotatedRect rect2(Point2f(0, 0.5), Size2f(1, 1), 45.0f);
vector<Point2f> vertices; int ret = rotatedRectangleIntersection(rect1, rect2, vertices);
CV_Assert(ret == INTERSECT_PARTIAL);
vector<Point2f> targetVertices(5); targetVertices[0] = Point2f(0.207107f, 1.0f); targetVertices[1] = Point2f(-0.207107f, 1.0f); targetVertices[2] = Point2f(-0.707107f, 0.5f); targetVertices[3] = Point2f(0.0f, -0.207107f); targetVertices[4] = Point2f(0.707107f, 0.5f); compare(vertices, targetVertices);}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_11){ RotatedRect rect1(Point2f(0, 0), Size2f(4, 2), 0.0f); RotatedRect rect2(Point2f(0, 0), Size2f(2, 2), -45.0f);
vector<Point2f> vertices; int ret = rotatedRectangleIntersection(rect1, rect2, vertices);
CV_Assert(ret == INTERSECT_PARTIAL);
vector<Point2f> targetVertices(6); targetVertices[0] = Point2f(-0.414214f, -1.0f); targetVertices[1] = Point2f(0.414213f, -1.0f); targetVertices[2] = Point2f(1.41421f, 0.0f); targetVertices[3] = Point2f(0.414214f, 1.0f); targetVertices[4] = Point2f(-0.414213f, 1.0f); targetVertices[5] = Point2f(-1.41421f, 0.0f); compare(vertices, targetVertices);}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_12){ RotatedRect rect1(Point2f(0, 0), Size2f(2, 2), 0.0f); RotatedRect rect2(Point2f(0, 1), Size2f(1, 1), 0.0f);
vector<Point2f> vertices; int ret = rotatedRectangleIntersection(rect1, rect2, vertices);
CV_Assert(ret == INTERSECT_PARTIAL);
vector<Point2f> targetVertices(4); targetVertices[0] = Point2f(-0.5f, 1.0f); targetVertices[1] = Point2f(-0.5f, 0.5f); targetVertices[2] = Point2f(0.5f, 0.5f); targetVertices[3] = Point2f(0.5f, 1.0f); compare(vertices, targetVertices);}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_13){ RotatedRect rect1(Point2f(0, 0), Size2f(1, 3), 0.0f); RotatedRect rect2(Point2f(0, 1), Size2f(3, 1), 0.0f);
vector<Point2f> vertices; int ret = rotatedRectangleIntersection(rect1, rect2, vertices);
CV_Assert(ret == INTERSECT_PARTIAL);
vector<Point2f> targetVertices(4); targetVertices[0] = Point2f(-0.5f, 0.5f); targetVertices[1] = Point2f(0.5f, 0.5f); targetVertices[2] = Point2f(0.5f, 1.5f); targetVertices[3] = Point2f(-0.5f, 1.5f); compare(vertices, targetVertices);}
TEST(Imgproc_RotatedRectangleIntersection, accuracy_14){ const int kNumTests = 100; const float kWidth = 5; const float kHeight = 5; RotatedRect rects[2]; std::vector<Point2f> inter; cv::RNG& rng = cv::theRNG(); for (int i = 0; i < kNumTests; ++i) { for (int j = 0; j < 2; ++j) { rects[j].center = Point2f(rng.uniform(0.0f, kWidth), rng.uniform(0.0f, kHeight)); rects[j].size = Size2f(rng.uniform(1.0f, kWidth), rng.uniform(1.0f, kHeight)); rects[j].angle = rng.uniform(0.0f, 360.0f); } int res = rotatedRectangleIntersection(rects[0], rects[1], inter); EXPECT_TRUE(res == INTERSECT_NONE || res == INTERSECT_PARTIAL || res == INTERSECT_FULL) << res; ASSERT_TRUE(inter.size() < 4 || isContourConvex(inter)) << inter; }}
TEST(Imgproc_RotatedRectangleIntersection, regression_12221_1){ RotatedRect r1( Point2f(259.65081787109375, 51.58895492553711), Size2f(5487.8779296875, 233.8921661376953), -29.488616943359375); RotatedRect r2( Point2f(293.70465087890625, 112.10154724121094), Size2f(5487.8896484375, 234.87368774414062), -31.27001953125);
std::vector<Point2f> intersections; int interType = cv::rotatedRectangleIntersection(r1, r2, intersections); EXPECT_EQ(INTERSECT_PARTIAL, interType); EXPECT_LE(intersections.size(), (size_t)8);}
TEST(Imgproc_RotatedRectangleIntersection, regression_12221_2){ RotatedRect r1( Point2f(239.78500366210938, 515.72021484375), Size2f(70.23420715332031, 39.74684524536133), -42.86162567138672); RotatedRect r2( Point2f(242.4205322265625, 510.1195373535156), Size2f(66.85948944091797, 61.46455383300781), -9.840961456298828);
std::vector<Point2f> intersections; int interType = cv::rotatedRectangleIntersection(r1, r2, intersections); EXPECT_EQ(INTERSECT_PARTIAL, interType); EXPECT_LE(intersections.size(), (size_t)8);}
}} // namespace


《完》



上一篇