obb iou计算,旋转框iou,python和c++版本

python版本


import math

#包围盒转化为角点
def rbbox_to_corners(rbbox):
    # generate clockwise corners and rotate it clockwise
    # 顺时针方向返回角点位置
    cx, cy, x_d, y_d, angle = rbbox
    a_cos = math.cos(angle)
    a_sin = math.sin(angle)
    corners_x = [-x_d / 2, -x_d / 2, x_d / 2, x_d / 2]
    corners_y = [-y_d / 2, y_d / 2, y_d / 2, -y_d / 2]
    corners = [0] * 8
    for i in range(4):
        corners[2 *
                i] = a_cos * corners_x[i] + \
                     a_sin * corners_y[i] + cx
        corners[2 * i +
                1] = -a_sin * corners_x[i] + \
                     a_cos * corners_y[i] + cy
    return corners

# 点在四边形(矩形)内?
def point_in_quadrilateral(pt_x, pt_y, corners):
    ab0 = corners[2] - corners[0]
    ab1 = corners[3] - corners[1]

    ad0 = corners[6] - corners[0]
    ad1 = corners[7] - corners[1]

    ap0 = pt_x - corners[0]
    ap1 = pt_y - corners[1]

    abab = ab0 * ab0 + ab1 * ab1
    abap = ab0 * ap0 + ab1 * ap1
    adad = ad0 * ad0 + ad1 * ad1
    adap = ad0 * ap0 + ad1 * ap1

    return abab >= abap and abap >= 0 and adad >= adap and adap >= 0

# 相交后转化为直线交点
def line_segment_intersection(pts1, pts2, i, j):
    # pts1, pts2 为corners
    # i j 分别表示第几个交点,取其和其后一个点构成的线段
    # 返回为 tuple(bool, pts) bool=True pts为交点
    A, B, C, D, ret = [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]
    A[0] = pts1[2 * i]
    A[1] = pts1[2 * i + 1]

    B[0] = pts1[2 * ((i + 1) % 4)]
    B[1] = pts1[2 * ((i + 1) % 4) + 1]

    C[0] = pts2[2 * j]
    C[1] = pts2[2 * j + 1]

    D[0] = pts2[2 * ((j + 1) % 4)]
    D[1] = pts2[2 * ((j + 1) % 4) + 1]
    BA0 = B[0] - A[0]
    BA1 = B[1] - A[1]
    DA0 = D[0] - A[0]
    CA0 = C[0] - A[0]
    DA1 = D[1] - A[1]
    CA1 = C[1] - A[1]
    # 叉乘判断方向
    acd = DA1 * CA0 > CA1 * DA0
    bcd = (D[1] - B[1]) * (C[0] - B[0]) > (C[1] - B[1]) * (D[0] - B[0])
    if acd != bcd:
        abc = CA1 * BA0 > BA1 * CA0
        abd = DA1 * BA0 > BA1 * DA0
        # 判断方向
        if abc != abd:
            DC0 = D[0] - C[0]
            DC1 = D[1] - C[1]
            ABBA = A[0] * B[1] - B[0] * A[1]
            CDDC = C[0] * D[1] - D[0] * C[1]
            DH = BA1 * DC0 - BA0 * DC1
            Dx = ABBA * DC0 - BA0 * CDDC
            Dy = ABBA * DC1 - BA1 * CDDC
            ret[0] = Dx / DH
            ret[1] = Dy / DH
            return True, ret
    return False, ret

# 顶点排序
def sort_vertex_in_convex_polygon(int_pts, num_of_inter):
    def _cmp(pt, center):
        vx = pt[0] - center[0]
        vy = pt[1] - center[1]
        d = math.sqrt(vx * vx + vy * vy)
        vx /= d
        vy /= d
        if vy < 0:
            vx = -2 - vx
        return vx

    if num_of_inter > 0:
        center = [0, 0]
        for i in range(num_of_inter):
            center[0] += int_pts[i][0]
            center[1] += int_pts[i][1]
        center[0] /= num_of_inter
        center[1] /= num_of_inter
        int_pts.sort(key=lambda x: _cmp(x, center))

# 将多边形转化为多个三角形面积之和
def area(int_pts, num_of_inter):
    def _trangle_area(a, b, c):
        return ((a[0] - c[0]) * (b[1] - c[1]) - (a[1] - c[1]) *
                (b[0] - c[0])) / 2.0

    area_val = 0.0
    for i in range(num_of_inter - 2):
        area_val += abs(
            _trangle_area(int_pts[0], int_pts[i + 1],
                          int_pts[i + 2]))
    return area_val


