# Client主进程
# 读取摄像头数据并显示

import MultiFunc_V2 as Func
import cv2
import threading
import numpy as np
import time
import queue

rtsp_ulr = 0  #"rtsp://192.168.1.206:554"
# rtsp_ulr = "rtsp://admin：123456@192.168.1.123/video1"

# 自定义无缓存读视频类
class NetCameraCapture:
    """Customized VideoCapture, always read latest frame """

    def __init__(self, camera_id):
        # "camera_id" is a int type id or string name
        self.cap = cv2.VideoCapture(camera_id)
        self.q = queue.Queue(maxsize=3)
        self.stop_threads = False  # to gracefully close sub-thread
        th = threading.Thread(target=self._reader)
        th.daemon = True  # 设置工作线程为后台运行
        th.start()

    # 实时读帧，只保存最后一帧
    def _reader(self):
        while not self.stop_threads:
            if self.cap.isOpened():  # 判断是否已经打开
                ret, frame = self.cap.read()
                if not ret:
                    break
            if not self.q.empty():
                try:
                    self.q.get_nowait()
                except queue.Empty:
                    pass
            self.q.put(frame)


    def read(self):
        return True, self.q.get()

    def get(self, id):
        return self.cap.get(id)

    def release(self):
        self.stop_threads = True
        self.cap.release()


class ClientThread(threading.Thread):

    def __init__(self):
        self._running = True  # 定义线程状态变量
        super().__init__()

    def terminate(self):
        self._running = False

    def run(self):
        while self._running:
            if GlobalVar.event1.isSet():
                GlobalVar.faces, temp_name = Func.function(GlobalVar.frame)
                # 如果识别结果为空，且少于15张图片（约0.5s），则不更新name
                if len(temp_name) < 2 and GlobalVar.i < 15:   # 识别结果为空
                    GlobalVar.i = GlobalVar.i + 1
                else:
                    GlobalVar.name = temp_name
                    GlobalVar.i = 0
            time.sleep(0.02)


class GlobalVar:
    event1 = threading.Event()  # 用于主进程读取摄像头图像时，不会同时取用图像

    frame = []
    faces = np.array([])
    t = ClientThread()  # 图片处理的子线程
    sk = Func.ClientNetworkThread()   # 与服务器通信的子线程
    width = 0  # 图片宽度
    height = 0  # 图片高度

    name = ""  # 识别结果
    i = 0


def init():
    GlobalVar.event1.clear
    # 开启线程
    GlobalVar.t.start()
    GlobalVar.sk.start()


def draw_frame():
    font = cv2.FONT_HERSHEY_COMPLEX
    cv2.putText(GlobalVar.frame, "Press 'q': Quit", (20, GlobalVar.height - 30), font, 0.8, (84, 255, 159), 1,
                    cv2.LINE_AA)
    # 显示人脸识别结果
    cv2.putText(GlobalVar.frame, GlobalVar.name, (20, GlobalVar.height - 80), font, 0.8, (84, 255, 159), 1, cv2.LINE_AA)

    if len(GlobalVar.faces) != 0:
        cv2.putText(GlobalVar.frame, "Faces: " + str(len(GlobalVar.faces)), (20, 50), font, 1, (0, 0, 255), 1,
                    cv2.LINE_AA)
        for kk, d in enumerate(GlobalVar.faces):
            # 绘制矩形框
            # cv2.rectangle(GlobalVar.frame, tuple([d.left(), d.top()]), tuple([d.right(), d.bottom()]),
            cv2.rectangle(GlobalVar.frame, (d[0], d[1]), (d[2], d[3]), (0, 255, 255), 2)
        # 显示人脸识别结果
        cv2.putText(GlobalVar.frame, GlobalVar.name, (d[0], d[1] - 10), font, 0.8, (0, 255, 255), 1, cv2.LINE_AA)
    else:
        cv2.putText(GlobalVar.frame, "Faces: " + str(0), (20, 50), font, 1, (0, 0, 255), 1, cv2.LINE_AA)


def demo():
    # 初始化
    init()

    # 创建 cv2 摄像头对象
    # 获取摄像机来捕获实时流  参数0表示本台设备的序号为0的采集设备（camera）
    # capture = cv2.VideoCapture(0)

    # 使用网络摄像头
    capture = NetCameraCapture(rtsp_ulr)

    # 获取捕获图像分辨率
    GlobalVar.width, GlobalVar.height = int(capture.get(3)), int(capture.get(4))
    print("图像尺寸:", GlobalVar.width, "x", GlobalVar.height, "px")

    i = 0
    s1 = time.time()

    while i < 1000:
        i = i + 1

        GlobalVar.event1.clear()  # 置为false，不允许子进程读取图片

        ret, GlobalVar.frame = capture.read()
        # if frame is read correctly ret is True
        if not ret:
            print("Can't receive frame (stream end?). Exiting ...")
            exit()

        GlobalVar.event1.set()  # 置为true，允许子进程读取图片

        # 在图片上绘制文字和框
        draw_frame()

        # 窗口显示 show with opencv
        cv2.imshow("Face Recognition", GlobalVar.frame)

        if cv2.waitKey(1) == ord('q') or cv2.waitKey(1) == ord('Q'):
            # 关闭摄像头 释放窗口
            capture.release()
            cv2.destroyAllWindows()
            GlobalVar.t.terminate()
            break

    s2 = time.time()
    print(i, " 张图片共用时：", (s2 - s1))
    GlobalVar.t.terminate()
    GlobalVar.sk.terminate()


if __name__ == "__main__":
    demo()
