(十九)AI虚拟拍照、AI虚拟旅游、AI虚拟摄像头,实时抠像、摄像头背景移除
本文代码实现了对摄像头视频的抠像处理,并把人像与背景图融合在一起,可以足不出户,即可拍出精美的旅游风景照片。省去了逐张PS的麻烦;
可以手势自动拍照,省去了按按钮的麻烦;
由于需要实时处理,必须在有GPU的电脑上运行,仅支持英伟达的显卡。
也可以把合成后的摄像映射在一个虚拟摄像头(AI_Camera),此虚拟摄像头可以被各种网络会议软件使用;
还可以把拍的照片自动上传百度,供人查看下载;
可运行的软件打包上传了网盘:
链接: https://pan.baidu.com/s/1Zlm81gs0yB4djGa8qhGXtg?pwd=8888
本文与前几篇博文关联性较强,请事先阅读前几篇。 对此文感兴趣的可以加微深入探讨:herbert156
话不多说上代码:
界面部分:
# -*- 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", "背景文件目录:"))
主运行代码:
#视频背景替换工具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_())