Skip to content

Commit b516e04

Browse files
committed
Added facial landmark est
Signed-off-by: Mpho Mphego <mpho112@gmail.com>
1 parent 03ba54e commit b516e04

File tree

2 files changed

+47
-20
lines changed

2 files changed

+47
-20
lines changed

main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def main(args):
164164
if face_height < 20 or face_width < 20:
165165
continue
166166

167-
predict_end_time, _, landmarks_bboxes = facial_landmarks.predict(face)
167+
predict_end_time, _, landmarks_bboxes = facial_landmarks.predict(face, draw=True)
168168
text = f"Facial Landmarks Est. Inference time: {predict_end_time:.3f} s"
169169
facial_landmarks.add_text(
170170
text, frame, (15, video_feed.source_height - 60)

src/model.py

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import abc
21
import argparse
32
import os
43
import sys
54
import time
65
import subprocess
76

7+
from abc import ABC, abstractmethod
88
from pathlib import Path
99

1010
import cv2
1111
import numpy as np
12+
import matplotlib.pyplot as plt
1213

1314
from loguru import logger
1415
from openvino.inference_engine import IENetwork, IECore
@@ -22,7 +23,7 @@
2223
]
2324

2425

25-
class Base(abc.ABC):
26+
class Base(ABC):
2627
"""Model Base Class"""
2728

2829
def __init__(
@@ -110,19 +111,26 @@ def predict(self, image, request_id=0, draw=False):
110111
bbox, _ = self.preprocess_output(pred_result, image, show_bbox=draw)
111112
return (predict_end_time, pred_result, bbox)
112113

113-
@abc.abstractmethod
114+
@abstractmethod
114115
def preprocess_output(self, inference_results, image, show_bbox=False):
115116
"""Draw bounding boxes onto the frame."""
116-
pass
117+
raise NotImplementedError("Please Implement this method")
117118

118119
@staticmethod
119-
@abc.abstractmethod
120-
def draw_output(image,):
121-
pass
120+
@abstractmethod
121+
def draw_output(image):
122+
raise NotImplementedError("Please Implement this method")
122123

123-
def add_text(self, text, frame, position, font_size=0.75, color=(255, 255, 255)):
124+
@staticmethod
125+
def plot_frame(image):
126+
"""Helper function for finding image coordinates/px"""
127+
img = image[:, :, 0]
128+
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
129+
plt.show()
130+
131+
def add_text(self, text, image, position, font_size=0.75, color=(255, 255, 255)):
124132
cv2.putText(
125-
frame, text, position, cv2.FONT_HERSHEY_COMPLEX, font_size, color, 1,
133+
image, text, position, cv2.FONT_HERSHEY_COMPLEX, font_size, color, 1,
126134
)
127135

128136
def preprocess_input(self, image):
@@ -151,7 +159,7 @@ def __init__(
151159
)
152160

153161
def preprocess_output(self, inference_results, image, show_bbox=False):
154-
"""Draw bounding boxes onto the frame."""
162+
"""Draw bounding boxes onto the Face Detection frame."""
155163
if not (self._init_image_w and self._init_image_h):
156164
raise RuntimeError("Initial image width and height cannot be None.")
157165

@@ -215,8 +223,8 @@ def draw_output(
215223
)
216224

217225

218-
class Head_Pose_Estimation(Base):
219-
"""Class for the Head Pose Estimation Model."""
226+
class Facial_Landmarks(Base):
227+
"""Class for the Facial Landmarks Detection Model."""
220228

221229
def __init__(
222230
self,
@@ -231,15 +239,34 @@ def __init__(
231239
model_name, source_width, source_height, device, threshold, extensions,
232240
)
233241

234-
def preprocess_output(self, inference_results, image):
235-
pass
236-
237-
def draw_output(coords, image):
238-
pass
242+
def preprocess_output(self, inference_results, image, show_bbox=False):
243+
"""Draw bounding boxes onto the Facial Landmarks frame."""
244+
# If using model: https://docs.openvinotoolkit.org/latest/_models_intel_landmarks_regression_retail_0009_description_landmarks_regression_retail_0009.html
245+
flattened_predictions = np.vstack(inference_results).ravel()
246+
eyes_coords = flattened_predictions[:4]
247+
h, w = image.shape[:2]
248+
249+
left_eye_x_coord = int(eyes_coords[0] * w)
250+
left_eye_y_coord = int(eyes_coords[1] * h)
251+
right_eye_x_coord = int(eyes_coords[2] * w)
252+
right_eye_y_coord = int(eyes_coords[3] * h)
253+
254+
eyes_coords = {
255+
"left_eye_point": (left_eye_x_coord, left_eye_y_coord),
256+
"right_eye_point": (right_eye_x_coord, right_eye_y_coord),
257+
}
258+
if show_bbox:
259+
self.draw_output(image, eyes_coords)
260+
return eyes_coords
239261

262+
@staticmethod
263+
def draw_output(image, eyes_coords, radius=10, color=(255, 0, 0), thickness=2):
264+
"""Draw a circle around ROI"""
265+
for eye, coords in eyes_coords.items():
266+
cv2.circle(image, (coords[0], coords[1]), radius, color, thickness)
240267

241-
class Facial_Landmarks(Base):
242-
"""Class for the Facial Landmarks Detection Model."""
268+
class Head_Pose_Estimation(Base):
269+
"""Class for the Head Pose Estimation Model."""
243270

244271
def __init__(
245272
self,

0 commit comments

Comments
 (0)