(七)视频背景移除/去背景/换背景/抠图/抠像代码示例:实时抠图、实时抠像、人像去背景、背景消除

视频背景移除/去背景/换背景/抠图/抠像代码示例:实时抠图、实时抠像、人像去背景、背景消除

本文与前几篇博文关联性较强,请事先阅读前几篇。 对此文感兴趣的可以加微深入探讨:herbert156
软件打包上传了百度网盘:
【视频背景移除】链接: https://pan.baidu.com/s/1Dhr7MHkGd8vlXfyETrK3xQ 提取码: 29n2
【图像背景移除】链接: https://pan.baidu.com/s/1nhuWMYWvTV3B0d0CdGDhFQ 提取码: q46x
【摄像头背景移除】链接: https://pan.baidu.com/s/1tx88C3dCH3ej3PJcKLDmdQ 提取码: g7xy

软件界面如下:
(七)视频背景移除/去背景/换背景/抠图/抠像代码示例:实时抠图、实时抠像、人像去背景、背景消除_第1张图片

一、视频抠像
以下的Python代码的功能:视频背景移除、去背景、人像抠图、换背景等,主要功能包括:
1、对包含人像的视频进行抠像,并替换背景(可以替换成纯色的、也可以替换成指定背景图片);
2、可以批量处理,在选择文件的对话框里可以选择多个文件,同时抠像换背景、批量操作;
3、软件设置里可以设置使用GPU处理还是CPU处理,软件只支持英伟达(Nvidia)的GTX/RTX系列的GPU;
4、抠图算法的模型有复杂模型和简易模型,可以根据原始图片的背景复杂度随意选择;
5、信息统计里面可以实时显示处理的各种统计信息;
6、视频处理完毕后自动进行音频的处理与合成。

二、视频抠图代码
将视频文件逐帧解出,然后逐帧抠图。再按照原来FPS合成视频、音频:

    def video_change_background(self, videofile, backfile):
        global bg_file, iii, stop_flag, t0
        try: cap = cv2.VideoCapture(videofile)  # 读取视频文件
        except: self.show_error('读取视频文件:'+videofile+'时,出现错误!'); return
        fps = cap.get(cv2.CAP_PROP_FPS)  # 帧率
        total_fr = cap.get(cv2.CAP_PROP_FRAME_COUNT)  # 总帧数
        size_x = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))  # 视频流的帧宽度
        size_y = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))  # 视频流的帧高度
        len_m,len_s = divmod(total_fr/fps, 60)
        videoinfo = '【视频信息】 文件总数:%d | 正在处理(%d/%d):'%(filesnums,iii,filesnums) + os.path.split(videofile)[1]+\
                    ' | 帧分辨率:%dx%d | 视频长度:%d分%d秒 | FPS:%.2f帧/秒'%(size_x,size_y,len_m,len_s,fps)
        self.txt11.setText(videoinfo)

        img1 = cv2.resize(backfile, (size_x, size_y))
        tempfile = os.path.split(bg_file)[0]+'\\out.mp4'
        out = cv2.VideoWriter(tempfile, cv2.VideoWriter_fourcc(*'mp4v'), fps, (size_x, size_y))
        t1 = time.time(); next_fr = 0
        if size_x / size_y > 1.778: fx = 427 / size_x; fy = fx   # 计算16:9的比例,以便缩放不变形
        else: fx = 240 / size_y; fy = fx

        while (True):
            t2 = time.time()
            if stop_flag:
                cap.release();  out.release(); os.remove(tempfile)
                self.txt11.setText('【视频信息】 文件总数:%d个 | 处理完成:%d个' % (filesnums, iii))
                self.txt12.setText('【运行信息】 用户终止了正在运行的程序......')
                return
            next_fr += 1
            ret, frame = cap.read()
            if ret:
                img2 = self.koutu(frame)
                #img2 = cv2.cvtColor(frame.copy(), cv2.COLOR_BGR2BGRA)   #测试用语句
                img3 = self.two_pic_combine_PIL(img1,img2)
                out.write(img3)  # 帧转成视频
            else: break
            if Box1_flag: self.my_label1.setPixmap(self.CvMatToQImage(cv2.resize(frame,(0,0),fx=fx,fy=fy)))
            if Box2_flag: self.my_label2.setPixmap(self.CvMatToQImage(cv2.resize(img3,(0,0),fx=fx,fy=fy)))
            cv2.waitKey(1)
            t3 = time.time(); m1, s1 = divmod(t3-t0, 60); m2, s2 = divmod(t3-t1, 60)
            runinfo = '【运行信息】 当前视频处理进度:%d%% | 总耗时:%d分%d秒 | 当前视频耗时:%d分%d秒 | 当前帧耗时:%.2f秒 | 处理速度:%.1fFPS'\
                      %(100*next_fr/total_fr, m1, s1, m2, s2,(t3-t2),1/(t3-t2))
            self.txt12.setText(runinfo)

        cap.release(); out.release()
        self.txt12.setText('【运行信息】 正在分离、合成音轨(大概需要:%.1f分钟),请稍后......'%(len_m/2))
        cv2.waitKey(1)
        audio = mpe.AudioFileClip(videofile)  # 分离声轨
        clip = mpe.VideoFileClip(tempfile)
        videoclip = clip.set_audio(audio)  # 写入声轨
        videoclip.write_videofile(out_dir+'/'+os.path.splitext(os.path.split(videofile)[1])[0]+'_1.mp4')
        os.remove(tempfile)
        t3 = time.time()
        self.txt12.setText('【运行信息】 处理完毕!总消耗时间:%d分%d秒'%(m1, s1))
        self.txt11.setText('【视频信息】 文件总数:%d个 | 处理完成:%d个'%(filesnums,iii))

