|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import os |
|
|
import json |
|
|
import cv2 |
|
|
import math |
|
|
import numpy as np |
|
|
import paddle |
|
|
import yaml |
|
|
|
|
|
from det_keypoint_unite_utils import argsparser |
|
|
from preprocess import decode_image |
|
|
from infer import Detector, DetectorPicoDet, PredictConfig, print_arguments, get_test_images, bench_log |
|
|
from keypoint_infer import KeyPointDetector, PredictConfig_KeyPoint |
|
|
from visualize import visualize_pose |
|
|
from benchmark_utils import PaddleInferBenchmark |
|
|
from utils import get_current_memory_mb |
|
|
from keypoint_postprocess import translate_to_ori_images |
|
|
|
|
|
KEYPOINT_SUPPORT_MODELS = { |
|
|
'HigherHRNet': 'keypoint_bottomup', |
|
|
'HRNet': 'keypoint_topdown' |
|
|
} |
|
|
|
|
|
|
|
|
def predict_with_given_det(image, det_res, keypoint_detector, |
|
|
keypoint_batch_size, run_benchmark): |
|
|
keypoint_res = {} |
|
|
|
|
|
rec_images, records, det_rects = keypoint_detector.get_person_from_rect( |
|
|
image, det_res) |
|
|
|
|
|
if len(det_rects) == 0: |
|
|
keypoint_res['keypoint'] = [[], []] |
|
|
return keypoint_res |
|
|
|
|
|
keypoint_vector = [] |
|
|
score_vector = [] |
|
|
|
|
|
rect_vector = det_rects |
|
|
keypoint_results = keypoint_detector.predict_image( |
|
|
rec_images, run_benchmark, repeats=10, visual=False) |
|
|
keypoint_vector, score_vector = translate_to_ori_images(keypoint_results, |
|
|
np.array(records)) |
|
|
keypoint_res['keypoint'] = [ |
|
|
keypoint_vector.tolist(), score_vector.tolist() |
|
|
] if len(keypoint_vector) > 0 else [[], []] |
|
|
keypoint_res['bbox'] = rect_vector |
|
|
return keypoint_res |
|
|
|
|
|
|
|
|
def topdown_unite_predict(detector, |
|
|
topdown_keypoint_detector, |
|
|
image_list, |
|
|
keypoint_batch_size=1, |
|
|
save_res=False): |
|
|
det_timer = detector.get_timer() |
|
|
store_res = [] |
|
|
for i, img_file in enumerate(image_list): |
|
|
|
|
|
det_timer.preprocess_time_s.start() |
|
|
image, _ = decode_image(img_file, {}) |
|
|
det_timer.preprocess_time_s.end() |
|
|
|
|
|
if FLAGS.run_benchmark: |
|
|
results = detector.predict_image( |
|
|
[image], run_benchmark=True, repeats=10) |
|
|
|
|
|
cm, gm, gu = get_current_memory_mb() |
|
|
detector.cpu_mem += cm |
|
|
detector.gpu_mem += gm |
|
|
detector.gpu_util += gu |
|
|
else: |
|
|
results = detector.predict_image([image], visual=False) |
|
|
results = detector.filter_box(results, FLAGS.det_threshold) |
|
|
if results['boxes_num'] > 0: |
|
|
keypoint_res = predict_with_given_det( |
|
|
image, results, topdown_keypoint_detector, keypoint_batch_size, |
|
|
FLAGS.run_benchmark) |
|
|
|
|
|
if save_res: |
|
|
save_name = img_file if isinstance(img_file, str) else i |
|
|
store_res.append([ |
|
|
save_name, keypoint_res['bbox'], |
|
|
[keypoint_res['keypoint'][0], keypoint_res['keypoint'][1]] |
|
|
]) |
|
|
else: |
|
|
results["keypoint"] = [[], []] |
|
|
keypoint_res = results |
|
|
if FLAGS.run_benchmark: |
|
|
cm, gm, gu = get_current_memory_mb() |
|
|
topdown_keypoint_detector.cpu_mem += cm |
|
|
topdown_keypoint_detector.gpu_mem += gm |
|
|
topdown_keypoint_detector.gpu_util += gu |
|
|
else: |
|
|
if not os.path.exists(FLAGS.output_dir): |
|
|
os.makedirs(FLAGS.output_dir) |
|
|
visualize_pose( |
|
|
img_file, |
|
|
keypoint_res, |
|
|
visual_thresh=FLAGS.keypoint_threshold, |
|
|
save_dir=FLAGS.output_dir) |
|
|
if save_res: |
|
|
""" |
|
|
1) store_res: a list of image_data |
|
|
2) image_data: [imageid, rects, [keypoints, scores]] |
|
|
3) rects: list of rect [xmin, ymin, xmax, ymax] |
|
|
4) keypoints: 17(joint numbers)*[x, y, conf], total 51 data in list |
|
|
5) scores: mean of all joint conf |
|
|
""" |
|
|
with open("det_keypoint_unite_image_results.json", 'w') as wf: |
|
|
json.dump(store_res, wf, indent=4) |
|
|
|
|
|
|
|
|
def topdown_unite_predict_video(detector, |
|
|
topdown_keypoint_detector, |
|
|
camera_id, |
|
|
keypoint_batch_size=1, |
|
|
save_res=False): |
|
|
video_name = 'output.mp4' |
|
|
if camera_id != -1: |
|
|
capture = cv2.VideoCapture(camera_id) |
|
|
else: |
|
|
capture = cv2.VideoCapture(FLAGS.video_file) |
|
|
video_name = os.path.split(FLAGS.video_file)[-1] |
|
|
|
|
|
width = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH)) |
|
|
height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT)) |
|
|
fps = int(capture.get(cv2.CAP_PROP_FPS)) |
|
|
frame_count = int(capture.get(cv2.CAP_PROP_FRAME_COUNT)) |
|
|
print("fps: %d, frame_count: %d" % (fps, frame_count)) |
|
|
|
|
|
if not os.path.exists(FLAGS.output_dir): |
|
|
os.makedirs(FLAGS.output_dir) |
|
|
out_path = os.path.join(FLAGS.output_dir, video_name) |
|
|
fourcc = cv2.VideoWriter_fourcc(* 'mp4v') |
|
|
writer = cv2.VideoWriter(out_path, fourcc, fps, (width, height)) |
|
|
index = 0 |
|
|
store_res = [] |
|
|
keypoint_smoothing = KeypointSmoothing( |
|
|
width, height, filter_type=FLAGS.filter_type, beta=0.05) |
|
|
|
|
|
while (1): |
|
|
ret, frame = capture.read() |
|
|
if not ret: |
|
|
break |
|
|
index += 1 |
|
|
print('detect frame: %d' % (index)) |
|
|
|
|
|
frame2 = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) |
|
|
|
|
|
results = detector.predict_image([frame2], visual=False) |
|
|
results = detector.filter_box(results, FLAGS.det_threshold) |
|
|
if results['boxes_num'] == 0: |
|
|
writer.write(frame) |
|
|
continue |
|
|
|
|
|
keypoint_res = predict_with_given_det( |
|
|
frame2, results, topdown_keypoint_detector, keypoint_batch_size, |
|
|
FLAGS.run_benchmark) |
|
|
|
|
|
if FLAGS.smooth and len(keypoint_res['keypoint'][0]) == 1: |
|
|
current_keypoints = np.array(keypoint_res['keypoint'][0][0]) |
|
|
smooth_keypoints = keypoint_smoothing.smooth_process( |
|
|
current_keypoints) |
|
|
|
|
|
keypoint_res['keypoint'][0][0] = smooth_keypoints.tolist() |
|
|
|
|
|
im = visualize_pose( |
|
|
frame, |
|
|
keypoint_res, |
|
|
visual_thresh=FLAGS.keypoint_threshold, |
|
|
returnimg=True) |
|
|
|
|
|
if save_res: |
|
|
store_res.append([ |
|
|
index, keypoint_res['bbox'], |
|
|
[keypoint_res['keypoint'][0], keypoint_res['keypoint'][1]] |
|
|
]) |
|
|
|
|
|
writer.write(im) |
|
|
if camera_id != -1: |
|
|
cv2.imshow('Mask Detection', im) |
|
|
if cv2.waitKey(1) & 0xFF == ord('q'): |
|
|
break |
|
|
writer.release() |
|
|
print('output_video saved to: {}'.format(out_path)) |
|
|
if save_res: |
|
|
""" |
|
|
1) store_res: a list of frame_data |
|
|
2) frame_data: [frameid, rects, [keypoints, scores]] |
|
|
3) rects: list of rect [xmin, ymin, xmax, ymax] |
|
|
4) keypoints: 17(joint numbers)*[x, y, conf], total 51 data in list |
|
|
5) scores: mean of all joint conf |
|
|
""" |
|
|
with open("det_keypoint_unite_video_results.json", 'w') as wf: |
|
|
json.dump(store_res, wf, indent=4) |
|
|
|
|
|
|
|
|
class KeypointSmoothing(object): |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, |
|
|
width, |
|
|
height, |
|
|
filter_type, |
|
|
alpha=0.5, |
|
|
fc_d=0.1, |
|
|
fc_min=0.1, |
|
|
beta=0.1, |
|
|
thres_mult=0.3): |
|
|
super(KeypointSmoothing, self).__init__() |
|
|
self.image_width = width |
|
|
self.image_height = height |
|
|
self.threshold = np.array([ |
|
|
0.005, 0.005, 0.005, 0.005, 0.005, 0.01, 0.01, 0.01, 0.01, 0.01, |
|
|
0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 |
|
|
]) * thres_mult |
|
|
self.filter_type = filter_type |
|
|
self.alpha = alpha |
|
|
self.dx_prev_hat = None |
|
|
self.x_prev_hat = None |
|
|
self.fc_d = fc_d |
|
|
self.fc_min = fc_min |
|
|
self.beta = beta |
|
|
|
|
|
if self.filter_type == 'OneEuro': |
|
|
self.smooth_func = self.one_euro_filter |
|
|
elif self.filter_type == 'EMA': |
|
|
self.smooth_func = self.ema_filter |
|
|
else: |
|
|
raise ValueError('filter type must be one_euro or ema') |
|
|
|
|
|
def smooth_process(self, current_keypoints): |
|
|
if self.x_prev_hat is None: |
|
|
self.x_prev_hat = current_keypoints[:, :2] |
|
|
self.dx_prev_hat = np.zeros(current_keypoints[:, :2].shape) |
|
|
return current_keypoints |
|
|
else: |
|
|
result = current_keypoints |
|
|
num_keypoints = len(current_keypoints) |
|
|
for i in range(num_keypoints): |
|
|
result[i, :2] = self.smooth(current_keypoints[i, :2], |
|
|
self.threshold[i], i) |
|
|
return result |
|
|
|
|
|
def smooth(self, current_keypoint, threshold, index): |
|
|
distance = np.sqrt( |
|
|
np.square((current_keypoint[0] - self.x_prev_hat[index][0]) / |
|
|
self.image_width) + np.square((current_keypoint[ |
|
|
1] - self.x_prev_hat[index][1]) / self.image_height)) |
|
|
if distance < threshold: |
|
|
result = self.x_prev_hat[index] |
|
|
else: |
|
|
result = self.smooth_func(current_keypoint, self.x_prev_hat[index], |
|
|
index) |
|
|
|
|
|
return result |
|
|
|
|
|
def one_euro_filter(self, x_cur, x_pre, index): |
|
|
te = 1 |
|
|
self.alpha = self.smoothing_factor(te, self.fc_d) |
|
|
dx_cur = (x_cur - x_pre) / te |
|
|
dx_cur_hat = self.exponential_smoothing(dx_cur, self.dx_prev_hat[index]) |
|
|
|
|
|
fc = self.fc_min + self.beta * np.abs(dx_cur_hat) |
|
|
self.alpha = self.smoothing_factor(te, fc) |
|
|
x_cur_hat = self.exponential_smoothing(x_cur, x_pre) |
|
|
self.dx_prev_hat[index] = dx_cur_hat |
|
|
self.x_prev_hat[index] = x_cur_hat |
|
|
return x_cur_hat |
|
|
|
|
|
def ema_filter(self, x_cur, x_pre, index): |
|
|
x_cur_hat = self.exponential_smoothing(x_cur, x_pre) |
|
|
self.x_prev_hat[index] = x_cur_hat |
|
|
return x_cur_hat |
|
|
|
|
|
def smoothing_factor(self, te, fc): |
|
|
r = 2 * math.pi * fc * te |
|
|
return r / (r + 1) |
|
|
|
|
|
def exponential_smoothing(self, x_cur, x_pre, index=0): |
|
|
return self.alpha * x_cur + (1 - self.alpha) * x_pre |
|
|
|
|
|
|
|
|
def main(): |
|
|
deploy_file = os.path.join(FLAGS.det_model_dir, 'infer_cfg.yml') |
|
|
with open(deploy_file) as f: |
|
|
yml_conf = yaml.safe_load(f) |
|
|
arch = yml_conf['arch'] |
|
|
detector_func = 'Detector' |
|
|
if arch == 'PicoDet': |
|
|
detector_func = 'DetectorPicoDet' |
|
|
|
|
|
detector = eval(detector_func)(FLAGS.det_model_dir, |
|
|
device=FLAGS.device, |
|
|
run_mode=FLAGS.run_mode, |
|
|
trt_min_shape=FLAGS.trt_min_shape, |
|
|
trt_max_shape=FLAGS.trt_max_shape, |
|
|
trt_opt_shape=FLAGS.trt_opt_shape, |
|
|
trt_calib_mode=FLAGS.trt_calib_mode, |
|
|
cpu_threads=FLAGS.cpu_threads, |
|
|
enable_mkldnn=FLAGS.enable_mkldnn, |
|
|
threshold=FLAGS.det_threshold) |
|
|
|
|
|
topdown_keypoint_detector = KeyPointDetector( |
|
|
FLAGS.keypoint_model_dir, |
|
|
device=FLAGS.device, |
|
|
run_mode=FLAGS.run_mode, |
|
|
batch_size=FLAGS.keypoint_batch_size, |
|
|
trt_min_shape=FLAGS.trt_min_shape, |
|
|
trt_max_shape=FLAGS.trt_max_shape, |
|
|
trt_opt_shape=FLAGS.trt_opt_shape, |
|
|
trt_calib_mode=FLAGS.trt_calib_mode, |
|
|
cpu_threads=FLAGS.cpu_threads, |
|
|
enable_mkldnn=FLAGS.enable_mkldnn, |
|
|
use_dark=FLAGS.use_dark) |
|
|
keypoint_arch = topdown_keypoint_detector.pred_config.arch |
|
|
assert KEYPOINT_SUPPORT_MODELS[ |
|
|
keypoint_arch] == 'keypoint_topdown', 'Detection-Keypoint unite inference only supports topdown models.' |
|
|
|
|
|
|
|
|
if FLAGS.video_file is not None or FLAGS.camera_id != -1: |
|
|
topdown_unite_predict_video(detector, topdown_keypoint_detector, |
|
|
FLAGS.camera_id, FLAGS.keypoint_batch_size, |
|
|
FLAGS.save_res) |
|
|
else: |
|
|
|
|
|
img_list = get_test_images(FLAGS.image_dir, FLAGS.image_file) |
|
|
topdown_unite_predict(detector, topdown_keypoint_detector, img_list, |
|
|
FLAGS.keypoint_batch_size, FLAGS.save_res) |
|
|
if not FLAGS.run_benchmark: |
|
|
detector.det_times.info(average=True) |
|
|
topdown_keypoint_detector.det_times.info(average=True) |
|
|
else: |
|
|
mode = FLAGS.run_mode |
|
|
det_model_dir = FLAGS.det_model_dir |
|
|
det_model_info = { |
|
|
'model_name': det_model_dir.strip('/').split('/')[-1], |
|
|
'precision': mode.split('_')[-1] |
|
|
} |
|
|
bench_log(detector, img_list, det_model_info, name='Det') |
|
|
keypoint_model_dir = FLAGS.keypoint_model_dir |
|
|
keypoint_model_info = { |
|
|
'model_name': keypoint_model_dir.strip('/').split('/')[-1], |
|
|
'precision': mode.split('_')[-1] |
|
|
} |
|
|
bench_log(topdown_keypoint_detector, img_list, keypoint_model_info, |
|
|
FLAGS.keypoint_batch_size, 'KeyPoint') |
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
paddle.enable_static() |
|
|
parser = argsparser() |
|
|
FLAGS = parser.parse_args() |
|
|
print_arguments(FLAGS) |
|
|
FLAGS.device = FLAGS.device.upper() |
|
|
assert FLAGS.device in ['CPU', 'GPU', 'XPU' |
|
|
], "device should be CPU, GPU or XPU" |
|
|
|
|
|
main() |
|
|
|