if __name__ == '__main__':
    rbbox1 = [274 ,614, 48 ,24 ,52.4832583462631987] #x,y,w,h,angle
    rbbox2 = [274 ,615 ,49 ,22 ,1.486161712080829]
    corners1 = rbbox_to_corners(rbbox1)
    corners2 = rbbox_to_corners(rbbox2)
    # print(corners1,"\n",corners2)
    pts, num_pts = [], 0
    for i in range(4):
        point = [corners1[2 * i], corners1[2 * i + 1]]
        if point_in_quadrilateral(point[0], point[1],
                                  corners2):
            num_pts += 1
            pts.append(point)
    for i in range(4):
        point = [corners2[2 * i], corners2[2 * i + 1]]
        if point_in_quadrilateral(point[0], point[1],
                                  corners1):
            num_pts += 1
            pts.append(point)

    for i in range(4):
        for j in range(4):
            ret, point = line_segment_intersection(corners1, corners2, i, j)
            if ret:
                num_pts += 1
                pts.append(point)

    sort_vertex_in_convex_polygon(pts, num_pts)
    polygon_area = area(pts, num_pts)
    area_union=rbbox1[2]*rbbox1[3]+rbbox2[2]*rbbox2[3]-polygon_area
    print('area: {}'.format(polygon_area/area_union))

c++

#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
// box转化为角点
std::vector<float> rbbox_to_corners(const std::vector<float> &rbbox) {
    // generate clockwise corners and rotate it clockwise
    // 顺时针方向返回角点位置
    float cx = rbbox[0] + rbbox[2] / 2;
    float cy = rbbox[1] + rbbox[3] / 2;
    float x_d = rbbox[2];
    float y_d = rbbox[3];
    float angle = rbbox[4];
    float a_cos = std::cos(angle);
    float a_sin = std::sin(angle);
    std::vector<float> corners(8, 0.0);
    float corners_x[4] = {-x_d / 2, -x_d / 2, x_d / 2, x_d / 2};
    float corners_y[4] = {-y_d / 2, y_d / 2, y_d / 2, -y_d / 2};
    for (int i = 0; i < 4; ++i) {
        corners[2 * i] = a_cos * corners_x[i] - a_sin * corners_y[i] + cx;
        corners[2 * i + 1] = a_sin * corners_x[i] + a_cos * corners_y[i] + cy;
    }
    return corners;
}

// 检测点是否在四边形内的函数
bool point_in_quadrilateral(float pt_x, float pt_y, const std::vector<float>& corners) {
    float ab0 = corners[2] - corners[0];
    float ab1 = corners[3] - corners[1];

    float ad0 = corners[6] - corners[0];
    float ad1 = corners[7] - corners[1];

    float ap0 = pt_x - corners[0];
    float ap1 = pt_y - corners[1];

    float abab = ab0 * ab0 + ab1 * ab1;
    float abap = ab0 * ap0 + ab1 * ap1;
    float adad = ad0 * ad0 + ad1 * ad1;
    float adap = ad0 * ap0 + ad1 * ap1;

    return abab >= abap && abap >= 0 && adad >= adap && adap >= 0;
}


// 检测线段相交并计算交点的函数
int line_segment_intersection(const std::vector<float>& pts1, const std::vector<float>& pts2, int i, int j 
                                                             , bool &ret1,float &point_x,float &point_y) {
    // pts1, pts2 分别为 corners
    // i j 分别表示第几个交点,取其和其后一个点构成的线段
    // 返回 tuple(bool, pts) bool=true pts为交点
    std::vector<float> A(2), B(2), C(2), D(2), ret(2);
    A[0] = pts1[2 * i];
    A[1] = pts1[2 * i + 1];

    B[0] = pts1[2 * ((i + 1) % 4)];
    B[1] = pts1[2 * ((i + 1) % 4) + 1];

    C[0] = pts2[2 * j];
    C[1] = pts2[2 * j + 1];

    D[0] = pts2[2 * ((j + 1) % 4)];
    D[1] = pts2[2 * ((j + 1) % 4) + 1];

    float BA0 = B[0] - A[0];
    float BA1 = B[1] - A[1];
    float DA0 = D[0] - A[0];
    float CA0 = C[0] - A[0];
    float DA1 = D[1] - A[1];
    float CA1 = C[1] - A[1];

    // 叉乘判断方向
    bool acd = DA1 * CA0 > CA1 * DA0;
    bool bcd = (D[1] - B[1]) * (C[0] - B[0]) > (C[1] - B[1]) * (D[0] - B[0]);

    if (acd != bcd) {
        bool abc = CA1 * BA0 > BA1 * CA0;
        bool abd = DA1 * BA0 > BA1 * DA0;

        // 判断方向
        if (abc != abd) {
            float DC0 = D[0] - C[0];
            float DC1 = D[1] - C[1];
            float ABBA = A[0] * B[1] - B[0] * A[1];
            float CDDC = C[0] * D[1] - D[0] * C[1];
            float DH = BA1 * DC0 - BA0 * DC1;
            float Dx = ABBA * DC0 - BA0 * CDDC;
            float Dy = ABBA * DC1 - BA1 * CDDC;
            ret[0] = Dx / DH;
            ret[1] = Dy / DH;
            ret1=true;
            point_x=ret[0] ;
            point_y=ret[1] ;
            return 0;
        }
    }
    ret1=false;
    point_x=ret[0] ;
    point_y=ret[1] ;
    return 0;
}



