12 from __future__
import division
15 from dynamic_reconfigure.server
import Server
16 from jsk_perception.cfg
import AWSDetectFacesConfig
18 from jsk_topic_tools
import ConnectionBasedTransport
20 from sensor_msgs.msg
import CompressedImage, Image
21 from opencv_apps.msg
import FaceArrayStamped, Face, Rect
22 from jsk_recognition_msgs.msg
import ClassificationResult, PeoplePoseArray, PeoplePose
23 from tf.transformations
import quaternion_from_euler
65 super(self.__class__, self).
__init__()
67 aws_credentials_path = rospy.get_param(
'~aws_credentials_path',
'aws.json')
68 rospy.loginfo(
"Loading AWS credentials from {}".format(aws_credentials_path))
70 with open(aws_credentials_path)
as f:
71 aws_credentials = json.load(f)
73 rospy.logerr(
'Cannot open "{}".\n Please put region/aws_access_key_id/aws_secret_access_key to aws.json.'.format(aws_credentials_path))
77 aws_access_key_id = aws_credentials[
'aws_access_key_id']
78 aws_secret_access_key = aws_credentials[
'aws_secret_access_key']
79 region_name = aws_credentials[
'region']
81 print(
'Invalid config file')
86 aws_access_key_id=aws_access_key_id,
87 aws_secret_access_key=aws_secret_access_key,
88 region_name=region_name)
93 rospy.loginfo(
"Publish even if face is not found : {}".format(self.
always_publish))
96 rospy.loginfo(
"Launch image window : {}".format(self.
use_window))
100 rospy.loginfo(
"Facial attributes to be returned : {}".format(self.
attributes))
104 self.
faces_pub = self.advertise(
'~faces', FaceArrayStamped, queue_size=1)
105 self.
poses_pub = self.advertise(
'~poses', PoseArray, queue_size=1)
106 self.
attributes_pub = self.advertise(
'~attributes', ClassificationResult, queue_size=1)
107 self.
landmarks_pub = self.advertise(
'~landmarks', PeoplePoseArray, queue_size=1)
108 self.
image_pub = self.advertise(
'~output', Image, queue_size=1)
109 self.
image_comp_pub = self.advertise(
'~output/compressed', CompressedImage, queue_size=1)
110 self.
orig_image_pub = self.advertise(
'~image/compressed', CompressedImage, queue_size=1)
119 self.
buff_size = rospy.get_param(
'~buff_size', 640 * 480 * 3 // 5 * 10)
120 rospy.loginfo(
"rospy.Subscriber buffer size : {}".format(self.
buff_size))
131 new_config = {k: config[k]
for k
in config
if k
in self.
old_config and config[k] != self.
old_config[k]}
134 if 'ALL' in new_config
and new_config[
'ALL']
is True:
136 for key
in config.keys():
137 if key
in [
'ALL',
'groups']:
142 elif 'DEFAULT' in new_config
and new_config[
'DEFAULT']
is True:
144 for key
in config.keys():
145 if key
in [
'DEFAULT',
'groups']:
151 for key
in config.keys():
152 if key
in [
'ALL',
'DEFAULT',
'groups']:
158 config[
'ALL'] =
False
159 config[
'DEFAULT'] =
False
165 rospy.logdebug(
" {}".format(text))
167 cv2.putText(img, text,
168 (bbox.x + bbox.height // 2 + 8, bbox.y - bbox.width // 2 + self.
offset), cv2.FONT_HERSHEY_PLAIN,
169 fontScale=1, color=(0, 255, 0), thickness=1, lineType=cv2.LINE_AA)
175 or self.
image_pub.get_num_connections() > 0 \
179 start_time = rospy.Time.now()
181 np_arr = np.fromstring(image.data, np.uint8)
182 img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR)
184 if image.format.find(
"compressed rgb") > -1:
185 img = img[:, :, ::-1]
188 img_width = img.shape[1]
189 img_height = img.shape[0]
192 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
193 img_gray = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2BGR)
195 _, buf = cv2.imencode(
'.jpg', img)
198 face_msgs = FaceArrayStamped()
199 face_msgs.header = image.header
202 pose_msgs = PoseArray()
203 pose_msgs.header = image.header
206 attributes_msgs = ClassificationResult()
207 attributes_msgs.header = image.header
208 attributes_msgs.label_names = []
209 attributes_msgs.probabilities = []
211 landmarks_msgs = PeoplePoseArray()
212 landmarks_msgs.header = image.header
213 landmarks_msgs.poses = []
216 rospy.logdebug(
"Found {} faces".format(len(faces[
'FaceDetails'])))
217 for face
in faces[
'FaceDetails']:
222 if 'BoundingBox' in face:
223 top =
int(face[
'BoundingBox'][
'Top'] * img_height)
224 left =
int(face[
'BoundingBox'][
'Left'] * img_width)
225 width =
int(face[
'BoundingBox'][
'Width'] * img_width)
226 height =
int(face[
'BoundingBox'][
'Height'] * img_height)
227 bbox_msg.x = left + width // 2
228 bbox_msg.y = top + height // 2
229 bbox_msg.width = width
230 bbox_msg.height = height
232 face_msg.face = bbox_msg
235 cv2.rectangle(img_gray, (left, top), (left + width, top + height), color=(0, 255, 0), thickness=2)
238 if 'Landmarks' in face:
239 landmark_msg = PeoplePose()
240 landmark_msg.limb_names = []
241 landmark_msg.poses = []
242 for i
in range(len(face[
'Landmarks'])):
243 landmark = face[
'Landmarks'][i]
244 px =
int(landmark[
'X'] * img_width)
245 py =
int(landmark[
'Y'] * img_height)
247 landmark_msg.limb_names.append(landmark[
'Type'])
248 landmark_msg.poses.append(Pose(position=Point(x=px, y=py)))
251 cv2.circle(img_gray, (px, py), 1, COLORS[i % (len(COLORS))], thickness=-1)
253 landmarks_msgs.poses.append(landmark_msg)
255 eye_left_msg = Rect()
256 eye_right_msg = Rect()
257 landmark = next((x
for x
in face[
'Landmarks']
if x[
'Type'] ==
'eyeLeft'),
False)
259 eye_left_msg.x =
int(landmark[
'X'] * img_width)
260 eye_left_msg.y =
int(landmark[
'Y'] * img_height)
262 landmark1 = next((x
for x
in face[
'Landmarks']
if x[
'Type'] ==
'leftEyeLeft'),
False)
263 landmark2 = next((x
for x
in face[
'Landmarks']
if x[
'Type'] ==
'leftEyeRight'),
False)
264 if landmark1
and landmark2:
265 eye_left_msg.width =
int((landmark2[
'X'] - landmark1[
'X']) * img_width)
266 landmark1 = next((x
for x
in face[
'Landmarks']
if x[
'Type'] ==
'leftEyeUp'),
False)
267 landmark2 = next((x
for x
in face[
'Landmarks']
if x[
'Type'] ==
'leftEyeDown'),
False)
268 if landmark1
and landmark2:
269 eye_left_msg.height =
int((landmark2[
'Y'] - landmark1[
'Y']) * img_height)
271 landmark = next((x
for x
in face[
'Landmarks']
if x[
'Type'] ==
'eyeRight'),
False)
273 eye_right_msg.x =
int(landmark[
'X'] * img_width)
274 eye_right_msg.y =
int(landmark[
'Y'] * img_height)
276 landmark1 = next((x
for x
in face[
'Landmarks']
if x[
'Type'] ==
'rightEyeLeft'),
False)
277 landmark2 = next((x
for x
in face[
'Landmarks']
if x[
'Type'] ==
'rightEyeRight'),
False)
278 if landmark1
and landmark2:
279 eye_right_msg.width =
int((landmark2[
'X'] - landmark1[
'X']) * img_width)
280 landmark1 = next((x
for x
in face[
'Landmarks']
if x[
'Type'] ==
'rightEyeUp'),
False)
281 landmark2 = next((x
for x
in face[
'Landmarks']
if x[
'Type'] ==
'rightEyeDown'),
False)
282 if landmark1
and landmark2:
283 eye_right_msg.height =
int((landmark2[
'Y'] - landmark1[
'Y']) * img_height)
285 face_msg.eyes = [eye_left_msg, eye_right_msg]
291 if 'Confidence' in face:
292 confidence = face[
'Confidence']
293 face_msg.confidence = confidence
294 attributes_msgs.label_names.append(
'confidence')
295 attributes_msgs.probabilities.append(confidence)
299 if 'AgeRange' in face:
300 self.
process_attributes(
"Age Range : {} - {}".format(face[
'AgeRange'][
'Low'], face[
'AgeRange'][
'High']), img_gray, bbox_msg)
305 yaw = face[
'Pose'][
'Yaw']
306 roll = face[
'Pose'][
'Roll']
307 pitch = face[
'Pose'][
'Pitch']
308 q = quaternion_from_euler(roll * math.pi / 180, pitch * math.pi / 180, yaw * math.pi / 180)
310 pose_msg.orientation.x = q[0]
311 pose_msg.orientation.y = q[1]
312 pose_msg.orientation.z = q[2]
313 pose_msg.orientation.w = q[3]
314 self.
process_attributes(
"Pose : Yaw {:.3f}, Roll {:.3f}, Pitch {:.3f}".format(yaw, roll, pitch), img_gray, bbox_msg)
317 if 'Quality' in face:
318 sharpness = face[
'Quality'][
'Sharpness']
319 brightness = face[
'Quality'][
'Brightness']
320 attributes_msgs.label_names.append(
'sharpness')
321 attributes_msgs.probabilities.append(sharpness)
322 attributes_msgs.label_names.append(
'brightness')
323 attributes_msgs.probabilities.append(brightness)
324 self.
process_attributes(
"Quality : Sharpness {:.3f}, Brightness {:.3f}".format(sharpness, brightness), img_gray, bbox_msg)
327 if 'Emotions' in face:
328 for emotion
in face[
'Emotions']:
329 if emotion[
'Confidence'] > 50:
330 face_msg.label +=
"; {}".format(emotion[
'Type'])
331 attributes_msgs.label_names.append(emotion[
'Type'])
332 attributes_msgs.probabilities.append(emotion[
'Confidence'])
333 self.
process_attributes(
"{}: {:.3f}".format(emotion[
'Type'], emotion[
'Confidence']), img_gray, bbox_msg)
336 for key
in face.keys():
337 if type(face[key])
is dict
and 'Confidence' in face[key]
and 'Value' in face[key]:
338 if face[key][
'Value']
is True:
339 face_msg.label +=
"; {}".format(key)
340 if not face[key][
'Value']
in [
True,
False]:
341 face_msg.label +=
"; {}".format(face[key][
'Value'])
342 if face[key][
'Value']
is True:
343 attributes_msgs.label_names.append(key)
344 attributes_msgs.probabilities.append(face[key][
'Confidence'])
345 elif face[key][
'Value']
is False:
346 attributes_msgs.label_names.append(key)
347 attributes_msgs.probabilities.append(100 - face[key][
'Confidence'])
349 attributes_msgs.label_names.append(face[key][
'Value'])
350 attributes_msgs.probabilities.append(face[key][
'Confidence'])
351 self.
process_attributes(
"{} : {} ({:.3f})".format(key, face[key][
'Value'], face[key][
'Confidence']), img_gray, bbox_msg)
354 face_msg.label = face_msg.label[2:]
355 face_msgs.faces.append(face_msg)
358 pose_msgs.poses.append(pose_msg)
361 cv2.imshow(image._connection_header[
'topic'], img_gray)
367 rospy.loginfo(
"processing time {}".format((rospy.Time.now() - start_time).to_sec()))
370 if self.
image_pub.get_num_connections() > 0:
372 img_gray, encoding=
'bgr8'))
375 msg = CompressedImage()
376 msg.header = image.header
378 msg.data = np.array(cv2.imencode(
'.jpg', img_gray)[1]).tostring()
390 rospy.logdebug(
"processing time {} on message taken at {} sec ago".format(
391 (rospy.Time.now() - start_time).to_sec(),
392 (rospy.Time.now() - image.header.stamp).to_sec()))
395 if __name__ ==
'__main__':
396 rospy.init_node(
'aws_detect_faces')
397 rospy.loginfo(
"ROS node initialized as {}".format(rospy.get_name()))