在《Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解》节介绍了怎么经过Python+Moviepy+OpenCV实现消除视频Logo的四种方法,并提供了详细的实现思路和实现代码,但这种原生态的应用不适合开发人员之外的其余人员使用,提供一个图形界面的工具程序是比较好的解决方案,本文就介绍实现这样一个图形化工具的步骤。html
本节的背景知识都在《Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解》介绍了,在此就不重复介绍了。python
本程序复用了《PyQt+moviepy音视频剪辑实战1:多个音视频合成顺序播放或同屏播放的视频文件实现详解》、《PyQt+moviepy音视频剪辑实战1:多视频合成顺序播放或同屏播放的视频文件》的公用框架,该框架提供统一的print输出管理、浮动窗口管理以及系通通一框架。web
从上面截图能够看到,主界面处理公共框架的功能外,提供了三大类功能,分别是消除准备(包括选择Logo、选择替换图)、查看功能(包括查看Logo图、查看替换图)、视频Logo消除(包括基于帧的预览、视频预览以及视频输出)。windows
该窗口能够用于预览图像及信息的展示,使用QGraphicView来实现:
app
class mainWin(QtWidgets.QMainWindow,ui_mainWin.Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) self.initValues() self.initSignalAndSlots() self.initPublicFrame() def initWidgetSatus(self):#初始化界面元素状态 self.action_selectReplaceRegion.setEnabled(False) self.action_selectLog.setEnabled(False) self.action_previewOneFrame.setEnabled(False) self.action_viewLogoImg.setEnabled(False) self.action_videoPreview.setEnabled(False) self.action_viewReplaceImg.setEnabled(False) self.action_outputVideo.setEnabled(False) def initOperations(self):#当选择不一样的视频文件时要做废原视频操做的相关记录 self.logoSelected = False self.replaceRegSelected =False if self.srcFName: self.videoOperation = CSubVideoImg(self.srcFName) self.replaceObject = None self.logoObjList = None self.destFNameManuChanged = False def initValues(self):#部分实例变量初始化 self.initWidgetSatus() self.videoOperation = None self.srcFName = None self.destFName = None self.srcDir = "" self.destDir = "" self.showHelpInfo = True #是否显示操做提示信息 self.destFNameManuChanged = False #输出文件是否手工修改标记 self.ridLogoManner = ridLogoManner_inpaint #缺省消除方式 self.imgInfW = imgInfoWin.imgInfoWin() #建立图像信息展现窗 self.fileDialog = QtWidgets.QFileDialog(self) self.initOperations() def initPublicFrame(self):#公共框架初始化 self.toggleOperationInfObject = self.actionshowHideOpInf # 显隐操做信息窗的开关对象如按钮、动做等,必须可使用setText方法 self.connectShowInfoSignal = self.actionshowHideOpInf.triggered # 用于触发打开或关闭输出信息窗的信号 self.connectAboutSignal = self.actionAbout.triggered # 用于触发打开about提示窗的信号 self.needShowHints = False # 若是须要在运行窗口显示初始的操做提示信息,则将此置为True,并在本类中提供showOperationHints(displayMsgWin)实例方法 def initSignalAndSlots(self): #信号和槽链接,全部重要操做都会从新触发界面元素状态设置 self.btn_choiceSrc.clicked.connect(self.chooseFile) #选择源文件 self.videoFile.textChanged['QString'].connect(self.verifyWidgetStatus) self.destFile.textEdited.connect(self.verifyWidgetStatus) #目标文件修改了 self.btn_choiceDest.clicked.connect(self.chooseFile) self.destFile.textEdited.connect(self.manuChangeDestFName) #输出文件若是手工修改了则不会根据选择的视频文件自动同步 self.action_selectLog.triggered.connect(self.selectLog) #选择Logo区域信号链接 self.action_previewOneFrame.triggered.connect(self.previewOneFrame) #帧预览信号链接 self.action_videoPreview.triggered.connect(self.videoPreview) #视频预览信号链接 self.action_help.triggered.connect(self.help) #帮助信号链接 self.action_selectReplaceRegion.triggered.connect(self.selectReplaceRegion) #替换图像选择信号链接 self.action_viewLogoImg.triggered.connect(self.viewLogoImg) #查看Logo图像信号链接 self.action_viewReplaceImg.triggered.connect(self.viewReplaceImg) #查看替换图像信号链接 self.action_outputVideo.triggered.connect(self.convertVideo) #输出处理视频信号链接 #消除方式变化信号链接 self.radioButton_staticImg.toggled.connect(self.ridLogoMannerSelected) self.radioButton_frameImg.toggled.connect(self.ridLogoMannerSelected) self.radioButton_inpaint.toggled.connect(self.ridLogoMannerSelected) self.radioButton_multiSampleInpaint.toggled.connect(self.ridLogoMannerSelected)
def showHelp(self,helpinf): #显示帮助信息 print(helpinf) if self.checkBox_showOperHint.isChecked(): QMessageBox.information(self, '操做提示', helpinf, QMessageBox.Ok ) def showInfo(self,info):#显示提示信息 print(info) QMessageBox.information(self, '操做提示', info, QMessageBox.Ok ) def showImgInf(self,*showObjs): #在图像信息窗按顺序显示相关图像或文本 imgInfW = self.imgInfW for showObj in showObjs: if showObj is None: continue if isinstance(showObj,str): imgInfW.showText(showObj) else: qtimg = imgInfW.showCVImg(showObj) imgInfW.show()
def verifyWidgetStatus(self): #根据当前操做确认界面元素的状态 self.initWidgetSatus() videoFName = self.videoFile.text().strip() if len(videoFName): dir = QtCore.QDir("") if(dir.exists(videoFName)): self.action_selectLog.setEnabled(True) if self.ridLogoManner in [ridLogoManner_staticImg,ridLogoManner_frameImg]: if self.logoSelected: self.action_selectReplaceRegion.setEnabled(True) if videoFName!=self.srcFName: self.srcFName = videoFName self.initOperations() if self.logoSelected and (self.replaceRegSelected or self.ridLogoManner in [ridLogoManner_inpaint,ridLogoManner_multiSampleInpaint] ): self.action_previewOneFrame.setEnabled(True) self.action_videoPreview.setEnabled(True) destFName = self.destFile.text().strip() if len(destFName): self.action_outputVideo.setEnabled(True) self.destFName = destFName if self.replaceRegSelected: if self.ridLogoManner in [ridLogoManner_staticImg,ridLogoManner_frameImg]: self.action_viewReplaceImg.setEnabled(True) if self.logoSelected: self.action_viewLogoImg.setEnabled(True)
下面是准备消除操做的一个关键槽方法–选择Logo图像的槽方法:框架
def selectLog(self): #实现Logo图像选择 fps = int(self.lineEdit_logoSelectFps.text().strip()) if self.ridLogoManner != ridLogoManner_multiSampleInpaint: helpstr = "将弹出新窗口按设定的帧率播放视频图像,请在显示的视频上使用鼠标左键选择Logo图像的范围。注意:\n" + \ "一、选择时会有蓝色边框的矩形确认选择范围,当选择完成时松开鼠标便可确认选择;\n" + \ "二、视频选择时会中止播放,能够选择完成后经过鼠标右键点击或鼠标双击恢复视频播放\n" + \ "三、若是选择错了能够从新选择;\n" + \ "四、若是确认选择结束,按ESC或Q、q三者中的一个退出选择操做,系统将记录选择的Logo图像;\n" + \ "五、选择的Logo图像能够经过查看菜单下的相关菜单进行查看。\n\n" + \ "本提示信息能够经过界面“显示操做提示信息”复选框关闭。" else: helpstr = "将弹出新窗口按设定的帧率播放视频图像,请在显示的视频上使用鼠标左键选择Logo图像的范围。注意:\n" + \ "一、选择时会有蓝色边框的矩形确认选择范围,当选择完成时松开鼠标便可确认选择;\n" + \ "二、视频选择时会中止播放,能够选择完成后经过鼠标右键点击或鼠标双击恢复视频播放\n" + \ "三、若是选择错了能够从新选择;\n" + \ "四、若是确认选择,按n、N、s、S将保存当前选择Logo图像,恢复播放后能够再选择Logo再保存,以支持选择多个Logo图像" \ "5,按ESC或Q、q三者中的一个退出选择操做,退出时已选择图像会保存,系统将不剔重的记录选择的全部Logo图像;\n" + \ "六、选择的Logo图像能够经过查看菜单下的相关菜单进行查看。\n\n" + \ "本提示信息能够经过界面“显示操做提示信息”复选框关闭。" self.showHelp(helpstr) logobjs,frame = self.videoOperation.getROI("select multiLogo Imgs Range",fps) if logobjs is not None and len(logobjs): self.logoSelected = True self.logoObjList = (logobjs, frame) self.verifyWidgetStatus() self.frameMask = self.videoOperation.genMultiLogoFrameMask([logobjs[-1]],frame) self.multiFrameMask = self.videoOperation.genMultiLogoFrameMask(logobjs, frame) self.frame = frame else: self.showInfo("本次操做没有选择对应Logo图像,若是要执行后续操做,请从新选择。")
def viewLogoImg(self): #查看Logo图像 if not self.logoSelected: self.showInfo("当前视频文件还没有选择Logo图像") return self.showImgInf( f"截取的Logo共计{len(self.logoObjList[0])}个,除了多采样图像修复术外,其余消除方法都只取最后一个。各图像以下:\n ") count = 0 logoObjs = self.logoObjList[0] for logoobj in logoObjs: self.showImgInf(f" 第{count + 1}个:",logoobj[0]) count += 1
def convertVideo(self): #输出视频 self.setEnabled(False) if self.ridLogoManner in [ridLogoManner_staticImg,ridLogoManner_frameImg]: ret, inf = self.videoOperation.convertVideo(self.destFName, self.ridLogoManner, self.logoObjList, self.replaceObject) elif self.ridLogoManner == ridLogoManner_inpaint: ret,inf = self.videoOperation.convertVideo( self.destFName, self.ridLogoManner, self.logoObjList, frameMask=self.frameMask) else: ret,inf = self.videoOperation.convertVideo( self.destFName, self.ridLogoManner, self.logoObjList, frameMask=self.multiFrameMask) print(inf) self.setEnabled(True)
if __name__=='__main__': app = QtWidgets.QApplication(sys.argv) w = mainWin() loadWin = loadApp.loadAppWin(w,"视频Logo消除", True, True) w.show() sys.exit(app.exec_())
一、初始界面
ide
二、选择Logo图像的截图
三、查看Logo图像的截图
四、输出视频文件截图
svg
使用《PyQt(Python+Qt)学习随笔:windows下使用pyinstaller将PyQt文件打包成exe可执行文件》介绍的方法进行打包。工具
老猿在win7上最终打包的可执行程序包已经上传到百度云,你们能够下载下来长期无偿使用。具体下载地址为百度网盘。学习
提取码:yh2d
选择该连接下的:视频Logo消除工具V2.0.rar 便可。
注意:
百度云上分享的《咖啡狗免费工具软件共享空间》下的不一样软件安装时必须解压到不一样目录,若是解压到同一目录可能有冲突致使不能正常运行,但解压后遵循以下要求能够将其聚合到同一个目录:
更多moviepy的介绍请参考《PyQt+moviepy音视频剪辑实战文章目录》或《moviepy音视频开发专栏》。这2个专栏内容的导读请参考《Python音视频剪辑库MoviePy1.0.3中文教程导览及可执行工具下载》。
老猿的付费专栏《使用PyQt开发图形界面Python应用》专门介绍基于Python的PyQt图形界面开发基础教程,付费专栏《moviepy音视频开发专栏》详细介绍moviepy音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,两个专栏加起来只须要19.9元,都适合有必定Python基础但无相关专利知识的小白读者学习。这2个收费专栏都有对应免费专栏,只是收费专栏的文章介绍更具体、内容更深刻、案例更多。
付费专栏文章目录:《moviepy音视频开发专栏文章目录》、《使用PyQt开发图形界面Python应用专栏目录》。本文对应付费专栏文章为《Python音视频开发:消除抖音短视频Logo的图形化工具实现过程详解》。
关于Moviepy音视频开发的内容,请你们参考《Python音视频剪辑库MoviePy1.0.3中文教程导览及可执行工具下载》的导览式介绍。
对于缺少Python基础的同仁,能够经过老猿的免费专栏《专栏:Python基础教程目录》从零开始学习Python。
若是有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。