// 比较函数,用于排序
bool compare_points(const std::vector<float>& pt1, const std::vector<float>& pt2, const std::vector<float>& center) {
    float vx1 = pt1[0] - center[0];
    float vy1 = pt1[1] - center[1];
    float vx2 = pt2[0] - center[0];
    float vy2 = pt2[1] - center[1];
    float d1 = std::sqrt(vx1 * vx1 + vy1 * vy1);
    float d2 = std::sqrt(vx2 * vx2 + vy2 * vy2);
    vx1 /= d1;
    vy1 /= d1;
    vx2 /= d2;
    vy2 /= d2;
    if (vy1 < 0) {
        vx1 = -2 - vx1;
    }
    if (vy2 < 0) {
        vx2 = -2 - vx2;
    }
    return vx1 < vx2;
}

// 对凸多边形的顶点进行排序
void sort_vertex_in_convex_polygon(std::vector<std::vector<float>>& int_pts, int num_of_inter) {
    if (num_of_inter > 0) {
        std::vector<float> center(2, 0);
        for (int i = 0; i < num_of_inter; ++i) {
            center[0] += int_pts[i][0];
            center[1] += int_pts[i][1];
        }
        center[0] /= num_of_inter;
        center[1] /= num_of_inter;
        std::sort(int_pts.begin(), int_pts.end(), [&center](const std::vector<float>& pt1, const std::vector<float>& pt2) {
            return compare_points(pt1, pt2, center);
        });
    }
}

// 计算三角形的面积
float triangle_area(const std::vector<float>& a, const std::vector<float>& b, const std::vector<float>& c) {
    return std::abs((a[0] - c[0]) * (b[1] - c[1]) - (a[1] - c[1]) * (b[0] - c[0])) / 2.0;
}

// 计算多边形转化为多个三角形面积之和
float polygon_area(const std::vector<std::vector<float>>& int_pts, int num_of_inter) {
    float area_val = 0.0;
    for (int i = 1; i < num_of_inter - 1; ++i) {
        area_val += triangle_area(int_pts[0], int_pts[i], int_pts[i + 1]);
    }
    return area_val;
}


int main(int argc, char *argv[])

{
  // 定义两个包围盒的数据
    std::vector<float> rbbox1 = {274 ,614, 48 ,24 ,52.4832583462631987};
    std::vector<float> rbbox2 = {274 ,615 ,49 ,22 ,1.486161712080829};
    
    // 调用函数得到角点数据
    std::vector<float> corners1 = rbbox_to_corners(rbbox1);
    std::vector<float> corners2 = rbbox_to_corners(rbbox2);
    
    std::vector<std::vector<float>> pts;
    int num_pts = 0;
    // 检测角点是否在对方的四边形内
    for (int i = 0; i < 4; ++i) {
        float point_x = corners1[2 * i];
        float point_y = corners1[2 * i + 1];
        if (point_in_quadrilateral(point_x, point_y, corners2)) {
            num_pts++;
            pts.push_back({point_x, point_y});
        }
    }
    for (int i = 0; i < 4; ++i) {
        float point_x = corners2[2 * i];
        float point_y = corners2[2 * i + 1];
        if (point_in_quadrilateral(point_x, point_y, corners1)) {
            num_pts++;
            pts.push_back({point_x, point_y});
        }
    }


    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            float point_x,point_y;
            bool ret;
            line_segment_intersection(corners1, corners2, i, j,ret,point_x,point_y);
            if (ret) {
                num_pts++;
                pts.push_back({point_x, point_y});
            }
        }
    }


    sort_vertex_in_convex_polygon(pts, num_pts);
 

    float polygon_area_val = polygon_area(pts, num_pts);

    // 计算 area_union
    float area_union = rbbox1[2] * rbbox1[3] + rbbox2[2] * rbbox2[3] - polygon_area_val;

        // 计算并输出结果
    std::cout << "area: " << polygon_area_val / area_union << std::endl;
  return 0;

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值