具备人脸识别功能的多目标在线实时行为检测(yolov5+deepsort+slowfast) |
您所在的位置:网站首页 › yolov5视频检测种类会变 › 具备人脸识别功能的多目标在线实时行为检测(yolov5+deepsort+slowfast) |
我正在参加「掘金·启航计划」 前言这里先声明一下本项目是基于github.com/wufan-tb/yo… 做的一个二次开发,也就是进行一个项目改造,同时针对原项目进行优化。 在原项目中,采用单线程流线操作,导致无法进行真正的实时的多目标在线检测。只能通过已有的视频文件进行检测。同时在运算过程中,计算资源消耗较大,在进行真正的在线推理时将导致卡顿。为此,为了能够更好地是完成任务。本文博主,在花费一天的时间仔细阅读其源码后,进行了新一轮的定制修改。 支持了在线视频检测,也就是支持: cam = cv.VideoCapture(0) 复制代码同时,这里我将前天做好的人脸检测模块一起放置在了这里: GitHub: github.com/Huterox/Rea… Gitee: gitee.com/Huterox/Rea… 里面包含了完整的权重文件,无需进行下载新的权重文件。 为了方便管理和统一,我们这边单独将配置文件给提取出来了。主要是项目当中的这两个文件:
人脸识别的模块非常简单,首先的话,首先就是我们的配置路径,例如,我们存入人脸信息的文件地址,还有一些字体文件啥的。
之后是我们多目标的一个行为检测模块。 """ 目标检测配置 """ import os class DECTION_CONFIG(): #test imgs folder or video or camera input_date = r"C:\Users\31395\Desktop\peoplePose\temp\yolo_slowfast\video\test_person.mp4" #folder to save result imgs, can not use input folder,视频保存路径 output = "output/video/" #inference size (pixels) yolo_imsize = 640 #object confidence threshold yolo_conf = 0.4 #IOU threshold for NMS yolo_iou = 0.4 #cuda device, i.e. 0 or 0,1,2,3 or cpu yolo_device = "cuda" #默认已经设置好了是cooc数据集 yolo_classes = None yolo_weight = "" #10 ~ 30 should be fine, the bigger, the faster solowfast_process_batch_size = 25 # set 0.8 or 1 or 1.2 solowfast_video_clip_length = 1.2 #usually set 25 or 30 solowfast_frames_per_second = 25 data_mean = [0.45, 0.45, 0.45] data_std = [0.225, 0.225, 0.225] deepsort_ckpt = "alg/poseRec/deep_sort/deep_sort/deep/checkpoint/ckpt.t7" deepsort_pb = "alg/poseRec/selfutils/temp.pbtxt" streamTempBaseChannel = "/alg/poseRec/data/tempChannel" # 设置实时处理的FPS realTimeFps = 20 # 最大队列长度 max_queue_size = 512 # 每2秒左右存储一次视频,用于实时视频检测 tempStream = 2 复制代码首先的话,由于我是在刚刚提到的那个项目的基础上进行自己整合开发的,所以的话,这里保留了他们原先的项目配置,新增了自己的一些配置,首先是关于yolo的一些配置,然后是slowfast的一些配置,那么deepsort的配置的话,在deep sort 那个文件夹下面,这个的话我们不需要进行改动。 这里主要说一下我们新增的配置。(有中文注释部分)。 因为我们这边是做了一个实时在线检测的,但是呢,由于这个原项目,一开始就是做视频读取进行识别的,同时,slowfast ,deepsort都是一个需要时间序列的算法,也就是说需要将一组图像输入到网络然后进行预测的算法,并且处理的速度非常慢,因此为了放置摄像头画面被吞了,我们这边就只能去开多线程去维护一个实时的状态。 因为如果不开多线程的话,会导致什么问题呢,就是时间从1~10,假设在第5秒的时候要进行处理,那么处理的时间是4秒,等你处理完了已经到了第10秒了(第九秒末)中间4秒发生的事情就没了。所以如果做实时,那么处理的效率就必须上去,这个堆设备去,但是在设备能力不行的情况下,我们能够做的就是减少画面的缺失,也就是做一个异步操作。那么这里我选择了python的多线程来实现,为什么不是多进程呢,多进程的确可以加快进度,因为GIL的存在。但是考虑到,我们期望是尽可能减少资源消耗的情况下,去不遗漏画面,所以的话,这里我们就只是用线程去做。一核有难总比八核有难要好一点。 人脸识别模块🆗,那么我们接下来先看一下我们的人脸识别模块,这个的话其实先前是介绍了的。不过后面我们又做了点改动。那就是支持中文了,因为opencv是不支持中文的。然后的话,我们的模块如下: 首先的话还是我们的人脸采集模块,在collection当中我们提供了一个方法: cam = cv.VideoCapture(0) Collection().collection_cramer(cam) cam.release() cv.destroyAllWindows() print("采集完毕,程序退出!!") 复制代码这个方法支持直接从摄像头或者视频当中进行采集。当然我们同样也有一个直接从图片当中进行采集的方法 之后采集完毕之后的话,在这个目录下面(可以在配置中设置)
之后的话,我们要做的就是把这些人脸进行一个特征识别,然后呢,将这些特征进行保存。 """ 负责读取采集到的人脸图像,然后去构建人脸对应的信息 """ import cv2 as cv import os import numpy as np import csv from tqdm import tqdm import shutil from client.server.configFace import FACE_FILE,FACE_CONFIG class BuildFace(): def write2csv(self,data, mode): """ 更新csv文件当中的数据(这里面存储的是我们人脸的特征) :param data: :param mode: :return: """ with open(FACE_FILE.csv_base_path, mode, newline='') as wf: csv_writer = csv.writer(wf) csv_writer.writerow(data) def get_features_from_csv(self): features_in_csv = [] with open(FACE_FILE.csv_base_path, 'r') as rf: csv_reader = csv.reader(rf) for row in csv_reader: for i in range(0, 128): row[i] = float(row[i]) features_in_csv.append(row) return features_in_csv def save_select_in_csv(self,data): """ 选择性更新人脸数据 :param data: :return: """ features_in_csv = self.get_features_from_csv() with open(FACE_FILE.csv_base_path, 'w', newline='') as wf: csv_writer = csv.writer(wf) for index, i in enumerate(FACE_CONFIG.get("face_needTo_update")): features_in_csv[i] = data[index] csv_writer.writerow(features_in_csv[0]) with open(FACE_FILE.csv_base_path, 'a+', newline='') as af: csv_writer = csv.writer(af) for j in range(1, len(features_in_csv)): csv_writer.writerow(features_in_csv[j]) print("csv文件更新完成!!") def get_128_features(self,person_index): """ :param person_index: person_index代表第几个人脸数据文件夹 :return: """ num = 0 features = [] imgs_folder = FACE_FILE.imgs_folder_path[person_index] points_faceImage_path = FACE_FILE.points_faceData_path + imgs_folder imgs_path = FACE_FILE.faceData_path + imgs_folder + '/' list_imgs = os.listdir(imgs_path) imgs_num = len(list_imgs) if os.path.exists(FACE_FILE.points_faceData_path + imgs_folder): shutil.rmtree(points_faceImage_path) os.makedirs(points_faceImage_path) print("人脸点图文件夹建立成功!!") with tqdm(total=imgs_num) as pbar: pbar.set_description(str(imgs_folder)) for j in range(imgs_num): image = cv.imread(os.path.join(imgs_path, list_imgs[j])) faces = FACE_CONFIG.get("detector")(image, 1) if len(faces) != 0: for z, face in enumerate(faces): shape = FACE_CONFIG.get("predictor")(image, face) w, h = (face.right() - face.left()), (face.bottom() - face.top()) left, right, top, bottom = face.left() - w // 4, face.right() + w // 4, face.top() - h // 2, face.bottom() + h // 4 im = image cv.rectangle(im, (left, top), (right, bottom), (0, 0, 255)) cv.imwrite(points_faceImage_path + '/{}.png'.format(j), im) if (FACE_CONFIG.get("get_points_faceData_flag") == True): for p in range(0, 68): cv.circle(image, (shape.part(p).x, shape.part(p).y), 2, (0,0,255)) cv.imwrite(points_faceImage_path + '/{}.png'.format(j), image) the_features = list(FACE_CONFIG.get("recognition_model").compute_face_descriptor(image, shape)) # 获取128维特征向量 features.append(the_features) num += 1 pbar.update(1) np_f = np.array(features) res = np.median(np_f, axis=0) return res def building_form_config(self): if (FACE_CONFIG.get("import_all_features_flag") == True): self.building_all() else: peoples = FACE_CONFIG.get("face_needTo_update") self.building_select(peoples) def building_all(self): res = self.get_128_features(person_index=0) self.write2csv(res, 'w') for i in range(1, FACE_CONFIG.get("num_of_person_in_lib")): res = self.get_128_features(person_index=i) self.write2csv(res, 'a+') def building_select(self,peoples): """ 更新某几个人脸,传入对应的下标编号,例如:[0,2,4] :param peoples: :return: """ select_res = [] for i in peoples: res = self.get_128_features(person_index=i) select_res.append(res) self.save_select_in_csv(select_res) 复制代码这里同样也是提供了多个方法,局部更新和全局更新都有。 那么同样的,我们将人脸的信息保存在这里:
之后就是我们做人脸识别的做法。 人脸识别的过程其实和我们的人脸采集过程非常相似,不同的是,当新的人脸过来之后,我们计算他的特征向量与我们已有的特征向量进行一个比对。然后得到相似度最高的那个。 在这里我主要说明两个比较重要的方法, 第一个就是这个: def detect_from_cam(self,camera): """ 这里的话,和我们采集是一样的,就是传入这个camera对象就好了 :return: """ while camera.isOpened() and not self.quit_flag: val, self.image = camera.read() if val == False: continue key = cv.waitKey(1) res = self.face_detecting() # 0.038s if res is not None: face, self.all_face_location = res for i in range(self.face_num): [left, right, top, bottom] = self.all_face_location[i] self.middle_point = [(left + right) / 2, (top + bottom) / 2] self.face_img = self.image[top:bottom, left:right] cv.rectangle(self.image, (left, top), (right, bottom), (0, 0, 255)) shape = FACE_CONFIG.get("predictor")(self.image, face[i]) # 0.002s if self.face_num_change_flag == True or self.check_times |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |