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