detect_face.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import cv2
  2. import time
  3. import argparse
  4. import numpy as np
  5. class SCRFD():
  6. def __init__(self, onnxmodel, confThreshold=0.5, nmsThreshold=0.5):
  7. self.inpWidth = 640
  8. self.inpHeight = 640
  9. self.confThreshold = confThreshold
  10. self.nmsThreshold = nmsThreshold
  11. self.net = cv2.dnn.readNet(onnxmodel)
  12. self.keep_ratio = True
  13. self.fmc = 3
  14. self._feat_stride_fpn = [8, 16, 32]
  15. self._num_anchors = 2
  16. def resize_image(self, srcimg):
  17. padh, padw, newh, neww = 0, 0, self.inpHeight, self.inpWidth
  18. if self.keep_ratio and srcimg.shape[0] != srcimg.shape[1]:
  19. hw_scale = srcimg.shape[0] / srcimg.shape[1]
  20. if hw_scale > 1:
  21. newh, neww = self.inpHeight, int(self.inpWidth / hw_scale)
  22. img = cv2.resize(srcimg, (neww, newh), interpolation=cv2.INTER_AREA)
  23. padw = int((self.inpWidth - neww) * 0.5)
  24. img = cv2.copyMakeBorder(img, 0, 0, padw, self.inpWidth - neww - padw, cv2.BORDER_CONSTANT,
  25. value=0) # add border
  26. else:
  27. newh, neww = int(self.inpHeight * hw_scale) + 1, self.inpWidth
  28. img = cv2.resize(srcimg, (neww, newh), interpolation=cv2.INTER_AREA)
  29. padh = int((self.inpHeight - newh) * 0.5)
  30. img = cv2.copyMakeBorder(img, padh, self.inpHeight - newh - padh, 0, 0, cv2.BORDER_CONSTANT, value=0)
  31. else:
  32. img = cv2.resize(srcimg, (self.inpWidth, self.inpHeight), interpolation=cv2.INTER_AREA)
  33. return img, newh, neww, padh, padw
  34. def distance2bbox(self, points, distance, max_shape=None):
  35. x1 = points[:, 0] - distance[:, 0]
  36. y1 = points[:, 1] - distance[:, 1]
  37. x2 = points[:, 0] + distance[:, 2]
  38. y2 = points[:, 1] + distance[:, 3]
  39. if max_shape is not None:
  40. x1 = x1.clamp(min=0, max=max_shape[1])
  41. y1 = y1.clamp(min=0, max=max_shape[0])
  42. x2 = x2.clamp(min=0, max=max_shape[1])
  43. y2 = y2.clamp(min=0, max=max_shape[0])
  44. return np.stack([x1, y1, x2, y2], axis=-1)
  45. def distance2kps(self, points, distance, max_shape=None):
  46. preds = []
  47. for i in range(0, distance.shape[1], 2):
  48. px = points[:, i % 2] + distance[:, i]
  49. py = points[:, i % 2 + 1] + distance[:, i + 1]
  50. if max_shape is not None:
  51. px = px.clamp(min=0, max=max_shape[1])
  52. py = py.clamp(min=0, max=max_shape[0])
  53. preds.append(px)
  54. preds.append(py)
  55. return np.stack(preds, axis=-1)
  56. def detect(self, srcimg):
  57. t1 = time.time()
  58. img, newh, neww, padh, padw = self.resize_image(srcimg)
  59. blob = cv2.dnn.blobFromImage(img, 1.0 / 128, (self.inpWidth, self.inpHeight), (127.5, 127.5, 127.5), swapRB=True)
  60. # Sets the input to the network
  61. self.net.setInput(blob)
  62. # Runs the forward pass to get output of the output layers
  63. outs = self.net.forward(self.net.getUnconnectedOutLayersNames())
  64. # inference output
  65. scores_list, bboxes_list, kpss_list = [], [], []
  66. for idx, stride in enumerate(self._feat_stride_fpn):
  67. scores = outs[idx][0]
  68. bbox_preds = outs[idx + self.fmc * 1][0] * stride
  69. kps_preds = outs[idx + self.fmc * 2][0] * stride
  70. height = blob.shape[2] // stride
  71. width = blob.shape[3] // stride
  72. anchor_centers = np.stack(np.mgrid[:height, :width][::-1], axis=-1).astype(np.float32)
  73. anchor_centers = (anchor_centers * stride).reshape((-1, 2))
  74. if self._num_anchors > 1:
  75. anchor_centers = np.stack([anchor_centers] * self._num_anchors, axis=1).reshape((-1, 2))
  76. pos_inds = np.where(scores >= self.confThreshold)[0]
  77. bboxes = self.distance2bbox(anchor_centers, bbox_preds)
  78. pos_scores = scores[pos_inds]
  79. pos_bboxes = bboxes[pos_inds]
  80. scores_list.append(pos_scores)
  81. bboxes_list.append(pos_bboxes)
  82. kpss = self.distance2kps(anchor_centers, kps_preds)
  83. # kpss = kps_preds
  84. kpss = kpss.reshape((kpss.shape[0], -1, 2))
  85. pos_kpss = kpss[pos_inds]
  86. kpss_list.append(pos_kpss)
  87. scores = np.vstack(scores_list).ravel()
  88. # bboxes = np.vstack(bboxes_list) / det_scale
  89. # kpss = np.vstack(kpss_list) / det_scale
  90. bboxes = np.vstack(bboxes_list)
  91. kpss = np.vstack(kpss_list)
  92. bboxes[:, 2:4] = bboxes[:, 2:4] - bboxes[:, 0:2]
  93. ratioh, ratiow = srcimg.shape[0] / newh, srcimg.shape[1] / neww
  94. bboxes[:, 0] = (bboxes[:, 0] - padw) * ratiow
  95. bboxes[:, 1] = (bboxes[:, 1] - padh) * ratioh
  96. bboxes[:, 2] = bboxes[:, 2] * ratiow
  97. bboxes[:, 3] = bboxes[:, 3] * ratioh
  98. kpss[:, :, 0] = (kpss[:, :, 0] - padw) * ratiow
  99. kpss[:, :, 1] = (kpss[:, :, 1] - padh) * ratioh
  100. indices = cv2.dnn.NMSBoxes(bboxes.tolist(), scores.tolist(), self.confThreshold, self.nmsThreshold)
  101. return bboxes, indices, kpss