Files changed (2) hide show
  1. app.py +3 -106
  2. image_resizer.py +114 -0
app.py CHANGED
@@ -1,111 +1,8 @@
1
- import os
2
- import cv2
3
- import cv2 as cv
4
- import numpy as np
5
  import gradio as gr
6
- from yunet import YuNet
7
 
8
-
9
- # Valid combinations of backends and targets
10
- backend_target_pairs = [
11
- [cv.dnn.DNN_BACKEND_OPENCV, cv.dnn.DNN_TARGET_CPU],
12
- [cv.dnn.DNN_BACKEND_CUDA, cv.dnn.DNN_TARGET_CUDA],
13
- [cv.dnn.DNN_BACKEND_CUDA, cv.dnn.DNN_TARGET_CUDA_FP16],
14
- [cv.dnn.DNN_BACKEND_TIMVX, cv.dnn.DNN_TARGET_NPU],
15
- [cv.dnn.DNN_BACKEND_CANN, cv.dnn.DNN_TARGET_NPU],
16
- ]
17
-
18
-
19
- class ImageResizer:
20
- def __init__(
21
- self,
22
- modelPath,
23
- input_size=(320, 320),
24
- conf_threshold=0.6,
25
- nms_threshold=0.3,
26
- top_k=5000,
27
- backend_id=0,
28
- target_id=0,
29
- ):
30
- self.model = YuNet(
31
- modelPath=modelPath,
32
- inputSize=input_size,
33
- confThreshold=conf_threshold,
34
- nmsThreshold=nms_threshold,
35
- topK=top_k,
36
- backendId=backend_id,
37
- targetId=target_id,
38
- )
39
-
40
- def detect(self, image, num_faces=None):
41
- # If input is an image
42
- if image is not None:
43
- h, w, _ = image.shape
44
-
45
- # Inference
46
- self.model.setInputSize([w, h])
47
- results = self.model.infer(image)
48
-
49
- faces = results[:num_faces] if num_faces else results
50
-
51
- bboxs = []
52
-
53
- for face in faces:
54
- bbox = face[0:4].astype(np.int32) # x,y,w,h
55
- x, y, w, h = bbox
56
- # draw
57
- cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
58
- bboxs.append(bbox)
59
-
60
- return image, bboxs
61
-
62
- def resize(self, image, target_size=512, above_head_ratio=0.5):
63
- height, width, _c = image.shape
64
- ar = width / height
65
- # downscale the image
66
- if not target_size:
67
- target_size = 512
68
- if ar > 1:
69
- # Landscape
70
- new_height = target_size
71
- new_width = int(target_size * ar)
72
- elif ar < 1:
73
- # Portrait
74
- new_width = target_size
75
- new_height = int(target_size / ar)
76
- else:
77
- # Square
78
- new_width = target_size
79
- new_height = target_size
80
-
81
- resized = cv2.resize(
82
- image, (new_width, new_height), interpolation=cv2.INTER_LINEAR
83
- )
84
-
85
- # Perform object detection on the resized image
86
- dt_image, bboxes = self.detect(resized.copy())
87
-
88
- # crop around face
89
- if len(bboxes) >= 1:
90
- x, y, w, h = bboxes[0]
91
- else:
92
- x, y, w, h = 0, 0, target_size, target_size
93
- # 20% of image height
94
- above_head_max = int(target_size * above_head_ratio)
95
- x_center = int((x + (x + w)) / 2)
96
- y_center = int((y + (y + h)) / 2)
97
- # Calculate cropping box
98
- left = int(max(0, x_center - target_size // 2))
99
- top = int(max(0, y_center - above_head_max))
100
- right = min(left + target_size, resized.shape[1])
101
- bottom = min(top + target_size, resized.shape[0])
102
-
103
- cropped_image = resized[top:bottom, left:right]
104
- return dt_image, cropped_image
105
-
106
-
107
- model_path = "face_detection_yunet_2023mar.onnx"
108
- image_resizer = ImageResizer(modelPath=model_path)
109
 
110
 
111
  def face_detector(input_image, target_size=512):
 
 
 
 
 
1
  import gradio as gr
2
+ from image_resizer import ImageResizer
3
 
4
+ MODEL_PATH = "face_detection_yunet_2023mar.onnx"
5
+ image_resizer = ImageResizer(modelPath=MODEL_PATH)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
 
8
  def face_detector(input_image, target_size=512):
image_resizer.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import cv2 as cv
3
+ import numpy as np
4
+ from yunet import YuNet
5
+
6
+
7
+ # Valid combinations of backends and targets
8
+ backend_target_pairs = [
9
+ [cv.dnn.DNN_BACKEND_OPENCV, cv.dnn.DNN_TARGET_CPU],
10
+ [cv.dnn.DNN_BACKEND_CUDA, cv.dnn.DNN_TARGET_CUDA],
11
+ [cv.dnn.DNN_BACKEND_CUDA, cv.dnn.DNN_TARGET_CUDA_FP16],
12
+ [cv.dnn.DNN_BACKEND_TIMVX, cv.dnn.DNN_TARGET_NPU],
13
+ [cv.dnn.DNN_BACKEND_CANN, cv.dnn.DNN_TARGET_NPU],
14
+ ]
15
+
16
+
17
+ class ImageResizer:
18
+ def __init__(
19
+ self,
20
+ modelPath,
21
+ input_size=(320, 320),
22
+ conf_threshold=0.6,
23
+ nms_threshold=0.3,
24
+ top_k=5000,
25
+ backend_id=0,
26
+ target_id=0,
27
+ ):
28
+ self.model = YuNet(
29
+ modelPath=modelPath,
30
+ inputSize=input_size,
31
+ confThreshold=conf_threshold,
32
+ nmsThreshold=nms_threshold,
33
+ topK=top_k,
34
+ backendId=backend_id,
35
+ targetId=target_id,
36
+ )
37
+
38
+ def detect(self, image, num_faces=None):
39
+ # If input is an image
40
+ if image is not None:
41
+ h, w, _ = image.shape
42
+
43
+ # Inference
44
+ self.model.setInputSize([w, h])
45
+ results = self.model.infer(image)
46
+
47
+ faces = results[:num_faces] if num_faces else results
48
+
49
+ bboxs = []
50
+
51
+ for face in faces:
52
+ bbox = face[0:4].astype(np.int32) # x,y,w,h
53
+ x, y, w, h = bbox
54
+ # draw
55
+ cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
56
+ bboxs.append(bbox)
57
+
58
+ return image, bboxs
59
+
60
+ def resize(self, image, target_size=512, above_head_ratio=0.5):
61
+ height, width, _c = image.shape
62
+ ar = width / height
63
+ # downscale the image
64
+ if not target_size:
65
+ target_size = 512
66
+ if ar > 1:
67
+ # Landscape
68
+ new_height = target_size
69
+ new_width = int(target_size * ar)
70
+ elif ar < 1:
71
+ # Portrait
72
+ new_width = target_size
73
+ new_height = int(target_size / ar)
74
+ else:
75
+ # Square
76
+ new_width = target_size
77
+ new_height = target_size
78
+
79
+ resized = cv2.resize(
80
+ image, (new_width, new_height), interpolation=cv2.INTER_AREA
81
+ )
82
+
83
+ # Perform object detection on the resized image
84
+ dt_image, bboxes = self.detect(resized.copy())
85
+
86
+ # crop around face
87
+ if len(bboxes) >= 1:
88
+ x, y, w, h = bboxes[0]
89
+ else:
90
+ x, y, w, h = 0, 0, target_size, target_size
91
+ # 20% of image height
92
+ above_head_max = int(target_size * above_head_ratio)
93
+ x_center = int((x + (x + w)) / 2)
94
+ y_center = int((y + (y + h)) / 2)
95
+ # Calculate cropping box
96
+ top = int(max(0, y_center - above_head_max))
97
+ bottom = int(min(top + target_size, resized.shape[0]))
98
+
99
+ left = int(max(0, x_center - target_size // 2))
100
+ right = int(min(x_center + target_size // 2, resized.shape[1]))
101
+
102
+ # adjust width if necessory
103
+ _w = right - left
104
+ if _w != target_size:
105
+ dx = (
106
+ target_size - _w
107
+ ) # difference between the target size and the current width
108
+ nl = max(0, left - dx)
109
+ dr = dx - nl # remaining adjustment needed for the right coordinate
110
+ left = nl
111
+ right += dr
112
+
113
+ cropped_image = resized[top:bottom, left:right]
114
+ return dt_image, cropped_image