Skip to content

Commit eeb5b84

Browse files
committed
update face and head detection
1 parent fd0da22 commit eeb5b84

File tree

2 files changed

+184
-14
lines changed

2 files changed

+184
-14
lines changed

src/face_detection.py

Lines changed: 111 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,149 @@
22
This is a sample class for a model. You may choose to use it as-is or make any changes to it.
33
This has been provided just to give you an idea of how to structure your model class.
44
'''
5+
import cv2
6+
import numpy as np
7+
from openvino.inference_engine import IECore
58

6-
class Model_X:
9+
class FaceDetectionModel:
710
'''
811
Class for the Face Detection Model.
912
'''
1013
def __init__(self, model_name, device='CPU', extensions=None):
1114
'''
1215
TODO: Use this to set your instance variables.
1316
'''
14-
raise NotImplementedError
17+
self.model_name = model_name
18+
self.device = device
19+
self.extensions = extensions
20+
self.model_structure = self.model_name # model xml file
21+
self.model_weights = self.model_name.split('.')[0]+'.bin' # get model binary file path just use model xml file
22+
self.plugin = None
23+
self.network = None
24+
self.exec_net = None
25+
self.input_name = None
26+
self.input_shape = None
27+
self.output_names = None
28+
self.output_shape = None
1529

1630
def load_model(self):
1731
'''
1832
TODO: You will need to complete this method.
1933
This method is for loading the model to the device specified by the user.
2034
If your model requires any Plugins, this is where you can load them.
2135
'''
22-
raise NotImplementedError
36+
# load the IE Engine API plugin (Inference Engine entity)
37+
self.plugin = IECore()
38+
# Reads a network from the IR files and creates an IENetwork, load IR files into their related class, architecture with XML and weights with binary file
39+
self.network = self.plugin.read_network(model=self.model_structure, weights=self.model_weights)
40+
# Queries the plugin with specified device name what network layers are supported in the current configuration.
41+
# get the supported layers of the network
42+
supported_layers = self.plugin.query_network(network=self.network, device_name=self.device)
43+
# check unsupported layer
44+
unsupported_layers = [ul for ul in self.network.layers.keys() if ul not in supported_layers]
45+
46+
# condition of found unsupported layer and device is CPU
47+
if len(unsupported_layers)!=0 and self.device=='CPU':
48+
print('unsupported layers found:{}'.format(unsupported_layers))
49+
# extension is not None
50+
if not self.extensions==None:
51+
print("Adding cpu_extension")
52+
# Loads extension library to the plugin with a specified device name.
53+
self.plugin.add_extension(self.extensions, self.device)
54+
# update the support and unsupported layers
55+
supported_layers = self.plugin.query_network(network=self.network, device_name=self.device)
56+
unsupported_layers = [ul for ul in self.network.layers.keys() if ul not in supported_layers]
57+
# if still no unsupported layer exit
58+
if len(unsupported_layers)!=0:
59+
print("After adding the extensions still unsupported layers found")
60+
exit(1)
61+
print("After adding the extension the issue is resolved")
62+
# extensions is None exit
63+
else:
64+
print("Give the path of cpu extension")
65+
exit(1)
66+
# Loads a network that was read from the Intermediate Representation (IR) to the plugin with specified device
67+
# load the network into the inference engine
68+
self.exec_net = self.plugin.load_network(network=self.network, device_name=self.device, num_requests=1)
69+
70+
# Get the input layer, iterate through the inputs here
71+
self.input_name = next(iter(self.network.inputs))
72+
# Return the shape of the input layer
73+
self.input_shape self.network.inputs[self.input_name].shape
74+
# Get the output layer
75+
self.output_names = netx(iter(self.network.outputs))
76+
# Return the shape of the output layer
77+
self.output_shape = self.network.outputs[self.output_names].shape
78+
2379

2480
def predict(self, image):
2581
'''
2682
TODO: You will need to complete this method.
2783
This method is meant for running predictions on the input image.
2884
'''
29-
raise NotImplementedError
85+
# 1.process the image
86+
img_processed = self.preprocess_input(image.copy())
87+
# 2.Starts synchronous inference for the first infer request of the executable network and returns output data.
88+
# A dictionary that maps output layer names
89+
outputs = self.exec_net.infer({self.input_name:img_processed})
90+
print(outputs)
91+
# 3. process the outputs
92+
coords = self.preprocess_output(outputs, prob_threshold)
93+
# if coords empty, return 0,0
94+
if (len(coords)==0):
95+
return 0, 0
96+
# get the first detected face
97+
coords = coords[0]
98+
h=image.shape[0]
99+
w=image.shape[1]
100+
print(coords)
101+
102+
coords = coords* np.array([w, h, w, h])
103+
# Copy of the array, cast to a specified type. int32
104+
coords = coords.astype(np.int32)
105+
print(coords)
106+
107+
cropped_face = image[coords[1]:coords[3], coords[0]:coords[2]]
108+
print(cropped_face)
109+
110+
return cropped_face, coords
111+
30112

31113
def check_model(self):
32-
raise NotImplementedError
114+
# raise NotImplementedError
115+
pass
33116

34117
def preprocess_input(self, image):
35118
'''
36119
Before feeding the data into the model for inference,
37120
you might have to preprocess it. This function is where you can do that.
121+
Given an input image, height and width:
38122
'''
39-
raise NotImplementedError
123+
# - Resize to height and width, (H, W), but resize use W, H which is opposite order
124+
# print(self.input_shape)
125+
image_resized = cv2.resize(image, (self.input_shape[3], self.input.shape[2]))
126+
# print(image_resized)
127+
# - Transpose the final "channel" dimension to be first to BGR
128+
# - Reshape the image to add a "batch" of 1 at the start
129+
img_processed = np.transpose(np.expand_dims(image_resized, axis=0), (0,3,1,2))
130+
# print(img_processed) # BxCxHxW
131+
132+
return img_processed
133+
40134

41135
def preprocess_output(self, outputs):
42136
'''
43137
Before feeding the output of this model to the next model,
44138
you might have to preprocess the output. This function is where you can do that.
45139
'''
46-
raise NotImplementedError
140+
coords = []
141+
outs = outputs[self.output_names][0][0] # output
142+
for out in outs:
143+
conf = out[2]
144+
if conf > prob_threshold:
145+
x_min=out[3]
146+
y_min=out[4]
147+
x_max=out[5]
148+
y_max=out[6]
149+
coords.append([x_min, y_min, x_max, y_max])
150+
return coords

src/head_pose_estimation.py

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,111 @@
22
This is a sample class for a model. You may choose to use it as-is or make any changes to it.
33
This has been provided just to give you an idea of how to structure your model class.
44
'''
5+
import cv2
6+
import numpy as np
7+
from openvino.inference_engine import IECore
58