三、界面操作代码

    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.filesButton.setEnabled(False);       self.outButton.setEnabled(False)
        self.bkfileButton.setEnabled(False);      self.checkBox3.setEnabled(False)
        self.startButton.setEnabled(False);       self.stopButton.setEnabled(True)
        self.quitButton.setEnabled(False)
    def set_True_Btn(self):
        self.filesButton.setEnabled(True);       self.outButton.setEnabled(True)
        self.bkfileButton.setEnabled(True);      self.checkBox3.setEnabled(True)
        self.startButton.setEnabled(True);       self.stopButton.setEnabled(False)
        self.quitButton.setEnabled(True)

    def startrun(self):
        global iii,stop_flag,t0
        iii = 0; stop_flag = False
        self.txt12.setText('【运行信息】 正在初始化AI模型......');cv2.waitKey(1)
        t0 = time.time()
        if files == []: self.show_error('请选择需要替换背景的视频文件!'); return
        if not os.path.exists(out_dir): self.show_error('输出目录不存在,请重新选择!'); return
        self.set_False_Btn()
        if not Box3_flag:
            #try: back_ground = cv2.imread(bg_file)  # 读取背景文件
            try: back_ground = cv2.imdecode(np.fromfile(bg_file, dtype=np.uint8), -1)
            except: self.show_error('读取背景文件时,出现错误!'); self.set_True_Btn(); return
            if back_ground is None: self.show_error('读取背景文件时,出现错误!\n原因:目录/文件名不能包含中文...... '); self.set_True_Btn(); return
        else: back_ground = bk_img
        for file in files:
            iii += 1
            if stop_flag: break
            self.video_change_background(file, back_ground)
        self.set_True_Btn()
        self.my_label1.setPixmap(QPixmap("start_img.jpg"))
        self.my_label2.setPixmap(QPixmap("start_img.jpg"))

    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

    def helpWin(self):
        str="\n\n\n1、【选择文件】选择需要替换背景的视频文件;\n2、【输出目录】替换后的文件目录,文件名:源文件_1.mp4;\n"+\
        "3、【背景文件】选择后,人物视频的背景都被替换成此背景;\n4、【纯色背景】点选后,所有视频背景替换成纯色的;\n"+\
        "5、如没有Nvidia系列GPU,就选CPU处理,AI需选【简易】;\n6、AI抠像算法有简易、复杂2种,可在软件设置栏目里面选择;\n\n\n"+\
        "      本软件著作权归属:???        网址:www.???.com\n\n"
        QMessageBox.question(self, my_title, str, QMessageBox.Ok)
    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: sys.exit()

    def filesButton_fuc(self):
        global files,filesnums
        files, ok1 = QFileDialog.getOpenFileNames(self,'请选择视频文件[全选:Ctrl+A、多选:Ctrl/Shift+鼠标]',
                                                       input_path,"*.mp4;;*.avi;;*.mkv")
        filesnums = len(files)
        if files!=[]:
            txt='目录:'+os.path.split(files[0])[0]+' | 已选文件:'+str(filesnums)+'个 | 文件名:'
            for file in files: txt=txt+ os.path.split(file)[1]+'; '
            self.txt1.setText(txt)
        else: self.txt1.setText('请选择视频文件[全选:Ctrl+A、多选:Ctrl/Shift+鼠标]......')
    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)
    def bkfileButton_fuc(self):
        global 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)

    def click_comboBox1(self, text):
        global if_use_gpu,if_good_model
        if text == 'GPU':
            if GPU_memsize < 3 and self.comboBox2.currentIndex() == 1:
                self.show_error("\nGPU名称:%s\nGPU内存:%dG\n\n注意:\nGPU内存必须大于3G才能进行复杂AI模型,\n请选择简易模型!"
                                %(GPU_name,GPU_memsize))
                self.comboBox2.setCurrentIndex(0);if_good_model = False
            if_use_gpu = True
        else: if_use_gpu = False
    def click_comboBox2(self, text):
        global if_good_model,if_use_gpu
        if text == '复杂':
            if GPU_memsize < 3 and self.comboBox1.currentIndex() == 1:
                self.show_error("\nGPU名称:%s\nGPU内存:%dG\n\n注意:\nGPU内存必须大于3G才能进行复杂AI模型,\n请选择简易模型或CPU处理!"
                                % (GPU_name, GPU_memsize))
                self.comboBox1.setCurrentIndex(0);if_use_gpu = False
            if_good_model = True
        else: if_good_model = False

    def box_choose(self):
        global Box1_flag, Box2_flag
        if self.checkBox1.isChecked(): Box1_flag = True
        else:Box1_flag = False;  self.my_label1.setPixmap(QPixmap("start_img.jpg"))
        if self.checkBox2.isChecked(): Box2_flag = True
        else:Box2_flag = False;  self.my_label2.setPixmap(QPixmap("start_img.jpg"))

    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 createLayout(self):
        mainLayout = QtWidgets.QVBoxLayout();topLayout1 = QtWidgets.QHBoxLayout();topLayout2 = QtWidgets.QHBoxLayout()
        topLayout3 = QtWidgets.QHBoxLayout();topLayout4 = QtWidgets.QHBoxLayout()

        self.my_label1 = QtWidgets.QLabel(); self.my_label2 = QtWidgets.QLabel()
        topLayout1.addWidget(self.my_label1); topLayout1.addWidget(self.my_label2)

        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("本区域,显示的是替换后的缩略图...")

        self.GroupBox1 = QtWidgets.QGroupBox("软件设置")
        self.GroupBox1.setFixedSize(280, 60)
        self.lbl_1 = QtWidgets.QLabel("处理器:", self)
        self.lbl_1.setFixedSize(45, 25)
        self.comboBox1 = QtWidgets.QComboBox(self)
        self.comboBox1.setFixedSize(50, 25)
        self.comboBox1.addItem("CPU");  self.comboBox1.addItem("GPU")
        if if_use_gpu: self.comboBox1.setCurrentIndex(1)
        else: self.comboBox1.setEnabled(False)
        self.comboBox1.activated[str].connect(self.click_comboBox1)
        self.lbl_2 = QtWidgets.QLabel("AI算法:", self)
        self.lbl_2.setFixedSize(45, 25)
        self.comboBox2 = QtWidgets.QComboBox(self)
        self.comboBox2.setFixedSize(50, 25)
        self.comboBox2.addItem("简易"); self.comboBox2.addItem("复杂")
        if if_good_model:self.comboBox2.setCurrentIndex(1)
        self.comboBox2.activated[str].connect(self.click_comboBox2)
        GroupBox1Layout = QtWidgets.QHBoxLayout()
        GroupBox1Layout.addWidget(self.lbl_2)
        GroupBox1Layout.addWidget(self.comboBox2)
        GroupBox1Layout.addWidget(self.lbl_1)
        GroupBox1Layout.addWidget(self.comboBox1)
        self.GroupBox1.setLayout(GroupBox1Layout)
        #if not if_use_gpu: self.GroupBox1.setEnabled(False)

        self.GroupBox2 = QtWidgets.QGroupBox("预览设置")
        self.GroupBox2.setFixedSize(180, 60)
        self.checkBox1 = QtWidgets.QCheckBox("原始视频")
        self.checkBox2 = QtWidgets.QCheckBox("输出视频")
        GroupBox2Layout = QtWidgets.QHBoxLayout()
        GroupBox2Layout.addWidget(self.checkBox1)
        GroupBox2Layout.addWidget(self.checkBox2)
        self.GroupBox2.setLayout(GroupBox2Layout)
        self.checkBox1.stateChanged.connect(self.box_choose)
        self.checkBox2.stateChanged.connect(self.box_choose)
        self.checkBox1.setChecked(True); self.checkBox2.setChecked(True)

        self.GroupBox4 = QtWidgets.QGroupBox("文件设置")
        self.GroupBox4.setFixedSize(850, 160)
        self.filesButton = self.createButton("选择文件", self.filesButton_fuc)
        self.outButton = self.createButton("输出目录", self.outButton_fuc)
        self.bkfileButton = self.createButton("背景文件", self.bkfileButton_fuc)
        self.filesButton.setToolTip("选择即将被替换背景的视频文件,可单选、多选...")
        self.outButton.setToolTip("选择输出文件目录,替换后的文件将存在此目录...")
        self.bkfileButton.setToolTip("选择可用作背景的图片文件,建议分辨率:1920x1080...")
        self.filesButton.setFixedSize(80,23); self.outButton.setFixedSize(80,23)
        self.bkfileButton.setFixedSize(80,23)
        self.txt1 = QLabel('请选择视频文件[Ctrl+A全选、Ctrl/Shift+鼠标可多选]......', self); self.txt2 = QLabel('输出目录', self)
        self.txt3 = QLabel('背景文件', self); self.txt4 = QLabel('纯色文件', self)
        self.txt2.setText(out_dir);   self.txt3.setText(bg_file);
        self.txt4.setPixmap(self.CvMatToQImage(cv2.resize(bk_img, (50, 18))))
        self.checkBox3 = QtWidgets.QCheckBox("纯色背景")
        self.checkBox3.stateChanged.connect(self.box_choose3)

        self.red  = QLabel(' 红', self); self.green= QLabel('    绿', self); self.blue = QLabel('    蓝', self)
        self.red_e =   QLineEdit(self);    self.red_e.setText('8')
        self.green_e = QLineEdit(self);    self.green_e.setText('188')
        self.blue_e =  QLineEdit(self);    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.setFixedSize(28, 20);self.green_e.setFixedSize(28, 20);self.blue_e.setFixedSize(28, 20)
        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)

        layout_box1 = QtWidgets.QHBoxLayout()
        layout_box2 = QtWidgets.QHBoxLayout()
        layout_box3 = QtWidgets.QHBoxLayout()
        layout_box1.addWidget(self.filesButton, Qt.AlignLeft| Qt.AlignVCenter)
        layout_box1.addWidget(self.txt1, Qt.AlignLeft| Qt.AlignVCenter)
        layout_box2.addWidget(self.outButton)
        layout_box2.addWidget(self.txt2)
        layout_box2.addWidget(self.bkfileButton)
        layout_box2.addWidget(self.txt3)
        layout_box3.addWidget(self.checkBox3)
        layout_box3.addWidget(self.txt4)
        layout_box3.addWidget(self.red)
        layout_box3.addWidget(self.red_e)
        layout_box3.addWidget(self.green)
        layout_box3.addWidget(self.green_e)
        layout_box3.addWidget(self.blue)
        layout_box3.addWidget(self.blue_e)
        layout_box3.addStretch(1)
        layout11 = QWidget();  layout21 = QWidget(); layout31 = QWidget()
        layout11.setLayout(layout_box1);  layout21.setLayout(layout_box2); layout31.setLayout(layout_box3)

        GroupBoxmainLayout = QtWidgets.QVBoxLayout()
        GroupBoxmainLayout.addWidget(layout11, Qt.AlignLeft | Qt.AlignVCenter)
        GroupBoxmainLayout.addWidget(layout21, Qt.AlignLeft | Qt.AlignVCenter)
        GroupBoxmainLayout.addWidget(layout31, Qt.AlignLeft | Qt.AlignVCenter)
        self.GroupBox4.setLayout(GroupBoxmainLayout)

        self.GroupBox5 = QtWidgets.QGroupBox("信息统计")
        self.GroupBox5.setFixedSize(850, 90)
        self.txt11 = QLabel('【视频信息】', self)
        self.txt12 = QLabel('【运行信息】', self)
        GroupBox5Layout = QtWidgets.QGridLayout()
        GroupBox5Layout.addWidget(self.txt11, 0, 1)
        GroupBox5Layout.addWidget(self.txt12, 1, 1)
        self.GroupBox5.setLayout(GroupBox5Layout)

        self.startButton = self.createButton("开始处理", self.startrun)
        self.stopButton = self.createButton("停止", self.stoprun)
        self.helpButton = self.createButton("帮助", self.helpWin)
        self.quitButton = self.createButton("退出", self.quitWin)
        self.startButton.setFixedSize(80,25)
        self.stopButton.setFixedSize(55, 25)
        self.helpButton.setFixedSize(55,25)
        self.quitButton.setFixedSize(55,25)

        topLayout2.addWidget(self.GroupBox4)
        topLayout3.addWidget(self.GroupBox5)
        topLayout4.addWidget(self.GroupBox1)
        topLayout4.addWidget(self.GroupBox2)
        topLayout4.addWidget(self.startButton)
        topLayout4.addWidget(self.stopButton)
        topLayout4.addWidget(self.helpButton)
        topLayout4.addWidget(self.quitButton)
        topLayout4.setSpacing(20)

        layout1 = QWidget();  layout2 = QWidget()
        layout3 = QWidget();  layout4 = QWidget()
        layout1.setLayout(topLayout1);  layout2.setLayout(topLayout2)
        layout3.setLayout(topLayout3);  layout4.setLayout(topLayout4)

        mainLayout.addWidget(layout1, Qt.AlignLeft | Qt.AlignTop)
        mainLayout.addWidget(layout2, Qt.AlignLeft | Qt.AlignBottom)
        mainLayout.addWidget(layout3, Qt.AlignLeft | Qt.AlignBottom)
        mainLayout.addWidget(layout4, Qt.AlignLeft | Qt.AlignBottom)
        self.setLayout(mainLayout)

    def createButton(self, text, member):
        button = QtWidgets.QPushButton(text)
        button.clicked.connect(member)
        return button```

你可能感兴趣的:(Python,AI研究,paddlepaddle,python,深度学习)