import numpy as np
import cv2


def sigmoid(x):
    return 1 / (1 + np.exp(-x))


def xywh2xyxy(x):
    # x has shape [n, 4] where each row is (center_x, center_y, width, height)
    y = np.zeros_like(x)
    y[:, 0:2] = x[:, 0:2] - x[:, 2:4] / 2  # calculate min_x, min_y
    y[:, 2:4] = x[:, 0:2] + x[:, 2:4] / 2  # calculate max_x, max_y
    return y

def iou(box, boxes):
    # Compute xmin, ymin, xmax, ymax for both boxes
    xmin = np.maximum(box[0], boxes[:, 0])
    ymin = np.maximum(box[1], boxes[:, 1])
    xmax = np.minimum(box[2], boxes[:, 2])
    ymax = np.minimum(box[3], boxes[:, 3])

    # Compute intersection area
    intersection_area = np.maximum(0, xmax - xmin) * np.maximum(0, ymax - ymin)

    # Compute union area
    box_area = (box[2] - box[0]) * (box[3] - box[1])
    boxes_area = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
    union_area = box_area + boxes_area - intersection_area

    # Compute IoU
    iou = intersection_area / union_area

    return iou


def fast_nms(boxes, scores, iou_threshold):
    sorted_indices = np.argsort(scores)[::-1]

    selected_indices = []
    while sorted_indices.size > 0:
        box_id = sorted_indices[0]
        selected_indices.append(box_id)

        if sorted_indices.size == 1:
            break

        remaining_boxes = boxes[sorted_indices[1:]]
        current_box = boxes[box_id].reshape(1, -1)

        ious = np.array([iou(current_box[0], remaining_box) for remaining_box in remaining_boxes])
        keep_indices = np.where(ious < iou_threshold)[0]

        sorted_indices = sorted_indices[keep_indices + 1]

    return selected_indices

