| |
| #pragma once |
|
|
| #include <cassert> |
| #include <cmath> |
|
|
| #if defined(__CUDACC__) || __HCC__ == 1 || __HIP__ == 1 |
| |
| #define HOST_DEVICE __host__ __device__ |
| #define HOST_DEVICE_INLINE HOST_DEVICE __forceinline__ |
| #else |
| #include <algorithm> |
| #define HOST_DEVICE |
| #define HOST_DEVICE_INLINE HOST_DEVICE inline |
| #endif |
|
|
| namespace detectron2 { |
|
|
| namespace { |
|
|
| template <typename T> |
| struct RotatedBox { |
| T x_ctr, y_ctr, w, h, a; |
| }; |
|
|
| template <typename T> |
| struct Point { |
| T x, y; |
| HOST_DEVICE_INLINE Point(const T& px = 0, const T& py = 0) : x(px), y(py) {} |
| HOST_DEVICE_INLINE Point operator+(const Point& p) const { |
| return Point(x + p.x, y + p.y); |
| } |
| HOST_DEVICE_INLINE Point& operator+=(const Point& p) { |
| x += p.x; |
| y += p.y; |
| return *this; |
| } |
| HOST_DEVICE_INLINE Point operator-(const Point& p) const { |
| return Point(x - p.x, y - p.y); |
| } |
| HOST_DEVICE_INLINE Point operator*(const T coeff) const { |
| return Point(x * coeff, y * coeff); |
| } |
| }; |
|
|
| template <typename T> |
| HOST_DEVICE_INLINE T dot_2d(const Point<T>& A, const Point<T>& B) { |
| return A.x * B.x + A.y * B.y; |
| } |
|
|
| |
| template <typename T, typename R = T> |
| HOST_DEVICE_INLINE R cross_2d(const Point<T>& A, const Point<T>& B) { |
| return static_cast<R>(A.x) * static_cast<R>(B.y) - |
| static_cast<R>(B.x) * static_cast<R>(A.y); |
| } |
|
|
| template <typename T> |
| HOST_DEVICE_INLINE void get_rotated_vertices( |
| const RotatedBox<T>& box, |
| Point<T> (&pts)[4]) { |
| |
| double theta = box.a * 0.01745329251; |
| T cosTheta2 = (T)cos(theta) * 0.5f; |
| T sinTheta2 = (T)sin(theta) * 0.5f; |
|
|
| |
| pts[0].x = box.x_ctr + sinTheta2 * box.h + cosTheta2 * box.w; |
| pts[0].y = box.y_ctr + cosTheta2 * box.h - sinTheta2 * box.w; |
| pts[1].x = box.x_ctr - sinTheta2 * box.h + cosTheta2 * box.w; |
| pts[1].y = box.y_ctr - cosTheta2 * box.h - sinTheta2 * box.w; |
| pts[2].x = 2 * box.x_ctr - pts[0].x; |
| pts[2].y = 2 * box.y_ctr - pts[0].y; |
| pts[3].x = 2 * box.x_ctr - pts[1].x; |
| pts[3].y = 2 * box.y_ctr - pts[1].y; |
| } |
|
|
| template <typename T> |
| HOST_DEVICE_INLINE int get_intersection_points( |
| const Point<T> (&pts1)[4], |
| const Point<T> (&pts2)[4], |
| Point<T> (&intersections)[24]) { |
| |
| |
| Point<T> vec1[4], vec2[4]; |
| for (int i = 0; i < 4; i++) { |
| vec1[i] = pts1[(i + 1) % 4] - pts1[i]; |
| vec2[i] = pts2[(i + 1) % 4] - pts2[i]; |
| } |
|
|
| |
| |
| |
| |
| |
| double EPS = 1e-5; |
|
|
| |
| int num = 0; |
| for (int i = 0; i < 4; i++) { |
| for (int j = 0; j < 4; j++) { |
| |
| T det = cross_2d<T>(vec2[j], vec1[i]); |
|
|
| |
| if (fabs(det) <= 1e-14) { |
| continue; |
| } |
|
|
| auto vec12 = pts2[j] - pts1[i]; |
|
|
| T t1 = cross_2d<T>(vec2[j], vec12) / det; |
| T t2 = cross_2d<T>(vec1[i], vec12) / det; |
|
|
| if (t1 > -EPS && t1 < 1.0f + EPS && t2 > -EPS && t2 < 1.0f + EPS) { |
| intersections[num++] = pts1[i] + vec1[i] * t1; |
| } |
| } |
| } |
|
|
| |
| { |
| const auto& AB = vec2[0]; |
| const auto& DA = vec2[3]; |
| auto ABdotAB = dot_2d<T>(AB, AB); |
| auto ADdotAD = dot_2d<T>(DA, DA); |
| for (int i = 0; i < 4; i++) { |
| |
| |
| |
|
|
| auto AP = pts1[i] - pts2[0]; |
|
|
| auto APdotAB = dot_2d<T>(AP, AB); |
| auto APdotAD = -dot_2d<T>(AP, DA); |
|
|
| if ((APdotAB > -EPS) && (APdotAD > -EPS) && (APdotAB < ABdotAB + EPS) && |
| (APdotAD < ADdotAD + EPS)) { |
| intersections[num++] = pts1[i]; |
| } |
| } |
| } |
|
|
| |
| { |
| const auto& AB = vec1[0]; |
| const auto& DA = vec1[3]; |
| auto ABdotAB = dot_2d<T>(AB, AB); |
| auto ADdotAD = dot_2d<T>(DA, DA); |
| for (int i = 0; i < 4; i++) { |
| auto AP = pts2[i] - pts1[0]; |
|
|
| auto APdotAB = dot_2d<T>(AP, AB); |
| auto APdotAD = -dot_2d<T>(AP, DA); |
|
|
| if ((APdotAB > -EPS) && (APdotAD > -EPS) && (APdotAB < ABdotAB + EPS) && |
| (APdotAD < ADdotAD + EPS)) { |
| intersections[num++] = pts2[i]; |
| } |
| } |
| } |
|
|
| return num; |
| } |
|
|
| template <typename T> |
| HOST_DEVICE_INLINE int convex_hull_graham( |
| const Point<T> (&p)[24], |
| const int& num_in, |
| Point<T> (&q)[24], |
| bool shift_to_zero = false) { |
| assert(num_in >= 2); |
|
|
| |
| |
| |
| |
| int t = 0; |
| for (int i = 1; i < num_in; i++) { |
| if (p[i].y < p[t].y || (p[i].y == p[t].y && p[i].x < p[t].x)) { |
| t = i; |
| } |
| } |
| auto& start = p[t]; |
|
|
| |
| |
| for (int i = 0; i < num_in; i++) { |
| q[i] = p[i] - start; |
| } |
|
|
| |
| auto tmp = q[0]; |
| q[0] = q[t]; |
| q[t] = tmp; |
|
|
| |
| |
| |
| |
| T dist[24]; |
| #if defined(__CUDACC__) || __HCC__ == 1 || __HIP__ == 1 |
| |
| |
| for (int i = 0; i < num_in; i++) { |
| dist[i] = dot_2d<T>(q[i], q[i]); |
| } |
|
|
| |
| |
| |
| for (int i = 1; i < num_in - 1; i++) { |
| for (int j = i + 1; j < num_in; j++) { |
| T crossProduct = cross_2d<T>(q[i], q[j]); |
| if ((crossProduct < -1e-6) || |
| (fabs(crossProduct) < 1e-6 && dist[i] > dist[j])) { |
| auto q_tmp = q[i]; |
| q[i] = q[j]; |
| q[j] = q_tmp; |
| auto dist_tmp = dist[i]; |
| dist[i] = dist[j]; |
| dist[j] = dist_tmp; |
| } |
| } |
| } |
| #else |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| for (int i = 0; i < num_in; i++) { |
| dist[i] = dot_2d<T>(q[i], q[i]); |
| } |
|
|
| for (int i = 1; i < num_in - 1; i++) { |
| for (int j = i + 1; j < num_in; j++) { |
| T crossProduct = cross_2d<T>(q[i], q[j]); |
| if ((crossProduct < -1e-6) || |
| (fabs(crossProduct) < 1e-6 && dist[i] > dist[j])) { |
| auto q_tmp = q[i]; |
| q[i] = q[j]; |
| q[j] = q_tmp; |
| auto dist_tmp = dist[i]; |
| dist[i] = dist[j]; |
| dist[j] = dist_tmp; |
| } |
| } |
| } |
|
|
| |
| for (int i = 0; i < num_in; i++) { |
| dist[i] = dot_2d<T>(q[i], q[i]); |
| } |
|
|
| #endif |
|
|
| |
| |
| |
| int k; |
| for (k = 1; k < num_in; k++) { |
| if (dist[k] > 1e-8) { |
| break; |
| } |
| } |
| if (k == num_in) { |
| |
| q[0] = p[t]; |
| return 1; |
| } |
| q[1] = q[k]; |
| int m = 2; |
| |
| |
| |
| |
| |
| |
| |
| for (int i = k + 1; i < num_in; i++) { |
| while (m > 1) { |
| auto q1 = q[i] - q[m - 2], q2 = q[m - 1] - q[m - 2]; |
| |
| |
| |
| |
| if (q1.x * q2.y >= q2.x * q1.y) |
| m--; |
| else |
| break; |
| } |
| |
| |
| |
| |
| |
| q[m++] = q[i]; |
| } |
|
|
| |
| |
| |
| |
| |
| if (!shift_to_zero) { |
| for (int i = 0; i < m; i++) { |
| q[i] += start; |
| } |
| } |
|
|
| return m; |
| } |
|
|
| template <typename T> |
| HOST_DEVICE_INLINE T polygon_area(const Point<T> (&q)[24], const int& m) { |
| if (m <= 2) { |
| return 0; |
| } |
|
|
| T area = 0; |
| for (int i = 1; i < m - 1; i++) { |
| area += fabs(cross_2d<T>(q[i] - q[0], q[i + 1] - q[0])); |
| } |
|
|
| return area / 2.0; |
| } |
|
|
| template <typename T> |
| HOST_DEVICE_INLINE T rotated_boxes_intersection( |
| const RotatedBox<T>& box1, |
| const RotatedBox<T>& box2) { |
| |
| |
| Point<T> intersectPts[24], orderedPts[24]; |
|
|
| Point<T> pts1[4]; |
| Point<T> pts2[4]; |
| get_rotated_vertices<T>(box1, pts1); |
| get_rotated_vertices<T>(box2, pts2); |
|
|
| int num = get_intersection_points<T>(pts1, pts2, intersectPts); |
|
|
| if (num <= 2) { |
| return 0.0; |
| } |
|
|
| |
| |
| int num_convex = convex_hull_graham<T>(intersectPts, num, orderedPts, true); |
| return polygon_area<T>(orderedPts, num_convex); |
| } |
|
|
| } |
|
|
| template <typename T> |
| HOST_DEVICE_INLINE T |
| single_box_iou_rotated(T const* const box1_raw, T const* const box2_raw) { |
| |
| RotatedBox<T> box1, box2; |
| auto center_shift_x = (box1_raw[0] + box2_raw[0]) / 2.0; |
| auto center_shift_y = (box1_raw[1] + box2_raw[1]) / 2.0; |
| box1.x_ctr = box1_raw[0] - center_shift_x; |
| box1.y_ctr = box1_raw[1] - center_shift_y; |
| box1.w = box1_raw[2]; |
| box1.h = box1_raw[3]; |
| box1.a = box1_raw[4]; |
| box2.x_ctr = box2_raw[0] - center_shift_x; |
| box2.y_ctr = box2_raw[1] - center_shift_y; |
| box2.w = box2_raw[2]; |
| box2.h = box2_raw[3]; |
| box2.a = box2_raw[4]; |
|
|
| T area1 = box1.w * box1.h; |
| T area2 = box2.w * box2.h; |
| if (area1 < 1e-14 || area2 < 1e-14) { |
| return 0.f; |
| } |
|
|
| T intersection = rotated_boxes_intersection<T>(box1, box2); |
| T iou = intersection / (area1 + area2 - intersection); |
| return iou; |
| } |
|
|
| } |
|
|