具备人脸识别功能的多目标在线实时行为检测(yolov5+deepsort+slowfast)

您所在的位置:网站首页 yolov5视频检测种类会变 具备人脸识别功能的多目标在线实时行为检测(yolov5+deepsort+slowfast)

具备人脸识别功能的多目标在线实时行为检测(yolov5+deepsort+slowfast)

2023-05-13 00:08| 来源: 网络整理| 查看: 265

我正在参加「掘金·启航计划」

前言

这里先声明一下本项目是基于github.com/wufan-tb/yo… 做的一个二次开发,也就是进行一个项目改造,同时针对原项目进行优化。

在原项目中,采用单线程流线操作,导致无法进行真正的实时的多目标在线检测。只能通过已有的视频文件进行检测。同时在运算过程中,计算资源消耗较大,在进行真正的在线推理时将导致卡顿。为此,为了能够更好地是完成任务。本文博主,在花费一天的时间仔细阅读其源码后,进行了新一轮的定制修改。

支持了在线视频检测,也就是支持:

cam = cv.VideoCapture(0) 复制代码

同时,这里我将前天做好的人脸检测模块一起放置在了这里: GitHub: github.com/Huterox/Rea…

Gitee: gitee.com/Huterox/Rea… 里面包含了完整的权重文件,无需进行下载新的权重文件。

在这里插入图片描述

配置项

为了方便管理和统一,我们这边单独将配置文件给提取出来了。主要是项目当中的这两个文件: 在这里插入图片描述 分别用于管理人脸识别以及多目标的行为检测。 这里需要声明的是,如果需要进行二次开发的话,那么这里请将你的实现模块,放置在与config相同的目录下面,进行开发,原因的话,很简单,python目录的问题。

人脸识别配置 import dlib import os """ 人脸识别配置 """ class FACE_FILE(object): shape_predictor_path='alg/faceRec/data/data_dlib/shape_predictor_68_face_landmarks.dat' recognition_model_path='alg/faceRec/data/data_dlib/dlib_face_recognition_resnet_model_v1.dat' csv_base_path='alg/faceRec/data/csv/features.csv' faceData_path='alg/faceRec/data/faceData/' points_faceData_path='alg/faceRec/data/faceData_points/' faceName_path='alg/faceRec/data/faceName.txt' imgs_folder_path=os.listdir("alg/faceRec/data/faceData/") font_path = "alg/fonts/MSYH.ttc" FACE_CONFIG={ "max_collection_image": 50, "get_points_faceData_flag": True, "import_all_features_flag":True, "face_needTo_update":[x for x in range(1, 2)], #选择更新脸部的编号,从0开始 "num_of_person_in_lib":len(FACE_FILE.imgs_folder_path), "recognition_threshold":0.43, "predictor": dlib.shape_predictor(FACE_FILE.shape_predictor_path), "recognition_model": dlib.face_recognition_model_v1(FACE_FILE.recognition_model_path), "detector":dlib.get_frontal_face_detector(), } 复制代码

人脸识别的模块非常简单,首先的话,首先就是我们的配置路径,例如,我们存入人脸信息的文件地址,还有一些字体文件啥的。 在这里插入图片描述

多目标行为检测配置

之后是我们多目标的一个行为检测模块。

""" 目标检测配置 """ 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