6-
class Model_X:
9+
class HeadPoseEstimationModel:
710
'''
811
Class for the Face Detection Model.
912
'''
1013
def __init__(self, model_name, device='CPU', extensions=None):
1114
'''
1215
TODO: Use this to set your instance variables.
1316
'''
14-
raise NotImplementedError
17+
self.model_name = model_name
18+
self.device = device
19+
self.extensions = extensions
20+
self.model_structure = self.model_name
21+
self.model_weights = self.model_name.split(".")[0] + '.bin'
22+
self.plugin = None
23+
self.network = None
24+
self.exec_net = None
25+
self.input_name = None
26+
self.input_shape = None
27+
self.output_names = None
28+
1529

1630
def load_model(self):
1731
'''
1832
TODO: You will need to complete this method.
1933
This method is for loading the model to the device specified by the user.
2034
If your model requires any Plugins, this is where you can load them.
2135
'''
22-
raise NotImplementedError
36+
self.plugin = IECore()
37+
self.network = self.plugin.read_network(model=self.model_structure, weights=self.model_weights)
38+
supported_layers = self.plugin.query_network(network=self.network, device_name=self.device)
39+
unsupported_layers = [ul for ul in self.network.layers.keys() if ul not in supported_layers]
40+
41+
42+
if len(unsupported_layers)!=0 and self.device=='CPU':
43+
print("unsupported layers found{}".format(unsupported_layers))
44+
if not self.extensions==None:
45+
print("Adding cpu_extension")
46+
self.plugin.add_extension(self.extensions, self.device)
47+
supported_layers = self.plugin.query_network(network=self.network, device_name=self.device)
48+
unsupported_layers = [ul for ul in self.network.layers.keys() if ul not in supported_layers]
49+
if len(unsupported_layers)!=0:
50+
print("After adding the extensions still unsupported layers found")
51+
exit(1)
52+
print("After adding the extension still unsupported layers found")
53+
else:
54+
print("Give the path of cpu extension")
55+
exit(1)
56+
57+
self.exec_net = self.plugin.load_network(network.self.network, device_name=self.device, num_requests=1)
58+
59+
self.input_name = next(iter(self.network.inputs))
60+
self.input_shape = self.network.inputs[self.input_name].shape
61+
self.output_names = [i for i in self.network.outputs.keys()]
62+
2363

