Python+Docker实现人脸识别远程监控系统

说明

本项目实现远程人脸识别监控功能,包括服务端程序和客户端程序。服务端使用Python OpenCV库实现人脸识别功能,将添加上识别结果的视频流通过TCP发送给客户端,且实现了Docker容器对上述功能的封装;客户端程序通过IP+端口接入服务端,接收视频流,实时查看人脸识别结果。客户端可与服务端断开接入后重新连接,不影响服务端功能。

项目文件

  • tcpsend.py(服务端程序)
  • tcpreceive.py(客户端程序)
  • requirements.txt(项目依赖)
  • train.py(人脸识别模型训练程序)
  • trainer.yml(人脸识别模型)
  • haarcascade_frontalface_alt2.xml(分类器)
  • Dockerfile(构建Docker镜像所需文件)

项目源码

tcpsend.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import socket
import cv2
import sys
import os
import numpy as npip
###
address = ('ip', 5555) # 服务端地址和端口
ser = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ser.bind(address)
ser.listen(5)
# 阻塞式
print('waiting。。。')
conn, addr = ser.accept()
print('建立连接...')
print('连接对象:', addr)
cap = cv2.VideoCapture(0)
# cap = cv2.VideoCapture(0)
frames_num=cap.get(7)
print('视频总帧数:',frames_num)
print('发送目标...')
count = 0
###
###
#加载训练数据集文件
recogizer = cv2.face.LBPHFaceRecognizer_create()
recogizer.read('./trainer.yml')
names = []
warningtime = 0
#准备识别的图片
def face_detect_demo(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度
face_detector = cv2.CascadeClassifier('./haarcascade_frontalface_alt2.xml')
face = face_detector.detectMultiScale(gray, 1.1, 5, cv2.CASCADE_SCALE_IMAGE, (100, 100), (300, 300))
# face=face_detector.detectMultiScale(gray)
for x, y, w, h in face:
cv2.rectangle(img, (x, y), (x+w, y+h), color=(255, 144, 30), thickness=2) # blue,green,red
# cv2.circle(img,center=(x+w//2,y+h//2),radius=w//2,color=(0,255,0),thickness=1)
# 人脸识别
ids, confidence = recogizer.predict(gray[y:y + h, x:x + w])
# print('标签id:',ids,'置信评分:', confidence)
if confidence > 80:
cv2.putText(img, 'unkonw', (x + 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (255, 144, 30), 2)
else:
cv2.putText(img, 'dong', (x + 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (255, 144, 30), 2)
# cv2.imshow('result', img)
# print('bug:',ids)
return img
def name():
path = './dataset/'
# names = []
imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
for imagePath in imagePaths:
name = str(os.path.split(imagePath)[1].split('.', 2)[1])
names.append(name)
###
#name()
while True:
flag, frame = cap.read()
frame = face_detect_demo(frame)
# frame = cv2.resize(frame, (1280, 720))
# cv2.imshow('send', frame)
cv2.waitKey(1)
count += 1
# 数据打包有很多方式,也可以用json打包
img_encode = cv2.imencode('.jpg', frame)[1]
data_encode = np.array(img_encode)
str_encode = data_encode.tostring()
try:
conn.sendall(str_encode)
except :
conn, addr = ser.accept()

tcpreceive.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import socket
import sys
import cv2
import numpy as np
import time
address = ('ip', 5555) # 服务端地址和端口
cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
cli.connect(address) # 尝试连接服务端
except Exception:ip
print('[!] Server not found or not open')
sys.exit()
frame_count = 1
while True:
time1 = time.time() if frame_count == 1 else time1
trigger = 'ok'
cli.sendall(trigger.encode())
data = cli.recv(1024*1024*20)
image = np.frombuffer(data, np.uint8)
image = cv2.imdecode(image, cv2.IMREAD_COLOR)
try:
cv2.imshow('video', image)
except:
continue
cv2.waitKey(1)
end_time = time.time()
time2 = time.time()
print(image.shape[:2], int(frame_count / (time2 - time1)))
frame_count += 1
cli.close()

train.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import os
import cv2 as cv
from PIL import Image
import numpy as np

def getImageAndLabels(path):
facesSamples = [] # 储存人脸数据
ids = [] # 尺寸姓名数据
imagePaths = [os.path.join(path, f) for f in os.listdir(path)] # 储存图片信息
face_detector = cv.CascadeClassifier('D:/Python/python3.9.8/Lib/site-packages/cv2/data/haarcascade_frontalface_alt2.xml') # 加载分类器
for imagePath in imagePaths: # 遍历列表中的图片
PIL_img = Image.open(imagePath).convert('L') # 打开图片,灰度化(PIL有九种模式:1,L,P,RGB,RGBA,CMYK,YCbCr,YCbCr,I,F)
img_numpy = np.array(PIL_img, 'uint8') # 将图片转换为数组,以黑白深浅
faces = face_detector.detectMultiScale(img_numpy) # 获取图片人脸特征
id = int(os.path.split(imagePath)[1].split('.')[0]) # 获取每张图片的id和姓名
for x, y, w, h in faces:
ids.append(id)
facesSamples.append(img_numpy[y:y+h, x:x+w])
print('id:', id)
print('fs:', facesSamples)
return facesSamples, ids

if __name__ == '__main__':
path = './dataset/' # 图片路径
faces, ids = getImageAndLabels(path) # 获取图像数组和id标签数据和姓名
recognizer = cv.face.LBPHFaceRecognizer_create() # 加载识别器
recognizer.train(faces, np.array(ids)) # 训练
recognizer.write('./trainer/trainer.yml') # 保存文件

requirements.txt

1
2
3
4
numpy==1.21.5
Pillow==9.1.0
opencv-contrib-python==4.5.5.64
opencv-python==4.5.5.64

Dockerfile

1
2
3
4
5
6
7
8
FROM python:3.7-slim
ADD ./facerecognitionserver /code
WORKDIR /code
RUN apt-get update
RUN apt-get install -y libgl1-mesa-glx
RUN apt-get install -y libglib2.0-dev
RUN pip install -r requirements.txt
CMD ["python","/code/tcpsend.py"]