赞
踩
语言 :C++
OpenCV版本:3.4.0
在目标检测中,后处理阶段会用到非极大值抑制来过滤目标框,而计算两个框的IOU(交并比)则是其关键的一环,先计算两个框相交的点,再求出这些点构成的多边形的面积就是这两个框相交的面积。
cv::rotatedRectangleIntersection(cv::RotatedRect r1, cv::RotatedRect r1, vector<cv::Point2f> vertices)用来计算两个旋转矩形框的相交多边形,返回的结果vertices是多边形的点坐标,最多返回8个点的坐标。
再通过double cv::contourArea(InputArray contour, bool oriented=false)计算多边形面积,这样就得到了相交多边形的面积。
但是实际应用中发现contourArea计算的面积不正确,通过排查发现是rotatedRectangleIntersection生成的点坐标不是顺时针或者逆时针的顺序(并不是所有情况下都是,而是某些小部分情况下),画张图来解释下,rotatedRectangleIntersection函数返回的点坐标顺序可能是125463,这样的顺序会导致contourArea函数计算的面积是错误的,当然这并不是contourArea函数的bug,因为这个函数计算时是按照点的顺序(方向)来计算轮廓的面积,所以需要重新对坐标顺序进行排列,使得坐标按照顺时针或者逆时针排序,从任意一点开始都可以,比如123456,234561,543216顺序都可以。
- #include <vector>
- #include <math.h>
- #include <opencv2/highgui/highgui.hpp>
- #include <opencv2/imgproc.hpp>
-
- typedef struct{
- float x;
- float y;
- float w;
- float h;
- float theta;
- float score;
- int label;
- }detection;
-
- // 第一步找到最左边的点
- int find_leftmost_point(vector<cv::Point2f> intersectingRegion)
- {
- int index = 0;
- float tmp = intersectingRegion[0].x;
- for(int i=1; i<intersectingRegion.size(); i++)
- {
- if(intersectingRegion[i].x < tmp)
- {
- tmp = intersectingRegion[i].x;
- index = i;
- }
- }
- return index;
- }
-
- //第二步对所有点进行排序
- vector<cv::Point2f> sort_points(vector<cv::Point2f> intersectingRegion)
- {
- vector<cv::Point2f> sort_intersectingRegion;
- int leftmost_index = find_leftmost_point(intersectingRegion);
-
- vector<float> arctan;
- for(int i=0; i<intersectingRegion.size(); i++)
- {
- arctan.push_back(atan2(intersectingRegion[i].y - intersectingRegion[leftmost_index].y, intersectingRegion[i].x - intersectingRegion[leftmost_index].x));
- }
-
- vector<int> index;
- for(int i=0; i<arctan.size(); i++)
- {
- index.push_back(i);
- }
-
- sort(index.begin(), index.end(), [&](const int& a, const int& b) {return (arctan[a] < arctan[b]);});
-
- for(int i=0; i<index.size(); i++)
- {
- sort_intersectingRegion.push_back(intersectingRegion[index[i]]);
- }
- return sort_intersectingRegion;
- }
-
- // 计算两个旋转框的IOU
- float rbox_iou(detection d1, detection d2)
- {
- float inter_area;
- float area_r1 = d1.w * d1.h;
- float area_r2 = d2.w * d2.h;
- cv::RotatedRect rect1;
- rect1.center = cv::Point2f(d1.x, d1.y);
- rect1.size = cv::Size(d1.w, d1.h);
- rect1.angle = d1.theta;
- cv::RotatedRect rect2;
- rect2.center = cv::Point2f(d2.x, d2.y);
- rect2.size = cv::Size(d2.w, d2.h);
- rect2.angle = d2.theta;
-
- vector<cv::Point2f> intersectingRegion;
- cv::rotatedRectangleIntersection(rect1, rect2, intersectingRegion);
-
- if (intersectingRegion.empty())
- {
- inter_area = 0;
- }
- else
- {
- vector<cv::Point2f> sort_intersectingRegion = sort_points(intersectingRegion);
- inter_area = cv::contourArea(sort_intersectingRegion);
- }
- return inter_area / (area_r1 + area_r2 - inter_area + 0.00000001);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。