2464
def predict(self, image):
2565
'''
2666
TODO: You will need to complete this method.
2767
This method is meant for running predictions on the input image.
2868
'''
29-
raise NotImplementedError
69+
img_processed = self.preprocess_input(image.copy())
70+
outputs = self.exec_net({self.input_name:img_processed})
71+
lastOutput = self.preprocess_output(outputs)
72+
73+
return lastOutput
3074

3175
def check_model(self):
32-
raise NotImplementedError
76+
pass
3377

3478
def preprocess_input(self, image):
3579
'''
3680
Before feeding the data into the model for inference,
3781
you might have to preprocess it. This function is where you can do that.
3882
'''
39-
raise NotImplementedError
83+
# we wanna opposite order from H, W
84+
image_resized = cv2.resize(image, (self.input_shape[3], self,input_shape[2]))
85+
# (optional)
86+
# img_processed = np.transpose(np.expand_dims(image_resized, axis=0), (0, 3, 1, 2))
87+
88+
# transpose so that order has channels 1st, cuz our image after resizing still have channels last
89+
# 1st put the 3rd channel which is our image channels for BGR.
90+
# and next is 0 and 1 which were originally our heihgt and width of the image
91+
image = image_resized.transpose((2,0,1))
92+
# add 1 dim at very start, then channels then H, W
93+
img_processed = image.reshape(1, 3, self.input_shape[2], self.input_shape[3])
94+
95+
return img_processed
4096

4197
def preprocess_output(self, outputs):
4298
'''
4399
Before feeding the output of this model to the next model,
44100
you might have to preprocess the output. This function is where you can do that.
101+
https://docs.openvinotoolkit.org/latest/omz_models_intel_head_pose_estimation_adas_0001_description_head_pose_estimation_adas_0001.html
102+
Output layer names in Inference Engine format:
103+
104+
name: "angle_y_fc", shape: [1, 1] - Estimated yaw (in degrees).
105+
name: "angle_p_fc", shape: [1, 1] - Estimated pitch (in degrees).
106+
name: "angle_r_fc", shape: [1, 1] - Estimated roll (in degrees).
45107
'''
46-
raise NotImplementedError
108+
outs = []
109+
outs.append(outputs['angle_y_fc'].tolist()[0][0])
110+
outs.append(outputs['angle_p_fc'].tolist()[0][0])
111+
outs.append(outputs['angle_r_fc'].tolist()[0][0])
112+
return outs

0 commit comments

Comments
 (0)