collect face by dlib
This commit is contained in:
178
Class/collect_data/get_faces_from_camera.py
Normal file
178
Class/collect_data/get_faces_from_camera.py
Normal file
@@ -0,0 +1,178 @@
|
||||
# 进行人脸录入 / face register
|
||||
# 录入多张人脸 / support multi-faces
|
||||
|
||||
import dlib # 人脸处理的库 Dlib
|
||||
import numpy as np # 数据处理的库 Numpy
|
||||
import cv2 # 图像处理的库 OpenCV
|
||||
import os # 读写文件
|
||||
import shutil # 读写文件
|
||||
import time
|
||||
|
||||
# Dlib 正向人脸检测器
|
||||
detector = dlib.get_frontal_face_detector()
|
||||
|
||||
|
||||
class Face_Register:
|
||||
def __init__(self):
|
||||
self.path_photos_from_camera = "data/data_faces_from_camera/"
|
||||
self.font = cv2.FONT_ITALIC
|
||||
|
||||
self.existing_faces_cnt = 0 # 已录入的人脸计数器
|
||||
self.ss_cnt = 0 # 录入 personX 人脸时图片计数器
|
||||
self.faces_cnt = 0 # 录入人脸计数器
|
||||
|
||||
# 之后用来控制是否保存图像的 flag
|
||||
self.save_flag = 1
|
||||
# 之后用来检查是否先按 'n' 再按 's',即先新建文件夹再保存
|
||||
self.press_n_flag = 0
|
||||
|
||||
self.frame_time = 0
|
||||
self.frame_start_time = 0
|
||||
self.fps = 0
|
||||
|
||||
# 新建保存人脸图像文件
|
||||
def pre_work_mkdir(self):
|
||||
if os.path.isdir(self.path_photos_from_camera):
|
||||
pass
|
||||
else:
|
||||
os.mkdir(self.path_photos_from_camera)
|
||||
|
||||
# 删除之前存的人脸数据文件夹
|
||||
def pre_work_del_old_face_folders(self):
|
||||
# 删除之前存的人脸数据文件夹
|
||||
folders_rd = os.listdir(self.path_photos_from_camera)
|
||||
for i in range(len(folders_rd)):
|
||||
shutil.rmtree(self.path_photos_from_camera+folders_rd[i])
|
||||
if os.path.isfile("data/features_all.csv"):
|
||||
os.remove("data/features_all.csv")
|
||||
|
||||
# 如果有之前录入的人脸, 在之前 person_x 的序号按照 person_x+1 开始录入
|
||||
def check_existing_faces_cnt(self):
|
||||
if os.listdir("data/data_faces_from_camera/"):
|
||||
# 获取已录入的最后一个人脸序号
|
||||
person_list = os.listdir("data/data_faces_from_camera/")
|
||||
person_num_list = []
|
||||
for person in person_list:
|
||||
person_num_list.append(int(person.split('_')[-1]))
|
||||
self.existing_faces_cnt = max(person_num_list)
|
||||
|
||||
# 如果第一次存储或者没有之前录入的人脸, 按照 person_1 开始录入
|
||||
# Start from person_1
|
||||
else:
|
||||
self.existing_faces_cnt = 0
|
||||
|
||||
# 获取处理之后 stream 的帧数
|
||||
def update_fps(self):
|
||||
now = time.time()
|
||||
self.frame_time = now - self.frame_start_time
|
||||
self.fps = 1.0 / self.frame_time
|
||||
self.frame_start_time = now
|
||||
|
||||
# 生成的 cv2 window 上面添加说明文字
|
||||
def draw_note(self, img_rd):
|
||||
# 添加说明
|
||||
cv2.putText(img_rd, "Face Register", (20, 40), self.font, 1, (255, 255, 255), 1, cv2.LINE_AA)
|
||||
cv2.putText(img_rd, "FPS: " + str(self.fps.__round__(2)), (20, 100), self.font, 0.8, (0, 255, 0), 1,
|
||||
cv2.LINE_AA)
|
||||
cv2.putText(img_rd, "Faces: " + str(self.faces_cnt), (20, 140), self.font, 0.8, (0, 255, 0), 1, cv2.LINE_AA)
|
||||
cv2.putText(img_rd, "N: Create face folder", (20, 350), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
|
||||
cv2.putText(img_rd, "S: Save current face", (20, 400), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
|
||||
cv2.putText(img_rd, "Q: Quit", (20, 450), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
|
||||
|
||||
# 获取人脸
|
||||
def process(self, stream):
|
||||
# 1. 新建储存人脸图像文件目录
|
||||
# self.pre_work_mkdir()
|
||||
|
||||
# 2. 删除 "/data/data_faces_from_camera" 中已有人脸图像文件
|
||||
self.pre_work_del_old_face_folders()
|
||||
|
||||
# 3. 检查 "/data/data_faces_from_camera" 中已有人脸文件
|
||||
self.check_existing_faces_cnt()
|
||||
|
||||
while stream.isOpened():
|
||||
flag, img_rd = stream.read() # Get camera video stream
|
||||
kk = cv2.waitKey(1)
|
||||
faces = detector(img_rd, 0) # Use dlib face detector
|
||||
|
||||
# 4. 按下 'n' 新建存储人脸的文件夹
|
||||
if kk == ord('n'):
|
||||
self.existing_faces_cnt += 1
|
||||
current_face_dir = self.path_photos_from_camera + "person_" + str(self.existing_faces_cnt)
|
||||
os.makedirs(current_face_dir)
|
||||
print('\n')
|
||||
print("新建的人脸文件夹 / Create folders: ", current_face_dir)
|
||||
|
||||
self.ss_cnt = 0 # 将人脸计数器清零
|
||||
self.press_n_flag = 1 # 已经按下 'n'
|
||||
|
||||
# 5. 检测到人脸
|
||||
if len(faces) != 0:
|
||||
# 矩形框
|
||||
for k, d in enumerate(faces):
|
||||
# 计算矩形框大小
|
||||
height = (d.bottom() - d.top())
|
||||
width = (d.right() - d.left())
|
||||
hh = int(height/2)
|
||||
ww = int(width/2)
|
||||
|
||||
# 6. 判断人脸矩形框是否超出 480x640
|
||||
if (d.right()+ww) > 640 or (d.bottom()+hh > 480) or (d.left()-ww < 0) or (d.top()-hh < 0):
|
||||
cv2.putText(img_rd, "OUT OF RANGE", (20, 300), self.font, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
|
||||
color_rectangle = (0, 0, 255)
|
||||
save_flag = 0
|
||||
if kk == ord('s'):
|
||||
print("请调整位置 / Please adjust your position")
|
||||
else:
|
||||
color_rectangle = (255, 255, 255)
|
||||
save_flag = 1
|
||||
|
||||
cv2.rectangle(img_rd,
|
||||
tuple([d.left() - ww, d.top() - hh]),
|
||||
tuple([d.right() + ww, d.bottom() + hh]),
|
||||
color_rectangle, 2)
|
||||
|
||||
# 7. 根据人脸大小生成空的图像
|
||||
img_blank = np.zeros((int(height*2), width*2, 3), np.uint8)
|
||||
|
||||
if save_flag:
|
||||
# 8. 按下 's' 保存摄像头中的人脸到本地
|
||||
if kk == ord('s'):
|
||||
# 检查有没有先按'n'新建文件夹
|
||||
if self.press_n_flag:
|
||||
self.ss_cnt += 1
|
||||
for ii in range(height*2):
|
||||
for jj in range(width*2):
|
||||
img_blank[ii][jj] = img_rd[d.top()-hh + ii][d.left()-ww + jj]
|
||||
cv2.imwrite(current_face_dir + "/img_face_" + str(self.ss_cnt) + ".jpg", img_blank)
|
||||
print("写入本地 / Save into:", str(current_face_dir) + "/img_face_" + str(self.ss_cnt) + ".jpg")
|
||||
else:
|
||||
print("请先按 'N' 来建文件夹, 按 'S' / Please press 'N' and press 'S'")
|
||||
self.faces_cnt = len(faces)
|
||||
|
||||
# 9. 生成的窗口添加说明文字
|
||||
self.draw_note(img_rd)
|
||||
|
||||
# 10. 按下 'q' 键退出
|
||||
if kk == ord('q'):
|
||||
break
|
||||
|
||||
self.update_fps()
|
||||
cv2.namedWindow("camera", 1)
|
||||
cv2.imshow("camera", img_rd)
|
||||
|
||||
def run(self):
|
||||
cap = cv2.VideoCapture(0)
|
||||
self.process(cap)
|
||||
|
||||
cap.release()
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
|
||||
def main():
|
||||
Face_Register_con = Face_Register()
|
||||
Face_Register_con.run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,3 +1,5 @@
|
||||
# 进行摄像头直播推流 / live_broadcast
|
||||
|
||||
import cv2 as cv
|
||||
import time
|
||||
import subprocess as sp
|
||||
@@ -35,6 +37,7 @@ class stream_pusher(object):
|
||||
# 对获取的帧做一些画面处理的方法,返回完成处理的帧。
|
||||
def __frame_handle__(self, raw_frame, text, shape1, shape2):
|
||||
# 帧用cv2进行一些处理,比如写上文本,画矩形等
|
||||
cv.putText(raw_frame, text.split('.')[0], (20, 40), cv.FONT_ITALIC, 0.8, (0, 0, 255), 1, cv.LINE_AA)
|
||||
return (raw_frame)
|
||||
|
||||
# 向服务器推送
|
||||
@@ -85,14 +88,13 @@ if __name__ == '__main__':
|
||||
|
||||
rtmpUrl = "rtmp://39.97.124.237:1984/wodelive" # 用vcl等直播软件播放时,也用这个地址
|
||||
raw_q = multiprocessing.Queue() # 定义一个向推流对象传入帧及其他信息的队列
|
||||
time_q=multiprocessing.Queue()
|
||||
|
||||
my_pusher = stream_pusher(rtmp_url=rtmpUrl, raw_frame_q=raw_q) # 实例化一个对象
|
||||
my_pusher.run() # 让这个对象在后台推送视频流
|
||||
|
||||
while True:
|
||||
_, raw_frame = cap.read()
|
||||
info = (raw_frame, '2', '3', '4') # 把需要送入队列的内容进行封装
|
||||
info = (raw_frame, str(datetime.datetime.now()), '3', '4') # 把需要送入队列的内容进行封装
|
||||
# if not raw_q.full(): # 如果队列没满
|
||||
raw_q.put(info) # 送入队列
|
||||
cv.waitKey(1)
|
||||
BIN
Data/data_faces_from_camera/tmp.zip
Normal file
BIN
Data/data_faces_from_camera/tmp.zip
Normal file
Binary file not shown.
Reference in New Issue
Block a user