(19) AI virtual photography, AI virtual travel, AI virtual camera, real-time keying, and camera background removal

(19) AI virtual photography, AI virtual travel, AI virtual camera, real-time keying, and camera background removal

The code in this article implements keying processing of camera videos and fuses portraits with background images, allowing you to take exquisite photos of tourist scenery without leaving home. It saves you the trouble of PSing photos one by one;

You can automatically take pictures with gestures, eliminating the need to press buttons;

Due to the need for real-time processing, it must be run on a computer with a GPU and only supports NVIDIA graphics cards.

The synthesized camera can also be mapped to a virtual camera (AI_Camera), which can be used by various network conferencing software;

You can also automatically upload the photos you take to Baidu for others to view and download;

Insert image description here

The executable software is packaged and uploaded to the network disk:
link: https://pan.baidu.com/s/1Zlm81gs0yB4djGa8qhGXtg?pwd=8888

This article is closely related to the previous blog posts, so please read the previous ones beforehand. If you are interested in this article, you can add us for in-depth discussion: herbert156

Without further ado, let’s talk about the code:
the interface part:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'AI_Shoot_UI.ui'
#
# Created by: PyQt5 UI code generator 5.15.2
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_v_cam(object):
    def setupUi(self, v_cam):
        v_cam.setObjectName("v_cam")
        v_cam.resize(883, 528)
        self.horizontalLayoutWidget = QtWidgets.QWidget(v_cam)
        self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 861, 241))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.horizontalLayoutWidget.setFont(font)
        self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.my_label1 = QtWidgets.QLabel(self.horizontalLayoutWidget)
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.my_label1.setFont(font)
        self.my_label1.setObjectName("my_label1")
        self.horizontalLayout.addWidget(self.my_label1)
        self.my_label2 = QtWidgets.QLabel(self.horizontalLayoutWidget)
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.my_label2.setFont(font)
        self.my_label2.setObjectName("my_label2")
        self.horizontalLayout.addWidget(self.my_label2)
        self.option_win = QtWidgets.QGroupBox(v_cam)
        self.option_win.setGeometry(QtCore.QRect(10, 270, 861, 111))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.option_win.setFont(font)
        self.option_win.setObjectName("option_win")
        self.outButton = QtWidgets.QPushButton(self.option_win)
        self.outButton.setGeometry(QtCore.QRect(10, 20, 61, 23))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.outButton.setFont(font)
        self.outButton.setObjectName("outButton")
        self.bkfileButton = QtWidgets.QPushButton(self.option_win)
        self.bkfileButton.setGeometry(QtCore.QRect(10, 50, 61, 23))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.bkfileButton.setFont(font)
        self.bkfileButton.setObjectName("bkfileButton")
        self.txt2 = QtWidgets.QLabel(self.option_win)
        self.txt2.setGeometry(QtCore.QRect(80, 23, 251, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.txt2.setFont(font)
        self.txt2.setObjectName("txt2")
        self.txt3 = QtWidgets.QLabel(self.option_win)
        self.txt3.setGeometry(QtCore.QRect(80, 53, 251, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.txt3.setFont(font)
        self.txt3.setObjectName("txt3")
        self.checkBox3 = QtWidgets.QCheckBox(self.option_win)
        self.checkBox3.setGeometry(QtCore.QRect(11, 82, 68, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.checkBox3.setFont(font)
        self.checkBox3.setObjectName("checkBox3")
        self.txt4 = QtWidgets.QLabel(self.option_win)
        self.txt4.setGeometry(QtCore.QRect(81, 82, 51, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.txt4.setFont(font)
        self.txt4.setObjectName("txt4")
        self.red = QtWidgets.QLabel(self.option_win)
        self.red.setGeometry(QtCore.QRect(141, 82, 16, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.red.setFont(font)
        self.red.setObjectName("red")
        self.blue = QtWidgets.QLabel(self.option_win)
        self.blue.setGeometry(QtCore.QRect(243, 82, 16, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.blue.setFont(font)
        self.blue.setObjectName("blue")
        self.green = QtWidgets.QLabel(self.option_win)
        self.green.setGeometry(QtCore.QRect(191, 82, 16, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.green.setFont(font)
        self.green.setObjectName("green")
        self.red_e = QtWidgets.QLineEdit(self.option_win)
        self.red_e.setGeometry(QtCore.QRect(158, 80, 31, 20))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.red_e.setFont(font)
        self.red_e.setObjectName("red_e")
        self.blue_e = QtWidgets.QLineEdit(self.option_win)
        self.blue_e.setGeometry(QtCore.QRect(260, 80, 31, 20))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.blue_e.setFont(font)
        self.blue_e.setObjectName("blue_e")
        self.green_e = QtWidgets.QLineEdit(self.option_win)
        self.green_e.setGeometry(QtCore.QRect(208, 80, 31, 20))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.green_e.setFont(font)
        self.green_e.setObjectName("green_e")
        self.camera_lbl = QtWidgets.QLabel(self.option_win)
        self.camera_lbl.setGeometry(QtCore.QRect(420, 20, 81, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.camera_lbl.setFont(font)
        self.camera_lbl.setObjectName("camera_lbl")
        self.camera_comboBox = QtWidgets.QComboBox(self.option_win)
        self.camera_comboBox.setGeometry(QtCore.QRect(490, 17, 141, 22))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.camera_comboBox.setFont(font)
        self.camera_comboBox.setObjectName("camera_comboBox")
        self.camera_lbl_2 = QtWidgets.QLabel(self.option_win)
        self.camera_lbl_2.setGeometry(QtCore.QRect(420, 50, 81, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.camera_lbl_2.setFont(font)
        self.camera_lbl_2.setObjectName("camera_lbl_2")
        self.camera_w_h = QtWidgets.QComboBox(self.option_win)
        self.camera_w_h.setGeometry(QtCore.QRect(490, 47, 141, 22))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.camera_w_h.setFont(font)
        self.camera_w_h.setObjectName("camera_w_h")
        self.camera_lbl_3 = QtWidgets.QLabel(self.option_win)
        self.camera_lbl_3.setGeometry(QtCore.QRect(420, 80, 71, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.camera_lbl_3.setFont(font)
        self.camera_lbl_3.setObjectName("camera_lbl_3")
        self.open_fold = QtWidgets.QPushButton(self.option_win)
        self.open_fold.setGeometry(QtCore.QRect(340, 17, 61, 23))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.open_fold.setFont(font)
        self.open_fold.setObjectName("open_fold")
        self.chk_backfile = QtWidgets.QPushButton(self.option_win)
        self.chk_backfile.setGeometry(QtCore.QRect(340, 49, 61, 23))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.chk_backfile.setFont(font)
        self.chk_backfile.setObjectName("chk_backfile")
        self.real_camera_w_h = QtWidgets.QLabel(self.option_win)
        self.real_camera_w_h.setGeometry(QtCore.QRect(488, 79, 71, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.real_camera_w_h.setFont(font)
        self.real_camera_w_h.setObjectName("real_camera_w_h")
        self.camera_lbl_4 = QtWidgets.QLabel(self.option_win)
        self.camera_lbl_4.setGeometry(QtCore.QRect(667, 78, 91, 20))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.camera_lbl_4.setFont(font)
        self.camera_lbl_4.setObjectName("camera_lbl_4")
        self.frame_rate = QtWidgets.QLabel(self.option_win)
        self.frame_rate.setGeometry(QtCore.QRect(760, 78, 71, 20))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.frame_rate.setFont(font)
        self.frame_rate.setObjectName("frame_rate")
        self.v_cam_chk = QtWidgets.QCheckBox(self.option_win)
        self.v_cam_chk.setEnabled(True)
        self.v_cam_chk.setGeometry(QtCore.QRect(653, 20, 191, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.v_cam_chk.setFont(font)
        self.v_cam_chk.setObjectName("v_cam_chk")
        self.camera_lbl_5 = QtWidgets.QLabel(self.option_win)
        self.camera_lbl_5.setGeometry(QtCore.QRect(667, 50, 91, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.camera_lbl_5.setFont(font)
        self.camera_lbl_5.setObjectName("camera_lbl_5")
        self.cam_frame_rate = QtWidgets.QLabel(self.option_win)
        self.cam_frame_rate.setGeometry(QtCore.QRect(760, 47, 61, 20))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.cam_frame_rate.setFont(font)
        self.cam_frame_rate.setObjectName("cam_frame_rate")
        self.groupBox_2 = QtWidgets.QGroupBox(v_cam)
        self.groupBox_2.setGeometry(QtCore.QRect(10, 465, 301, 51))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.groupBox_2.setFont(font)
        self.groupBox_2.setObjectName("groupBox_2")
        self.checkBox1 = QtWidgets.QCheckBox(self.groupBox_2)
        self.checkBox1.setGeometry(QtCore.QRect(16, 22, 81, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.checkBox1.setFont(font)
        self.checkBox1.setObjectName("checkBox1")
        self.checkBox_fullwin = QtWidgets.QCheckBox(self.groupBox_2)
        self.checkBox_fullwin.setGeometry(QtCore.QRect(173, 22, 81, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.checkBox_fullwin.setFont(font)
        self.checkBox_fullwin.setObjectName("checkBox_fullwin")
        self.fullwinButton = QtWidgets.QPushButton(self.groupBox_2)
        self.fullwinButton.setGeometry(QtCore.QRect(250, 20, 31, 21))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.fullwinButton.setFont(font)
        self.fullwinButton.setObjectName("fullwinButton")
        self.fullwinButton0 = QtWidgets.QPushButton(self.groupBox_2)
        self.fullwinButton0.setGeometry(QtCore.QRect(93, 20, 31, 21))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.fullwinButton0.setFont(font)
        self.fullwinButton0.setObjectName("fullwinButton0")
        self.shootButton = QtWidgets.QPushButton(v_cam)
        self.shootButton.setGeometry(QtCore.QRect(380, 471, 51, 41))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.shootButton.setFont(font)
        self.shootButton.setObjectName("shootButton")
        self.startButton = QtWidgets.QPushButton(v_cam)
        self.startButton.setGeometry(QtCore.QRect(470, 480, 71, 23))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.startButton.setFont(font)
        self.startButton.setObjectName("startButton")
        self.stopButton = QtWidgets.QPushButton(v_cam)
        self.stopButton.setGeometry(QtCore.QRect(570, 480, 71, 23))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.stopButton.setFont(font)
        self.stopButton.setObjectName("stopButton")
        self.helpButton = QtWidgets.QPushButton(v_cam)
        self.helpButton.setGeometry(QtCore.QRect(680, 480, 81, 23))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.helpButton.setFont(font)
        self.helpButton.setObjectName("helpButton")
        self.quitButton = QtWidgets.QPushButton(v_cam)
        self.quitButton.setGeometry(QtCore.QRect(800, 480, 71, 23))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.quitButton.setFont(font)
        self.quitButton.setObjectName("quitButton")
        self.groupBox_3 = QtWidgets.QGroupBox(v_cam)
        self.groupBox_3.setGeometry(QtCore.QRect(10, 400, 861, 51))
        font = QtGui.QFont()
        font.setFamily("Agency FB")
        font.setPointSize(9)
        self.groupBox_3.setFont(font)
        self.groupBox_3.setObjectName("groupBox_3")
        self.spinBox = QtWidgets.QSpinBox(self.groupBox_3)
        self.spinBox.setGeometry(QtCore.QRect(240, 20, 31, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.spinBox.setFont(font)
        self.spinBox.setMinimum(1)
        self.spinBox.setMaximum(15)
        self.spinBox.setProperty("value", 3)
        self.spinBox.setObjectName("spinBox")
        self.delay_comboBox = QtWidgets.QComboBox(self.groupBox_3)
        self.delay_comboBox.setGeometry(QtCore.QRect(90, 18, 31, 22))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.delay_comboBox.setFont(font)
        self.delay_comboBox.setObjectName("delay_comboBox")
        self.delay_lbl = QtWidgets.QLabel(self.groupBox_3)
        self.delay_lbl.setGeometry(QtCore.QRect(10, 20, 81, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.delay_lbl.setFont(font)
        self.delay_lbl.setObjectName("delay_lbl")
        self.hand_shoot = QtWidgets.QCheckBox(self.groupBox_3)
        self.hand_shoot.setEnabled(True)
        self.hand_shoot.setGeometry(QtCore.QRect(780, 20, 68, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.hand_shoot.setFont(font)
        self.hand_shoot.setObjectName("hand_shoot")
        self.auto_chg_bk = QtWidgets.QCheckBox(self.groupBox_3)
        self.auto_chg_bk.setEnabled(True)
        self.auto_chg_bk.setGeometry(QtCore.QRect(139, 20, 101, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.auto_chg_bk.setFont(font)
        self.auto_chg_bk.setObjectName("auto_chg_bk")
        self.txt2_3 = QtWidgets.QLabel(self.groupBox_3)
        self.txt2_3.setGeometry(QtCore.QRect(288, 20, 91, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.txt2_3.setFont(font)
        self.txt2_3.setObjectName("txt2_3")
        self.bk_file_dir = QtWidgets.QLabel(self.groupBox_3)
        self.bk_file_dir.setGeometry(QtCore.QRect(370, 20, 391, 16))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(9)
        self.bk_file_dir.setFont(font)
        self.bk_file_dir.setText("")
        self.bk_file_dir.setObjectName("bk_file_dir")

        self.retranslateUi(v_cam)
        QtCore.QMetaObject.connectSlotsByName(v_cam)

    def retranslateUi(self, v_cam):
        _translate = QtCore.QCoreApplication.translate
        v_cam.setWindowTitle(_translate("v_cam", "AI虚拟拍照系统"))
        self.my_label1.setText(_translate("v_cam", "本区域,显示的是原始视频缩略图..."))
        self.my_label2.setText(_translate("v_cam", "本区域,显示的是替换后的缩略图..."))
        self.option_win.setTitle(_translate("v_cam", "操作设置"))
        self.outButton.setText(_translate("v_cam", "拍照存盘"))
        self.bkfileButton.setText(_translate("v_cam", "背景文件"))
        self.txt2.setText(_translate("v_cam", "拍照存盘"))
        self.txt3.setText(_translate("v_cam", "背景文件"))
        self.checkBox3.setText(_translate("v_cam", "纯色背景"))
        self.txt4.setText(_translate("v_cam", "纯色背景"))
        self.red.setText(_translate("v_cam", "红"))
        self.blue.setText(_translate("v_cam", "蓝"))
        self.green.setText(_translate("v_cam", "绿"))
        self.camera_lbl.setText(_translate("v_cam", "硬件摄像头:"))
        self.camera_lbl_2.setText(_translate("v_cam", "分辨率设置:"))
        self.camera_lbl_3.setText(_translate("v_cam", "实际分辨率:"))
        self.open_fold.setText(_translate("v_cam", "浏览照片"))
        self.chk_backfile.setText(_translate("v_cam", "查看背景"))
        self.real_camera_w_h.setText(_translate("v_cam", "实际分辨率"))
        self.camera_lbl_4.setText(_translate("v_cam", "AI算法处理帧率:"))
        self.frame_rate.setText(_translate("v_cam", "0.0 FPS"))
        self.v_cam_chk.setText(_translate("v_cam", "启动虚拟摄像头:AI_Camera"))
        self.camera_lbl_5.setText(_translate("v_cam", "摄像头读取帧率:"))
        self.cam_frame_rate.setText(_translate("v_cam", "0.0 FPS"))
        self.groupBox_2.setTitle(_translate("v_cam", "显示设置"))
        self.checkBox1.setText(_translate("v_cam", "实时展示->"))
        self.checkBox_fullwin.setText(_translate("v_cam", "拍后显示->"))
        self.fullwinButton.setText(_translate("v_cam", "全屏"))
        self.fullwinButton0.setText(_translate("v_cam", "全屏"))
        self.shootButton.setText(_translate("v_cam", "拍照"))
        self.startButton.setText(_translate("v_cam", "运行"))
        self.stopButton.setText(_translate("v_cam", "停止"))
        self.helpButton.setText(_translate("v_cam", "帮助"))
        self.quitButton.setText(_translate("v_cam", "退出"))
        self.groupBox_3.setTitle(_translate("v_cam", "拍照设置"))
        self.delay_lbl.setText(_translate("v_cam", "拍照延时(秒):"))
        self.hand_shoot.setText(_translate("v_cam", "手势拍照"))
        self.auto_chg_bk.setText(_translate("v_cam", "自动换背景(秒)"))
        self.txt2_3.setText(_translate("v_cam", "背景文件目录:"))

Main running code:

#视频背景替换工具V1.0
import keyboard
import numpy as np
import os, datetime, sys, time, threading, GPUtil
os.environ['OPENCV_VIDEOIO_PRIORITY_MSMF'] = '0'    #加快打开摄像头的速度
import cv2

import pyvirtualcam  # https://github.com/letmaik/pyvirtualcam
import http.client, win32api, win32con
import configparser as configparser
from PIL import Image,ImageDraw,ImageFont
from bypy import ByPy
from mediapipe import solutions
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtWidgets import QWidget,QMessageBox,QFileDialog,QApplication
from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSlot, pyqtSignal
from PyQt5.QtGui import QPixmap,QIntValidator
from PyCameraList.camera_device import list_video_devices

DEBUG_FLAG = False   #调试用
# DEBUG_FLAG = True   #调试用
from AI_Shoot_UI import Ui_v_cam

def is_contains_chinese():  #运行目录不能包含中文
    strs = os.getcwd()
    for _char in strs:
        if '\u4e00' <= _char <= '\u9fa5':
            win32api.MessageBox(0, f"软件安装目录【{strs}】不能包含中文,\n请移动到其他目录再运行......", '运行错误提示', win32con.MB_OK)
            sys.exit()

def get_web_time(host): #获取网络时间,并设置系统时间
    try:
        conn=http.client.HTTPConnection(host,timeout=20)
        conn.request("GET", "/")
        r=conn.getresponse()
    except:
        win32api.MessageBox(0, f"网络连接超时...", '运行错误提示', win32con.MB_OK); sys.exit()
    ts=  r.getheader('date') #获取http头date部分
    ltime= time.strptime(ts[5:25], "%d %b %Y %H:%M:%S")   #将GMT时间转换成北京时间
    ttime=time.localtime(time.mktime(ltime)+8*60*60)
    date = "%u%02u%02u" % (ttime.tm_year, ttime.tm_mon, ttime.tm_mday)
    return date

#检测显卡是否是Nvidia,并查看型号是否支持
try:
    gpus = GPUtil.getGPUs(); gpu_list = []; gpu_i = 0; gpu_available = 0
    for g in gpus: gpu_list.append([g.name, g.memoryTotal])
    GPU_nums = len(gpu_list)  #显卡数量
    print("【显卡数量】检测出的Nvidia GPU数量:%d个:" %GPU_nums)
    for GPU_Info in gpu_list:
        gpu_i += 1; GPU_name = GPU_Info[0]  #显卡名称
        GPU_memsize = GPU_Info[1]/1024  # 显卡总的显存大小
        print("【显卡:%d】型号:%s | 显存:%dG"%(gpu_i,GPU_name,GPU_memsize))
        if ('GTX' in GPU_name or 'RTX' in GPU_name): gpu_available += 1
    if gpu_available > 0: print("【可用数量】AI处理的可用GPU:%d个:" %gpu_i)
    else:
        win32api.MessageBox(0, "您的GPU是本软件不支持的Nvidia显卡,无法运行本软件!", '运行错误提示',
                            win32con.MB_OK); sys.exit()
except:
    win32api.MessageBox(0, "您的GPU是本软件不支持的显卡,无法运行本软件!", '运行错误提示',
                        win32con.MB_OK); sys.exit()

#读取配置文件AI_Shoot.ini
cfg = configparser.ConfigParser()
if os.path.exists('AI_Shoot.ini'):
    cfg.read('AI_Shoot.ini',encoding="utf-8")

    apikey = cfg.get('BAIDU', 'apikey')
    secretkey = cfg.get('BAIDU', 'secretkey')

    cam_res = cfg.get('AI_SHOOT', 'cam_res')

    autorun = cfg.getboolean('AI_SHOOT', 'autorun')
    change_bg_file = cfg.getboolean('AI_SHOOT', 'change_bg_file')
    hand_shoot_flag = cfg.getboolean('AI_SHOOT', 'hand_shoot_flag')
    upload_baidu = cfg.getboolean('AI_SHOOT', 'upload_baidu')
    full_screen= cfg.getboolean('AI_SHOOT', 'full_screen')
    hide_window= cfg.getboolean('AI_SHOOT', 'hide_window')
    show_scan_code= cfg.getboolean('AI_SHOOT', 'show_scan_code')

    camera_no = cfg.getint('AI_SHOOT', 'camera_no')
    delay_sec = cfg.getint('AI_SHOOT', 'delay_sec')
    chg_bk_counter = cfg.getint('AI_SHOOT', 'chg_bk_counter')
else:
    cam_res='1920x1080'
    camera_no = 0
    delay_sec = 3
    chg_bk_counter = 5
    change_bg_file = False
    hand_shoot_flag = False
    upload_baidu = False
    full_screen = False
    hide_window = False

Win_Open_Full = False
Win_Open_Normal = False
shoot_flag = False
timer_counter = 0

work_path = os.getcwd()+'/kx'; files = []
bg_file=work_path + '/bk.jpg'; out_dir=work_path + '/jpg'
bg_file_list = []; bk_file_no = 0
thread_img = cv2.imread("start_img.jpg")
scan_code_img = Image.open(r'sacn_code.png').resize((200, 200))

run_flag = 0; Box1_flag = False; Box3_flag = False
bk_pix = [8,188,8]; bk_img = np.zeros((1080, 1920, 3), np.uint8)  # Creat a Image
bk_img[:] = bk_pix; filesnums = 1 ; stop_flag = False

cam_lists = list_video_devices()
cam_list = []
cam_fps = 20.0; fr_rate = 10.0
for cams in cam_lists: cam_list.append(cams[1])

my_title = "AI虚拟拍照系统"
pil_img = Image.open("start_img.jpg")
ImageDraw.Draw(pil_img).text((350,200), my_title, (255,255,255),font=ImageFont.truetype("msyh.ttc", 18))
ImageDraw.Draw(pil_img).text((410,330), "正在加载AI模型,请稍后 ......", (255,255,255),font=ImageFont.truetype("msyh.ttc", 16))
img_s = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)

def showpic():  # 以下代码显示软件初始界面
    global ret, frame
    while run_flag == 0:
        cv2.imshow("AI Camera System", img_s)
        cv2.waitKey(100)
    cv2.destroyAllWindows()
t = threading.Thread(target=showpic)
t.start()

if upload_baidu:
    baidu_yun = ByPy()
    try: baidu_yun.refreshtoken()
    except: print('刷新百度网盘的授权码,发生错误....')

mpHands = solutions.hands   #手势检测
hands = mpHands.Hands(static_image_mode=False, max_num_hands=2, min_detection_confidence=0.5, min_tracking_confidence=0.5)
mp_pose = solutions.pose   #姿势检测
pose = mp_pose.Pose(static_image_mode=True, smooth_landmarks=True, min_detection_confidence=0.5, min_tracking_confidence=0.5)

# class upload_baidu_disk(QThread):
#     def __init__(self, save_name):
#         super(upload_baidu_disk, self).__init__()
#         self.save_name = save_name
#         print(save_name)
#         try:
#             baidu_yun.upload(self.save_name, remotepath='AI摄影', ondup="newcopy")
#         except:
#             print('图片上传百度网盘,发生错误....')
#     def run(self): pass
def upload_baidu_disk(save_name):
    try: baidu_yun.upload(save_name, remotepath='AI摄影', ondup="newcopy")
    except: print('图片上传百度网盘,发生错误....')

def win_on_off():
    if winshot.isHidden():
        winshot.show()
    else:
        winshot.hide()
    print("Switch the Windows!")
keyboard.add_hotkey('ctrl+alt+enter', win_on_off)

class full_win(QWidget):
    def __init__(self):
        super(full_win, self).__init__()
        palette = QtGui.QPalette()
        #palette1.setColor(palette1.Background, QtGui.QColor(0, 0, 0))
        palette.setBrush(self.backgroundRole(), QtGui.QBrush(QtGui.QPixmap(bg_file)))
        self.setPalette(palette)
        self.setWindowTitle("Full_Windows")
        self.setGeometry(320, 180, 640, 360)

        if full_screen:
            desktop = QApplication.desktop()
            screen_count = desktop.screenCount()
            if screen_count > 1:
                self.setGeometry(desktop.screenGeometry(1)); self.showFullScreen()
            else:
                self.setGeometry(desktop.screenGeometry(0)); self.showFullScreen()

        #self.setWindowFlags(Qt.FramelessWindowHint)

class result_win(QWidget):
    def __init__(self):
        super(result_win, self).__init__()
        palette = QtGui.QPalette()
        palette.setBrush(self.backgroundRole(), QtGui.QBrush(QtGui.QPixmap(bg_file)))
        self.setPalette(palette)
        self.setWindowTitle("Result_Windows")
        self.setGeometry(320, 180, 640, 360)

class camera_thread(QThread):
    # sinout = pyqtSignal(str)
    def __init__(self, winshot):
        super(camera_thread, self).__init__()
        self.main_win = winshot

    def run(self):
        global delay_sec, chg_bk_counter, timer_counter
        global thread_img, stop_flag, cam_fps
        while not stop_flag:
            t0 = time.time()
            try: ret, thread_img = self.main_win.cap.read()
            except Exception as errmsg:
                print(repr(errmsg))
                self.main_win.show_error('读取摄像头(编号:%d), 出现错误(Line204)!' % camera_no)
                stop_flag = True; self.main_win.set_True_Btn(); return

            cam_delay = time.time() - t0
            # print(f'Fps:{1 / cam_delay:0.2f}',end="\r")
            try: cam_fps = 1/cam_delay
            except: pass;   #print('float division by zero')
            delay_sleep = 0.04 - cam_delay
            if delay_sleep <= 0: delay_sleep = 0
            else:
                cam_fps = 1 / delay_sleep
                time.sleep(delay_sleep)

class hand_detect_thread(QThread):
        sinout = pyqtSignal(str)
        def __init__(self, winshot):
            super(hand_detect_thread, self).__init__()
            self.main_win = winshot
        def run(self):
            global delay_sec, chg_bk_counter, timer_counter, thread_img, stop_flag
            while not stop_flag:
                t0 = time.time()
                if self.main_win.hand_shoot.isChecked() and timer_counter <= 0:
                    imgRGB = cv2.cvtColor(cv2.flip(thread_img, 1), cv2.COLOR_BGR2RGB)
                    image_height, image_width, _ = np.shape(imgRGB)

                    pose_results = pose.process(imgRGB)
                    if pose_results.pose_landmarks:
                        p11 = pose_results.pose_landmarks.landmark[11].y
                        p12 = pose_results.pose_landmarks.landmark[12].y
                        p15 = pose_results.pose_landmarks.landmark[15].y
                        p16 = pose_results.pose_landmarks.landmark[16].y

                        if p11 > p15 or p12 > p16:
                            hand_results = hands.process(imgRGB)
                            if hand_results.multi_hand_landmarks:
                                if timer_counter <= 0:
                                    # print("发送信号,启动拍照! ")
                                    self.sinout.emit('START')
                delay_sleep = 1/fr_rate - time.time() + t0
                if delay_sleep <= 0: delay_sleep = 0
                time.sleep(delay_sleep)

class Winshot(QWidget, Ui_v_cam):
    def __init__(self):
        super(Winshot, self).__init__()
        self.setupUi(self)
        global hwnd, run_flag

        palette1 = QtGui.QPalette()
        palette1.setColor(palette1.Background, QtGui.QColor(200, 200, 200))

        try: self.ai_shooting = cv2.imread('AI_Shooting.jpg')
        except: print('没找到文件:AI_Shooting.jpg')

        self.shoot_timer = QTimer(self)  # 拍照定时器
        self.shoot_timer.timeout.connect(self.shoot_timer_fuc)
        self.chg_bk_timer = QTimer(self)  # 换背景定时器
        self.chg_bk_timer.timeout.connect(self.chg_bk_timer_fuc)
        self.result_win_timer = QTimer(self)  # 拍后显示定时器
        self.result_win_timer.timeout.connect(self.result_win_timer_fuc)

        self.createLayout()
        self.stopButton.setEnabled(False)
        self.set_rgb_False()
        self.setPalette(palette1)
        self.setWindowTitle(my_title)
        self.setWindowFlags(Qt.WindowMinimizeButtonHint)
        if not hide_window: self.show()
        run_flag = 1

        if autorun: self.start_run()       #自动运行

    def hand_detect_signal(self):
        global delay_sec, chg_bk_counter
        # delay_sec = 3;
        # chg_bk_counter += 3
        self.shootrun()

    def get_cams_name(self):
        cameras = list_video_devices()
        cams_name = []
        for cams in cameras: cams_name.append(cams[1])
        return cams_name

    def result_win_timer_fuc(self):
        palette = QtGui.QPalette()
        palette.setBrush(self.backgroundRole(),
                         QtGui.QBrush(self.CvMatToQImage(
                         cv2.resize(self.ai_shooting,(my_result_win.width(), my_result_win.height())))))
        my_result_win.setPalette(palette)
        self.result_win_timer.stop()

    def chg_bk_timer_fuc(self):
        global chg_bk_counter, change_bg_file, bk_file_no, bg_file
        chg_bk_counter -= 1
        if chg_bk_counter <= 0:
            bg_file = bg_file_list[bk_file_no]
            bk_file_no += 1
            if bk_file_no >= len(bg_file_list): bk_file_no = 0
            change_bg_file = True
            chg_bk_counter = self.spinBox.value()
    def shoot_timer_fuc(self):
        global timer_counter, shoot_flag
        timer_counter -= 1
        if timer_counter < 0: timer_counter = 0

        try: red_color = int(255 * (delay_sec - timer_counter) / delay_sec)
        except: red_color = 111

        if red_color < 1 or red_color >255: red_color = 111
        self.shootButton.setStyleSheet("background-color:rgb(%d,97,22);font-size:30px;font-weight:bold"%red_color)
        self.shootButton.setText(str(timer_counter))

        if timer_counter <= 0:
            self.shoot_timer.stop()
            shoot_flag = True
            self.shootButton.setStyleSheet("background-color:rgb(207,97,22);font-size:20px;font-weight:bold")
            self.shootButton.setText('拍照')

    def CV2toPIL(self, img):  # cv2转PIL
        return Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGRA2RGBA))
    def PILtoCV2(self, img):  # PIL转cv2
        return cv2.cvtColor(np.array(img), cv2.COLOR_RGBA2BGRA)
    def two_pic_combine_PIL(self, back_img, fore_img): #2个图片合并Image.composite
        back_img = self.CV2toPIL(back_img); fore_img = self.CV2toPIL(fore_img); r,g,b,alpha = fore_img.split()
        return cv2.cvtColor(self.PILtoCV2(Image.composite(fore_img, back_img, alpha)), cv2.COLOR_BGRA2BGR)
    def two_pic_combine_PIL_Paste(self, back_img, fore_img):    #Image.alpha_composite
        back_img = self.CV2toPIL(back_img); fore_img = self.CV2toPIL(fore_img)
        return cv2.cvtColor(self.PILtoCV2(Image.alpha_composite(back_img, fore_img)), cv2.COLOR_BGRA2BGR)

    def CvMatToQImage(self, ptr):  # Converts an opencv MAT format into a QImage
        ptr = cv2.cvtColor(ptr, cv2.COLOR_BGRA2RGBA)  # 颜色格式转换
        QtImg = QtGui.QImage(ptr.data, ptr.shape[1], ptr.shape[0], QtGui.QImage.Format_RGBA8888)
        return QtGui.QPixmap.fromImage(QtImg)

    def show_error(self,str):
        r_button = QMessageBox.question(self, my_title,'\n\n'+str+'\n\n', QMessageBox.Ok)
    def set_False_Btn(self):
        self.outButton.setEnabled(False);    self.shootButton.setEnabled(True)
        # self.bkfileButton.setEnabled(False);
        self.checkBox3.setEnabled(False)
        self.startButton.setEnabled(False); self.stopButton.setEnabled(True)
        self.quitButton.setEnabled(False)
        self.camera_comboBox.setEnabled(False)
        self.camera_w_h.setEnabled(False)

    def set_True_Btn(self):
        self.outButton.setEnabled(True);    self.shootButton.setEnabled(False)
        # self.bkfileButton.setEnabled(True);
        self.checkBox3.setEnabled(True)
        self.startButton.setEnabled(True); self.stopButton.setEnabled(False)
        self.quitButton.setEnabled(True)
        self.camera_comboBox.setEnabled(True)
        self.camera_w_h.setEnabled(True)

    @pyqtSlot()
    def start_run(self):
        global stop_flag, change_bg_file, bg_file, camera_no, shoot_flag
        global back_ground, thread_img, fr_rate, chg_bk_counter

        stop_flag = False;  shoot_flag = False; self.set_False_Btn()
        self.auto_chg_bk_fuc()  #检查自动更换背景

        if not Box3_flag:   #判断是否纯色背景
            try: back_ground = cv2.imdecode(np.fromfile(bg_file, dtype=np.uint8), -1)
            except: self.show_error('\n读取背景文件异常:文件不存在!   \n'); self.set_True_Btn(); return
            if back_ground is None: self.show_error('读取背景文件时,出现错误!\n原因:目录/文件名不能包含中文...... '); return
        else: back_ground = bk_img

        try: self.cap = cv2.VideoCapture(camera_no, cv2.CAP_ANY)  # 读取视频文件
        # try: self.cap = cv2.VideoCapture(camera_no, cv2.CAP_DSHOW)
        except Exception as errmsg:
            print(repr(errmsg)); self.show_error('读取摄像头-477, 出现错误...'); stop_flag = True; self.set_True_Btn(); return

        try:
            camera_w,camera_h = self.camera_w_h.currentText().split('x')
            fourcc = cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')
            self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, int(camera_w))
            self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, int(camera_h))
            self.cap.set(cv2.CAP_PROP_FOURCC, fourcc)
            # self.cap.set(cv2.CAP_PROP_FPS, 30)

            size_x = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))  # 视频流的帧宽度
            size_y = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))  # 视频流的帧高度
            fps = self.cap.get(cv2.CAP_PROP_FPS)  # 帧率
            self.real_camera_w_h.setText(f'{size_x}x{size_y}')
        except Exception as errmsg:
            print(repr(errmsg)); self.show_error('读取摄像头-492, 出现错误...'); stop_flag = True; self.set_True_Btn(); return
        # print(size_x, size_y, fps)
        if size_x == 0 or size_y == 0:
            self.show_error('读取摄像头-496(编号:%d), 出现错误...' % camera_no);
            stop_flag = True; self.set_True_Btn(); return

        img1 = cv2.resize(back_ground, (1920, 1080))

        if size_x / size_y > 1.778: fx = 427 / size_x;  fy = fx  # 计算16:9的比例,以便缩放不变形
        else: fy = 240 / size_y;  fx = fy
        palette2 = QtGui.QPalette()
        palette3 = QtGui.QPalette()

        self.new_thread = hand_detect_thread(self)
        self.new_thread.sinout.connect(self.hand_detect_signal)
        self.new_thread.start()
        self.cam_thread = camera_thread(self)
        self.cam_thread.start()

        with pyvirtualcam.Camera(width=size_x, height=size_y, fps=20, backend='unitycapture') as cam:
            # print(f'Camera Name: {cam.device}')
            while True:
                if stop_flag: my_full_win.hide(); my_result_win.hide(); break
                t0 = time.time()

                if (not Box3_flag) and change_bg_file:
                    try:
                        back_ground = cv2.imdecode(np.fromfile(bg_file, dtype=np.uint8), -1)
                        img1 = cv2.resize(back_ground, (1920, 1080))
                        # print("背景文件改变...")
                        # img1 = back_ground
                    except:
                        self.show_error('\n读取背景文件异常:文件不存在!   \n')
                    if back_ground is None: self.show_error('读取背景文件时,出现错误!\n原因:目录/文件名不能包含中文...'); break
                    change_bg_file = False

                # if self.hand_shoot.isChecked() and timer_counter <= 0:
                #     # self.hand_detect(frame) #检测手掌
                #     self.shoot_timer.start(1000)

                frame = cv2.flip(thread_img, 1)

                h1, w1, _ = thread_img.shape     #扩大左右像素到16:9
                if w1/h1 < 1.7:
                    side_pix = int((h1*16/9-w1)/2)
                    frame = cv2.copyMakeBorder(frame, 0, 0, side_pix, side_pix,
                                               cv2.BORDER_CONSTANT, value=[200,200,200])

                if not DEBUG_FLAG:   #测试用语句
                    img2 = self.koutu(frame)
                else: img2 = frame
                img2 = cv2.resize(img2, (1920, 1080))

                try:
                    img3 = self.two_pic_combine_PIL_Paste(img1, img2)
                    # img3 = self.icanx_water_print(img3)
                 except Exception as errmsg:
                    print(repr(errmsg))
                    self.show_error('读取摄像头-560(编号:%d), 出现错误!' % camera_no)
                    stop_flag = True; self.set_True_Btn(); return

                if self.v_cam_chk.isChecked():
                    cam.send(cv2.cvtColor(img3, cv2.COLOR_BGR2RGB))     #发送到虚拟摄像头
                # cam.sleep_until_next_frame()
                show_img = img3

                if timer_counter > 0:
                    pil_img = self.CV2toPIL(img3)
                    # pos_x = size_x/2-200*1920/size_x
                    ImageDraw.Draw(pil_img).text((450, 870), "摆好姿势," + str(timer_counter)+"秒后拍照",
                                                 (250, 250, 250), font=ImageFont.truetype("msyh.ttc", 150))
                    show_img = self.PILtoCV2(pil_img)

                if Box1_flag:
                    if show_scan_code:  # 写提示文字
                        pil_img = self.CV2toPIL(show_img)
                        # pos_x = size_x/2-200*1920/size_x
                        ImageDraw.Draw(pil_img).text((720, 60), "举手拍照,扫码下载:",
                                                     (250, 250, 250), font=ImageFont.truetype("msyh.ttc", 100))
                        pil_img.paste(scan_code_img, (1680, 40, 1880, 240))  # 显示二维码
                        show_img = self.PILtoCV2(pil_img)
                    palette2.setBrush(self.backgroundRole(),QtGui.QBrush(self.CvMatToQImage(cv2.resize(show_img,
                                      (my_full_win.width(), my_full_win.height())))))
                    my_full_win.setPalette(palette2)

                cv2.waitKey(1)
                if shoot_flag:      #写拍照写盘,存百度网盘
                    save_name = out_dir + '/IMG_' + time.strftime("%y%m%d_%H%M%S", time.localtime())+'.JPG'
                    if not os.path.exists(out_dir): self.show_error('输出文件, 出现错误!\n文件目录可能不存在...')

                    try:
                        # cv2.imwrite(save_name, img3)
                        cv2.imencode('.jpg', img3)[1].tofile(save_name)
                    except: self.show_error('输出文件, 出现错误!\n文件目录可能不存在...')

                    if upload_baidu: threading.Thread(target=upload_baidu_disk, kwargs={
    
    'save_name':save_name}).start()

                    palette2.setColor(palette2.Background, QtGui.QColor(0,0,0))
                    my_full_win.setPalette(palette2)
                    cv2.waitKey(200)
                    if self.checkBox_fullwin.isChecked():
                        palette3.setBrush(self.backgroundRole(), QtGui.QBrush(self.CvMatToQImage(cv2.resize(img3,
                                        (my_result_win.width(), my_result_win.height())))))
                        my_result_win.setPalette(palette3)
                        self.result_win_timer.start(3000)
                    chg_bk_counter = 0
                    shoot_flag = False

                # t1 = time.time()
                self.my_label1.setPixmap(self.CvMatToQImage(cv2.resize(frame, (427, 240))))
                # self.my_label2.setPixmap(self.CvMatToQImage(cv2.resize(show_img, (0, 0), fx=fx, fy=fy)))
                self.my_label2.setPixmap(self.CvMatToQImage(cv2.resize(show_img, (427, 240))))

                # print(f't2:{(time.time() - t0):0.4f}')

                fr_rate = 1/(time.time() - t0)
                self.frame_rate.setText(f'{fr_rate:.1f} FPS')
                self.cam_frame_rate.setText(f'{cam_fps:.1f} FPS')

        self.cap.release()
        self.set_True_Btn()
        self.frame_rate.setText(f'0.0 FPS')
        self.real_camera_w_h.setText('0x0')
        self.my_label1.setPixmap(QPixmap("start_img.jpg"))
        self.my_label2.setPixmap(QPixmap("start_img.jpg"))

    @pyqtSlot()
    def shootrun(self):
        global shoot_flag,timer_counter, delay_sec, chg_bk_counter
        if delay_sec == 0 : shoot_flag = True
        else:
            chg_bk_counter += delay_sec
            self.shootButton.setStyleSheet("background-color:rgb(20,97,22);font-size:30px;font-weight:bold")
            self.shootButton.setText(str(delay_sec))
            timer_counter = delay_sec
            self.shoot_timer.start(1000)

    @pyqtSlot()
    def stoprun(self):
        global stop_flag
        r_button = QMessageBox.question(self, my_title,"\n\n确定要停止运行吗?   \n\n", QMessageBox.Yes | QMessageBox.No)
        if r_button == QMessageBox.Yes: stop_flag = True

    @pyqtSlot()
    def helpWin(self):
        str="\n\n\n1、【选择摄像头】选择电脑连接的物理摄像头编号;\n2、【拍照存盘】拍照后的JPG文件保存目录,文件名:IMG_日期_时间.JPG;\n"+\
        "3、【背景文件】选择后,人物视频的背景都被替换成此背景;\n4、【纯色背景】点选后,所有视频背景替换成纯色的;\n"+ \
        "5、【手势拍照】将手臂举过头顶,AI识别3秒后开始拍照;\n6、【实时显示】点选后,可在大屏幕上全屏显示;\n" + \
        "7、虚拟摄像头名称:AI_Camera,可以在腾讯会议、Zoom会议、OBS等软件中使用;\n\n\n"+ \
        "      本软件著作权归属:XXX        网址:www.xxx-x.com\n\n"
        QMessageBox.question(self, my_title, str, QMessageBox.Ok)

    @pyqtSlot()
    def quitWin(self):
        r_button = QMessageBox.question(self, "my_title",
                                        "\n\n退出将终止本程序......\n\n确认退出吗?\n\n", QMessageBox.Yes | QMessageBox.No)
        if r_button == QMessageBox.Yes:
            hands.close(); pose.close(); sys.exit()

    @pyqtSlot()
    def outButton_fuc(self):
        global out_dir
        out_dir = QFileDialog.getExistingDirectory(self,'选择转换后的输出文件夹', work_path)
        if out_dir == '': self.txt2.setText('请选择背景替换后文件保存目录......')
        else: self.txt2.setText(out_dir)

    # @pyqtSlot()
    def bkfileButton_fuc(self):
        global bg_file, change_bg_file
        bg_file, ok1 = QFileDialog.getOpenFileName(self,"选择背景图片文件",work_path,"*.jpg;;*.png;;*.gif")
        if bg_file == '': self.txt3.setText('请选择背景图片文件......')
        else: self.txt3.setText(bg_file); change_bg_file = True

    def click_camera_comboBox(self, text):
        global camera_no
        # self.camera_comboBox.addItems(self.get_cams_name())
        self.camera_comboBox.currentIndex()
        if 'OBS' in text or 'AI_Camera' in text:
            self.show_error("只能对物理摄像头进行抠像处理,请重新选择...")
            self.camera_comboBox.setCurrentIndex(-1)
        else:
            camera_no = self.camera_comboBox.currentIndex()

    def click_delay_comboBox(self, text):
        global delay_sec
        delay_sec = int(text)

    @pyqtSlot()
    def box_choose1(self):
        global Box1_flag
        if self.checkBox1.isChecked():
            Box1_flag = True; my_full_win.show()
        else:
            Box1_flag = False;my_full_win.hide()

    def checkBox_fullwin_func(self):
        if self.checkBox_fullwin.isChecked():
            my_result_win.show()
        else:
            my_result_win.hide()

    @pyqtSlot()
    def fullwinButton0_func(self):
        if self.checkBox1.isChecked():
            if my_full_win.isFullScreen():  my_full_win.showNormal()
            else: my_full_win.showFullScreen()

    def fullwinButton_func(self):
        if self.checkBox_fullwin.isChecked():
            if my_result_win.isFullScreen():  my_result_win.showNormal()
            else: my_result_win.showFullScreen()

            palette = QtGui.QPalette()
            palette.setBrush(self.backgroundRole(),
                             QtGui.QBrush(self.CvMatToQImage(
                             cv2.resize(self.ai_shooting,(my_result_win.width(), my_result_win.height())))))
            my_result_win.setPalette(palette)

    @pyqtSlot()
    def box_choose3(self):
        global Box3_flag
        if self.checkBox3.isChecked():
            self.txt3.setEnabled(False); self.bkfileButton.setEnabled(False)
            self.txt3.setText('已经选择纯色背景......')
            self.set_rgb_True()
            Box3_flag = True
        else:
            self.txt3.setEnabled(True);  self.bkfileButton.setEnabled(True)
            self.txt3.setText(bg_file)
            self.set_rgb_False()
            Box3_flag = False
    def set_rgb_False(self):
        self.red.setEnabled(False);     self.red_e.setEnabled(False); self.green.setEnabled(False)
        self.green_e.setEnabled(False); self.blue.setEnabled(False);  self.blue_e.setEnabled(False)
    def set_rgb_True(self):
        self.red.setEnabled(True);     self.red_e.setEnabled(True); self.green.setEnabled(True)
        self.green_e.setEnabled(True); self.blue.setEnabled(True);  self.blue_e.setEnabled(True)
    def red_e_fuc(self, text):
        if text =='': rgb = 0
        else: rgb = int(text)
        bk_pix[2] = rgb; bk_img[:] = bk_pix
        self.txt4.setPixmap(self.CvMatToQImage(cv2.resize(bk_img, (50, 18))))
    def green_e_fuc(self, text):
        if text =='': rgb = 0
        else: rgb = int(text)
        bk_pix[1] = rgb; bk_img[:] = bk_pix
        self.txt4.setPixmap(self.CvMatToQImage(cv2.resize(bk_img, (50, 18))))
    def blue_e_fuc(self, text):
        if text =='': rgb = 0
        else: rgb = int(text)
        bk_pix[0] = rgb; bk_img[:] = bk_pix
        self.txt4.setPixmap(self.CvMatToQImage(cv2.resize(bk_img, (50, 18))))
    def open_fold_fuc(self):
        try: os.startfile(out_dir)
        except:pass
    def chk_bk_file_fuc(self):
        try: os.startfile(bg_file)
        except: pass

    def v_cam_chk_fuc(self):
        if self.v_cam_chk.isChecked():
            if not 'AI_Camera' in cam_list:
                win32api.MessageBox(0, "       首次运行,您必须安装AI_Camera虚拟摄像头才能正常使用!\n\n"
                                       "       请在安装目录下执行一次【安装虚拟摄像头.exe】即可。\n", '运行信息提示',
                                    win32con.MB_OK)
                self.v_cam_chk.setChecked(False)

    def auto_chg_bk_fuc(self):
        global bg_file_list, chg_bk_counter
        if self.auto_chg_bk.isChecked():
            if bg_file == '':
                self.show_error('\n读取背景文件异常,您必须至少选择1个背景文件... \n')
                self.auto_chg_bk.setChecked(False); return

            bg_file_list = []
            jpg_path = os.path.split(bg_file)[0]
            self.bk_file_dir.setText(jpg_path)
            for ff in os.listdir(jpg_path):
                jpg_file = jpg_path + '/' + ff
                if os.path.isfile(jpg_file): bg_file_list.append(jpg_file)
            # print(bg_file_list)
            chg_bk_counter = int(self.spinBox.value())
            self.chg_bk_timer.start(1000)
        else: self.chg_bk_timer.stop()

    def spinBox_fuc(self):
        global chg_bk_counter
        chg_bk_counter = int(self.spinBox.value())

    def createLayout(self):
        global Box1_flag
        self.my_label1.setPixmap(QPixmap("start_img.jpg"))
        self.my_label2.setPixmap(QPixmap("start_img.jpg"))
        # self.my_label1.setFixedSize(427, 240); self.my_label2.setFixedSize(427, 240)
        self.my_label1.setAlignment(Qt.AlignCenter)
        self.my_label2.setAlignment(Qt.AlignCenter)
        self.my_label1.setToolTip("本区域,显示的是原始视频缩略图...")
        self.my_label2.setToolTip("本区域,显示的是替换后的缩略图...")

        if full_screen: self.checkBox1.setChecked(True); Box1_flag =True
        self.checkBox1.stateChanged.connect(self.box_choose1)
        self.checkBox_fullwin.stateChanged.connect(self.checkBox_fullwin_func)

        self.txt2.setText(out_dir);   self.txt3.setText(bg_file)
        self.bk_file_dir.setText(os.path.split(bg_file)[0])
        self.txt4.setPixmap(self.CvMatToQImage(cv2.resize(bk_img, (50, 18))))

        self.checkBox3.stateChanged.connect(self.box_choose3)
        self.v_cam_chk.stateChanged.connect(self.v_cam_chk_fuc)
        self.auto_chg_bk.stateChanged.connect(self.auto_chg_bk_fuc)
        self.spinBox.valueChanged.connect(self.spinBox_fuc)
        self.hand_shoot.setChecked(hand_shoot_flag)
        self.v_cam_chk.setToolTip("启动虚拟摄像头,可以在腾讯会议、Zoom会议、OBS等软件中使用...")
        self.auto_chg_bk.setToolTip("启动自动换背景,间隔几秒后,自动更换背景...")
        self.spinBox.setToolTip("选择自动换背景的时间间隔...")
        self.hand_shoot.setToolTip("举起手、摆出【OK】手势,放下手,n秒后启动拍照...")
        self.checkBox1.setToolTip("合成后的视频在窗口(可全屏)显示...")
        self.checkBox_fullwin.setToolTip("拍照后的照片在窗口(可全屏)显示3秒钟...")

        self.spinBox.setValue(delay_sec)
        self.auto_chg_bk.setChecked(change_bg_file)

        self.red_e.setText('8'); self.green_e.setText('188'); self.blue_e.setText('8')
        self.red_e.setValidator(QIntValidator(0, 254))
        self.green_e.setValidator(QIntValidator(0, 254))
        self.blue_e.setValidator(QIntValidator(0, 254))

        self.red_e.textChanged[str].connect(self.red_e_fuc)
        self.green_e.textChanged[str].connect(self.green_e_fuc)
        self.blue_e.textChanged[str].connect(self.blue_e_fuc)

        self.camera_comboBox.addItems(self.get_cams_name())
        self.camera_comboBox.activated[str].connect(self.click_camera_comboBox)
        self.camera_comboBox.setToolTip("物理摄像头,选择电脑上安装的物理硬件摄像头...")
        if 'OBS' in self.camera_comboBox.currentText() or 'AI_Camera' in self.camera_comboBox.currentText():
            self.camera_comboBox.setCurrentIndex(-1)
        else: self.camera_comboBox.setCurrentIndex(0)

        self.delay_comboBox.addItems(['1', '2', '3', '4', '5', '6', '7', '8', '9'])
        self.delay_comboBox.setCurrentIndex(chg_bk_counter-1)
        self.delay_comboBox.activated[str].connect(self.click_delay_comboBox)

        self.camera_w_h.addItems(['640x360', '800x600','960x540','1280x720','1440x900','1920x1080','2560x1440','3840x2160'])
        if cam_res == '1280x720': self.camera_w_h.setCurrentIndex(3)
        else: self.camera_w_h.setCurrentIndex(5)
        self.camera_w_h.setToolTip("设置摄像头分辨率,如果设置成功,实际分辨率将在下面显示...")
        self.real_camera_w_h.setText('0x0')
        self.real_camera_w_h.setToolTip("显示设置成功后的实际分辨率...")

        self.shootButton.clicked.connect(self.shootrun)
        self.shootButton.setStyleSheet("background-color:rgb(207,97,22);font-size:20px;font-weight:bold")
        self.shootButton.setEnabled(False)

        self.startButton.clicked.connect(self.start_run)
        self.stopButton.clicked.connect(self.stoprun)
        self.helpButton.clicked.connect(self.helpWin)
        self.quitButton.clicked.connect(self.quitWin)
        self.outButton.clicked.connect(self.outButton_fuc)
        self.bkfileButton.clicked.connect(self.bkfileButton_fuc)
        self.open_fold.clicked.connect(self.open_fold_fuc)
        self.chk_backfile.clicked.connect(self.chk_bk_file_fuc)
        self.fullwinButton0.clicked.connect(self.fullwinButton0_func)
        self.fullwinButton.clicked.connect(self.fullwinButton_func)

        self.outButton.setToolTip("选择输出文件目录,拍照后的文件将存在此目录...")
        self.bkfileButton.setToolTip("选择可用作背景的图片文件,建议分辨率:1920x1080...")
        self.fullwinButton.setToolTip("拍照后的照片全屏幕显示3秒钟...")
        self.fullwinButton0.setToolTip("合成的视频全屏幕显示...")

#if __name__ == '__main__':
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
app = QtWidgets.QApplication(sys.argv)
my_full_win = full_win()
my_result_win = result_win()
winshot = Winshot()
sys.exit(app.exec_())

Guess you like

Origin blog.csdn.net/weixin_42398606/article/details/132360521
Recommended