Files

237 lines
7.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import sys
import cv2
import time
import numpy as np
import threading
import socket
import struct, os, select
class GlobVar:
server_ip = '192.168.1.17'
server_port = 8000
name_namelist = '' # 人脸匹配结果
event2 = threading.Event() # 用于告知socket进程数据已准备好可以发送给服务器了
event3 = threading.Event() # 用于告知socket进程允许或不允许修改name_namelist
flag = 0
st_time = 0 # 记录定时1秒的起始时间
nd_time = 0 # 记录定时1秒的结束时间
frame_new = []
frame_old = []
sys_path = sys.path[0].replace("\\", "/")
# 加载人脸检测模型
tensorflowWeightFile = sys_path + "/opencv_face_detector.pbtxt"
tensorflowModelFile = sys_path + "/opencv_face_detector_uint8.pb"
conf_threshold = 0.7
# net = cv2.dnn.readNetFromCaffe(caffeWeightFile, caffeModel=None) # 未找到caffee的模型文件
net = cv2.dnn.readNetFromTensorflow(tensorflowModelFile, tensorflowWeightFile)
faces = np.array([])
class ClientNetworkThread(threading.Thread):
def __init__(self):
self._running = True # 定义线程状态变量
super().__init__()
def terminate(self):
self._running = False
def run(self):
while self._running:
if GlobVar.event2.isSet():
sock_client_image()
time.sleep(0.02)
def sock_client_image():
# 1、建立socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((GlobVar.server_ip, GlobVar.server_port))
s.setblocking(0) # 设置为非阻塞模式
except socket.error as msg:
print("%s L102" % msg)
print("未连接到服务器 L103")
try:
s.close()
except socket.error as msg:
print(msg)
return
# 2、发送图片数据如果发送成功则等待接收如果不成功则不进行接收
flag = socket_send(s)
# 3、接收识别结果
if flag: socket_recv(s)
# 4、关闭socket
try:
s.close()
except socket.error as msg:
print(msg)
def action():
if len(GlobVar.faces) == 1: # 检测到有且仅有一张人脸并且保持静止1秒
if GlobVar.flag == 0:
GlobVar.flag = 1
GlobVar.frame_old = GlobVar.frame_new
GlobVar.st_time = time.time() # 开始计时
else:
if moving_detect(GlobVar.frame_old, GlobVar.frame_new): # 画面静止
GlobVar.nd_time = time.time() # 计算时间是否达到1秒
# print("已保持不动 {0} 秒".format(end - start))
if GlobVar.nd_time - GlobVar.st_time >= 1 and GlobVar.flag == 1: # 计时1秒时间到
GlobVar.flag = 2
print('存在单张人脸L55')
else: # 画面有变动
GlobVar.flag = 0
else: # 无人脸或有多张人脸
GlobVar.flag = 0
if len(GlobVar.faces) > 1:
print("Error: More than one person")
else:
print("No person")
def function(image):
GlobVar.faces = [] # 清空
GlobVar.name_namelist = "" # 清空
GlobVar.event2.clear()
GlobVar.event3.set()
GlobVar.frame_new = image
(h, w) = image.shape[:2]
blob = cv2.dnn.blobFromImage(cv2.resize(image, (300, 300)), 1.0,
(300, 300), (104.0, 177.0, 123.0))
GlobVar.net.setInput(blob)
detections = GlobVar.net.forward()
for i in range(0, detections.shape[2]):
# extract the confidence (i.e., probability) associated with the
# prediction
confidence = detections[0, 0, i, 2]
# filter out weak detections by ensuring the `confidence` is
# greater than the minimum confidence
if confidence < GlobVar.conf_threshold:
continue
# compute the (x, y)-coordinates of the bounding box for the
# object
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype("int")
GlobVar.faces.append(i)
GlobVar.faces[i] = [startX, startY, endX, endY]
# cv2.rectangle(frame, (startX, startY), (endX, endY), (0, 255, 255), 1)
# 再根据人脸个数做出判断
action()
# 若存在单张人脸且静止时间达到1秒
if GlobVar.flag == 2:
print("返回人脸位置坐标并且发送图片到server")
GlobVar.flag = 0
saveimage(h, w)
GlobVar.event2.set() # 告知子进程数据已准备好
GlobVar.event3.clear()
name = GlobVar.name_namelist
GlobVar.event3.set()
# 返回faces和name
return GlobVar.faces, name
def moving_detect(img1, img2): # 比较两幅画面,判断是否静止
grey_diff = cv2.absdiff(img1, img2) # 计算两幅图的像素差
change = np.average(grey_diff)
if change > 10:
return False # 画面有明显变动返回False
else:
return True # 画面无明显变动返回True
def saveimage(height, width):
# 提取人脸区域并保存成图片
for (x, y, endx, endy) in GlobVar.faces:
(w, h) = (endx - x, endy - y)
left = int(x - 0.25 * w)
if left < 0: left = 0
right = int(x + 1.25 * w)
if right > width: right = width
top = int(y - 0.25 * h)
if top < 0: top = 0
bottom = int(y + 1.25 * h)
if bottom > height: bottom = height
cropped_image = GlobVar.frame_new[top:bottom, left:right]
cv2.imwrite("singleface.jpg", cropped_image)
def socket_send(s):
file_path = 'singleface.jpg' # 输入当前目录下的图片名
# pack按照图片格式、图片名字、图片大小
fsend = struct.pack(b'128sq', # 图片打包的格式为128sq
bytes(os.path.basename(file_path), encoding='utf-8'), # 返回图片文件名,编码字节化
os.stat(file_path).st_size) # 返回读取文件的相关属性然后得到其中st_size的数据(记录文件大小)
try:
s.send(fsend)
except socket.error as msg:
print(msg)
return 0 # 数据发送失败返回0
fp = open(file_path, 'rb') # 打开要传输的图片
while True:
data = fp.read(1024) # 读入图片数据,data是图片的数据字节流(由于图片字节很多这里一次只读取1024个字节)
if not data: # 如果读到字节的数据没有了
print('{0} send over...'.format(len(data)))
break
try:
s.send(data) # 以二进制格式发送图片数据(每次发1024个字节)
except socket.error as msg:
print(msg)
return 0 # 数据发送出错返回0
print("数据已发送,开始接收...")
GlobVar.event2.clear()
return 1 # 数据发送完毕返回1
def socket_recv(s):
st1 = time.time()
response = ""
while True:
infds, outfds, errfds = select.select([s, ], [], [])
if len(infds) > 0: # 有数据返回不管是否成功接收均跳出while循环
try:
buf = s.recv(1024).decode('utf-8')
print("received: " + str(buf))
response += str(buf)
break
except socket.error as msg:
print(msg)
break
except BlockingIOError:
break
else:
print("no data comes back")
st2 = time.time()
if st2 - st1 > 0.5:
break # 等待超时
if GlobVar.event3.isSet():
GlobVar.name_namelist = response