| import torch |
| from torch.autograd import Variable |
| import math |
| from PIL import Image |
| import numpy as np |
| from align.box_utils import nms, _preprocess |
|
|
|
|
| def run_first_stage(image, net, scale, threshold): |
| """Run P-Net, generate bounding boxes, and do NMS. |
| |
| Arguments: |
| image: an instance of PIL.Image. |
| net: an instance of pytorch's nn.Module, P-Net. |
| scale: a float number, |
| scale width and height of the image by this number. |
| threshold: a float number, |
| threshold on the probability of a face when generating |
| bounding boxes from predictions of the net. |
| |
| Returns: |
| a float numpy array of shape [n_boxes, 9], |
| bounding boxes with scores and offsets (4 + 1 + 4). |
| """ |
|
|
| |
| width, height = image.size |
| sw, sh = math.ceil(width * scale), math.ceil(height * scale) |
| img = image.resize((sw, sh), Image.BILINEAR) |
| img = np.asarray(img, "float32") |
|
|
| img = Variable(torch.FloatTensor(_preprocess(img)), volatile=True) |
| output = net(img) |
| probs = output[1].data.numpy()[0, 1, :, :] |
| offsets = output[0].data.numpy() |
| |
| |
|
|
| boxes = _generate_bboxes(probs, offsets, scale, threshold) |
| if len(boxes) == 0: |
| return None |
|
|
| keep = nms(boxes[:, 0:5], overlap_threshold=0.5) |
| return boxes[keep] |
|
|
|
|
| def _generate_bboxes(probs, offsets, scale, threshold): |
| """Generate bounding boxes at places |
| where there is probably a face. |
| |
| Arguments: |
| probs: a float numpy array of shape [n, m]. |
| offsets: a float numpy array of shape [1, 4, n, m]. |
| scale: a float number, |
| width and height of the image were scaled by this number. |
| threshold: a float number. |
| |
| Returns: |
| a float numpy array of shape [n_boxes, 9] |
| """ |
|
|
| |
| |
| stride = 2 |
| cell_size = 12 |
|
|
| |
| inds = np.where(probs > threshold) |
|
|
| if inds[0].size == 0: |
| return np.array([]) |
|
|
| |
| tx1, ty1, tx2, ty2 = [offsets[0, i, inds[0], inds[1]] for i in range(4)] |
| |
| |
| |
| |
| |
| |
| |
|
|
| offsets = np.array([tx1, ty1, tx2, ty2]) |
| score = probs[inds[0], inds[1]] |
|
|
| |
| |
| bounding_boxes = np.vstack( |
| [ |
| np.round((stride * inds[1] + 1.0) / scale), |
| np.round((stride * inds[0] + 1.0) / scale), |
| np.round((stride * inds[1] + 1.0 + cell_size) / scale), |
| np.round((stride * inds[0] + 1.0 + cell_size) / scale), |
| score, |
| offsets, |
| ] |
| ) |
| |
|
|
| return bounding_boxes.T |
|
|