| import argparse |
| import glob |
| import os |
|
|
| import cv2 as cv |
| import numpy as np |
|
|
| here = os.path.dirname(os.path.abspath(__file__)) |
|
|
| sz = 300 |
| layers = [ |
| (30, 60, [2], 8, 38), |
| (60, 111, [2, 3], 16, 19), |
| (111, 162, [2, 3], 32, 10), |
| (162, 213, [2, 3], 64, 5), |
| (213, 264, [2], 100, 5), |
| (264, 315, [2], 300, 5), |
| ] |
| var = [0.1, 0.1, 0.2, 0.2] |
|
|
|
|
| def build_priors(): |
| p = [] |
| for mn, mx, ars, step, fm in layers: |
| ratios = [1.0] |
| for a in ars: |
| ratios += [a, 1.0 / a] |
| for y in range(fm): |
| for x in range(fm): |
| cx = (x + 0.5) * step |
| cy = (y + 0.5) * step |
| boxes = [(mn, mn), ((mn * mx) ** 0.5, (mn * mx) ** 0.5)] |
| for a in ratios[1:]: |
| boxes.append((mn * a ** 0.5, mn / a ** 0.5)) |
| for bw, bh in boxes: |
| p.append([cx, cy, bw, bh]) |
| return np.array(p, np.float32) |
|
|
|
|
| def default_model(): |
| files = [f for f in glob.glob(os.path.join(here, "*.onnx")) if "known_good" not in os.path.basename(f)] |
| return files[0] if files else os.path.join(here, "opencv_face_detector_uint8.onnx") |
|
|
|
|
| def main(): |
| parser = argparse.ArgumentParser(description="OpenCV SSD face detector (ONNX) demo") |
| parser.add_argument("--model", default=default_model()) |
| parser.add_argument("--image", default=os.path.join(here, "example_outputs", "input_image.png")) |
| parser.add_argument("--output", default=os.path.join(here, "example_outputs", "output_image.png")) |
| parser.add_argument("--conf", type=float, default=0.4) |
| args = parser.parse_args() |
|
|
| img = cv.imread(args.image) |
| if img is None: |
| raise SystemExit("could not read image: %s" % args.image) |
|
|
| inp = cv.resize(img, (sz, sz)).astype(np.float32) - np.array([104.0, 177.0, 123.0], np.float32) |
|
|
| net = cv.dnn.readNetFromONNX(args.model) |
| onames = net.getUnconnectedOutLayersNames() |
| net.setInput(inp[None]) |
| res = net.forward(onames) |
| loc = res[[i for i, n in enumerate(onames) if "mbox_loc" in n][0]].reshape(-1, 4) |
| conf = res[[i for i, n in enumerate(onames) if "mbox_conf" in n][0]].reshape(-1, 2) |
|
|
| priors = build_priors() |
| pcx = priors[:, 0] / sz |
| pcy = priors[:, 1] / sz |
| pw = priors[:, 2] / sz |
| ph = priors[:, 3] / sz |
|
|
| e = np.exp(conf - conf.max(1, keepdims=True)) |
| sm = e / e.sum(1, keepdims=True) |
| scores = sm[:, 1] |
|
|
| cx = pcx + loc[:, 0] * var[0] * pw |
| cy = pcy + loc[:, 1] * var[1] * ph |
| bw = pw * np.exp(loc[:, 2] * var[2]) |
| bh = ph * np.exp(loc[:, 3] * var[3]) |
| boxes = np.stack([cx - bw / 2, cy - bh / 2, cx + bw / 2, cy + bh / 2], 1) |
|
|
| keep = scores > args.conf |
| boxes = boxes[keep] |
| scores = scores[keep] |
| order = scores.argsort()[::-1] |
| pick = [] |
| while order.size: |
| i = order[0] |
| pick.append(i) |
| xx1 = np.maximum(boxes[i, 0], boxes[order[1:], 0]) |
| yy1 = np.maximum(boxes[i, 1], boxes[order[1:], 1]) |
| xx2 = np.minimum(boxes[i, 2], boxes[order[1:], 2]) |
| yy2 = np.minimum(boxes[i, 3], boxes[order[1:], 3]) |
| inter = np.maximum(0, xx2 - xx1) * np.maximum(0, yy2 - yy1) |
| ai = (boxes[i, 2] - boxes[i, 0]) * (boxes[i, 3] - boxes[i, 1]) |
| aj = (boxes[order[1:], 2] - boxes[order[1:], 0]) * (boxes[order[1:], 3] - boxes[order[1:], 1]) |
| iou = inter / (ai + aj - inter + 1e-9) |
| order = order[1:][iou <= 0.3] |
|
|
| h, w = img.shape[:2] |
| for i in pick: |
| x1, y1, x2, y2 = boxes[i] |
| cv.rectangle(img, (int(x1 * w), int(y1 * h)), (int(x2 * w), int(y2 * h)), (0, 255, 0), 2) |
| cv.imwrite(args.output, img) |
| print("opencv_face_detector_uint8", len(pick), "faces") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|