mirror of
https://github.com/deepinsight/insightface.git
synced 2025-12-30 08:02:27 +00:00
173 lines
4.5 KiB
Python
173 lines
4.5 KiB
Python
# coding: utf-8
|
|
# YuanYang
|
|
import math
|
|
import cv2
|
|
import numpy as np
|
|
|
|
|
|
def nms(boxes, overlap_threshold, mode='Union'):
|
|
"""
|
|
non max suppression
|
|
|
|
Parameters:
|
|
----------
|
|
box: numpy array n x 5
|
|
input bbox array
|
|
overlap_threshold: float number
|
|
threshold of overlap
|
|
mode: float number
|
|
how to compute overlap ratio, 'Union' or 'Min'
|
|
Returns:
|
|
-------
|
|
index array of the selected bbox
|
|
"""
|
|
# if there are no boxes, return an empty list
|
|
if len(boxes) == 0:
|
|
return []
|
|
|
|
# if the bounding boxes integers, convert them to floats
|
|
if boxes.dtype.kind == "i":
|
|
boxes = boxes.astype("float")
|
|
|
|
# initialize the list of picked indexes
|
|
pick = []
|
|
|
|
# grab the coordinates of the bounding boxes
|
|
x1, y1, x2, y2, score = [boxes[:, i] for i in range(5)]
|
|
|
|
area = (x2 - x1 + 1) * (y2 - y1 + 1)
|
|
idxs = np.argsort(score)
|
|
|
|
# keep looping while some indexes still remain in the indexes list
|
|
while len(idxs) > 0:
|
|
# grab the last index in the indexes list and add the index value to the list of picked indexes
|
|
last = len(idxs) - 1
|
|
i = idxs[last]
|
|
pick.append(i)
|
|
|
|
xx1 = np.maximum(x1[i], x1[idxs[:last]])
|
|
yy1 = np.maximum(y1[i], y1[idxs[:last]])
|
|
xx2 = np.minimum(x2[i], x2[idxs[:last]])
|
|
yy2 = np.minimum(y2[i], y2[idxs[:last]])
|
|
|
|
# compute the width and height of the bounding box
|
|
w = np.maximum(0, xx2 - xx1 + 1)
|
|
h = np.maximum(0, yy2 - yy1 + 1)
|
|
|
|
inter = w * h
|
|
if mode == 'Min':
|
|
overlap = inter / np.minimum(area[i], area[idxs[:last]])
|
|
else:
|
|
overlap = inter / (area[i] + area[idxs[:last]] - inter)
|
|
|
|
# delete all indexes from the index list that have
|
|
idxs = np.delete(
|
|
idxs,
|
|
np.concatenate(([last], np.where(overlap > overlap_threshold)[0])))
|
|
|
|
return pick
|
|
|
|
|
|
def adjust_input(in_data):
|
|
"""
|
|
adjust the input from (h, w, c) to ( 1, c, h, w) for network input
|
|
|
|
Parameters:
|
|
----------
|
|
in_data: numpy array of shape (h, w, c)
|
|
input data
|
|
Returns:
|
|
-------
|
|
out_data: numpy array of shape (1, c, h, w)
|
|
reshaped array
|
|
"""
|
|
if in_data.dtype is not np.dtype('float32'):
|
|
out_data = in_data.astype(np.float32)
|
|
else:
|
|
out_data = in_data
|
|
|
|
out_data = out_data.transpose((2, 0, 1))
|
|
out_data = np.expand_dims(out_data, 0)
|
|
out_data = (out_data - 127.5) * 0.0078125
|
|
return out_data
|
|
|
|
|
|
def generate_bbox(map, reg, scale, threshold):
|
|
"""
|
|
generate bbox from feature map
|
|
Parameters:
|
|
----------
|
|
map: numpy array , n x m x 1
|
|
detect score for each position
|
|
reg: numpy array , n x m x 4
|
|
bbox
|
|
scale: float number
|
|
scale of this detection
|
|
threshold: float number
|
|
detect threshold
|
|
Returns:
|
|
-------
|
|
bbox array
|
|
"""
|
|
stride = 2
|
|
cellsize = 12
|
|
|
|
t_index = np.where(map > threshold)
|
|
|
|
# find nothing
|
|
if t_index[0].size == 0:
|
|
return np.array([])
|
|
|
|
dx1, dy1, dx2, dy2 = [reg[0, i, t_index[0], t_index[1]] for i in range(4)]
|
|
|
|
reg = np.array([dx1, dy1, dx2, dy2])
|
|
score = map[t_index[0], t_index[1]]
|
|
boundingbox = np.vstack([
|
|
np.round((stride * t_index[1] + 1) / scale),
|
|
np.round((stride * t_index[0] + 1) / scale),
|
|
np.round((stride * t_index[1] + 1 + cellsize) / scale),
|
|
np.round((stride * t_index[0] + 1 + cellsize) / scale), score, reg
|
|
])
|
|
|
|
return boundingbox.T
|
|
|
|
|
|
def detect_first_stage(img, net, scale, threshold):
|
|
"""
|
|
run PNet for first stage
|
|
|
|
Parameters:
|
|
----------
|
|
img: numpy array, bgr order
|
|
input image
|
|
scale: float number
|
|
how much should the input image scale
|
|
net: PNet
|
|
worker
|
|
Returns:
|
|
-------
|
|
total_boxes : bboxes
|
|
"""
|
|
height, width, _ = img.shape
|
|
hs = int(math.ceil(height * scale))
|
|
ws = int(math.ceil(width * scale))
|
|
|
|
im_data = cv2.resize(img, (ws, hs))
|
|
|
|
# adjust for the network input
|
|
input_buf = adjust_input(im_data)
|
|
output = net.predict(input_buf)
|
|
boxes = generate_bbox(output[1][0, 1, :, :], output[0], scale, threshold)
|
|
|
|
if boxes.size == 0:
|
|
return None
|
|
|
|
# nms
|
|
pick = nms(boxes[:, 0:5], 0.5, mode='Union')
|
|
boxes = boxes[pick]
|
|
return boxes
|
|
|
|
|
|
def detect_first_stage_warpper(args):
|
|
return detect_first_stage(*args)
|