Python音视频开发:消除抖音短视频Logo的图形化工具实现
☞ ░ 前往老猿Python博文目录 ░
一、引言
在《Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解》节介绍了怎么通过Python+Moviepy+OpenCV实现消除视频Logo的四种方法,并提供了详细的实现思路和实现代码,但这种原生态的应用不适合开发人员以外的其他人员使用,提供一个图形界面的工具程序是比较好的解决方案,本文就介绍实现这样一个图形化工具的步骤。
本节的背景知识都在《Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解》介绍了,在此就不重复介绍了。
二、图形界面设计
本程序复用了《PyQt+moviepy音视频剪辑实战1:多个音视频合成顺序播放或同屏播放的视频文件实现详解》、《PyQt+moviepy音视频剪辑实战1:多视频合成顺序播放或同屏播放的视频文件》的公用框架,该框架提供统一的print输出管理、浮动窗口管理以及系统统一框架。
2.1、主界面

从上面截图可以看到,主界面处理公共框架的功能外,提供了三大类功能,分别是消除准备(包括选择Logo、选择替换图)、查看功能(包括查看Logo图、查看替换图)、视频Logo消除(包括基于帧的预览、视频预览以及视频输出)。
2.2、图形化信息预览窗
该窗口可以用于预览图像及信息的展现,使用QGraphicView来实现:

三、程序实现
3.1、主界面派生类定义及相关初始化方法
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)
3.2、信息显示方法
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()
3.3、部件状态设置方法
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)
3.4、消除准备相关动作槽方法示例
下面是准备消除操作的一个关键槽方法–选择Logo图像的槽方法:
def selectLog(self): #实现Logo图像选择
fps = int(self.lineEdit_logoSelectFps.text().strip())
if self.ridLogoManner != ridLogoManner_multiSampleInpaint:
helpstr = "将弹出新窗口按设定的帧率播放视频图像,请在显示的视频上使用鼠标左键选择Logo图像的范围。注意:\n" + \
"1、选择时会有蓝色边框的矩形确认选择范围,当选择完成时松开鼠标即可确认选择;\n" + \
"2、视频选择时会停止播放,可以选择完成后通过鼠标右键点击或鼠标双击恢复视频播放\n" + \
"3、如果选择错了可以重新选择;\n" + \
"4、如果确认选择结束,按ESC或Q、q三者中的一个退出选择操作,系统将记录选择的Logo图像;\n" + \
"5、选择的Logo图像可以通过查看菜单下的相关菜单进行查看。\n\n" + \
"本提示信息可以通过界面“显示操作提示信息”复选框关闭。"
else:
helpstr = "将弹出新窗口按设定的帧率播放视频图像,请在显示的视频上使用鼠标左键选择Logo图像的范围。注意:\n" + \
"1、选择时会有蓝色边框的矩形确认选择范围,当选择完成时松开鼠标即可确认选择;\n" + \
"2、视频选择时会停止播放,可以选择完成后通过鼠标右键点击或鼠标双击恢复视频播放\n" + \
"3、如果选择错了可以重新选择;\n" + \
"4、如果确认选择,按n、N、s、S将保存当前选择Logo图像,恢复播放后可以再选择Logo再保存,以支持选择多个Logo图像" \
"5,按ESC或Q、q三者中的一个退出选择操作,退出时已选择图像会保存,系统将不剔重的记录选择的所有Logo图像;\n" + \
"6、选择的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图像,如果要执行后续操作,请重新选择。")
3.5、查看动作槽方法示例
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
3.6、视频输出槽方法
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_())
五、运行截图
1、初始界面

2、选择Logo图像的截图

3、查看Logo图像的截图

4、输出视频文件截图

六、打包成exe
使用《PyQt(Python+Qt)学习随笔:windows下使用pyinstaller将PyQt文件打包成exe可执行文件》介绍的方法进行打包。
老猿在win7上最终打包的可执行程序包已经上传到百度云,大家可以下载下来长期免费使用。具体下载地址为百度网盘。
链接:https://pan.baidu.com/s/1UNaA2UqQBoxx-v8rCIPDhA
提取码:yh2d
选择该链接下的:视频Logo消除工具V2.0.rar 即可。
注意:
百度云上分享的《咖啡狗免费工具软件共享空间》下的不同软件安装时必须解压到不同目录,如果解压到同一目录可能有冲突导致不能正常运行,但解压后遵循如下要求可以将其聚合到同一个目录:
- 放置到同一目录的不同软件的版本必须相同,版本为压缩文件名中VX.X标注;
- 聚合拷贝时除拷贝执行文件外,还有resource目录必须拷贝,如果resource目录下有相同文件名可以覆盖;
- 聚合拷贝exe文件和resource目录及其下文件到其他已解压工具目录后,源目录可以删除。
更多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。
如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。

跟老猿学Python!
☞ ░ 前往老猿Python博文目录 ░
Python音视频开发:消除抖音短视频Logo的图形化工具实现的更多相关文章
- Python音视频开发:消除抖音短视频Logo和去电视台标
☞ ░ 前往老猿Python博文目录 ░ 一.引言 对于带Logo(如抖音Logo.电视台标)的视频,有三种方案进行Logo消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...
- from appium import webdriver 使用python爬虫,批量爬取抖音app视频(requests+Fiddler+appium)
使用python爬虫,批量爬取抖音app视频(requests+Fiddler+appium) - 北平吴彦祖 - 博客园 https://www.cnblogs.com/stevenshushu/p ...
- 使用Flutter开发的抖音国际版
简介 最近花了两天时间研究使用Flutter开发一个抖音国际版. 先上图,个人感觉使用Flutter开发app快得不要不要的额. 两天就基本可以开发个大概出来. 最主要是热更新,太方便实时调整U ...
- Moviepy音视频开发:视频转gif动画或jpg图片exe图形化工具开发案例
☞ ░ 前往老猿Python博文目录 ░ 一.引言 老猿之所以学习和研究Moviepy的使用,是因为需要一个将视频转成动画的工具,当时在网上到处搜索查找免费使用工具,结果找了很多自称免费的工具,但转完 ...
- Moviepy音视频开发:开发视频转gif动画或jpg图片exe图形化工具的案例
☞ ░ 前往老猿Python博文目录 ░ 一.引言 老猿之所以学习和研究Moviepy的使用,是因为需要一个将视频转成动画的工具,当时在网上到处搜索查找免费使用工具,结果找了很多自称免费的工具,但转完 ...
- JavaWeb-SpringBoot(抖音)_一、抖音项目制作
JavaWeb-SpringBoot(抖音)_一.抖音项目制作 传送门 JavaWeb-SpringBoot(抖音)_二.服务器间通讯 传送门 JavaWeb-SpringBoot(抖音)_三.抖音项 ...
- JavaWeb-SpringBoot(抖音)_三、抖音项目后续
JavaWeb-SpringBoot(抖音)_一.抖音项目制作 传送门 JavaWeb-SpringBoot(抖音)_二.服务器间通讯 传送门 JavaWeb-SpringBoot(抖音)_三.抖音项 ...
- 最快1天搭建短视频APP!阿里云短视频解决方案上线
短视频行业的发展前景乐观是毋庸置疑的,整个短视频的市场规模一直在增长,网络数据显示2018年已经突破100亿大关,在2019年预测将超过200亿.那么,对于短视频从业者来讲,要持续推动业务的发展,必须 ...
- Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解
☞ ░ 前往老猿Python博文目录 ░ 一.引言 对于带Logo(如抖音Logo.电视台标)的视频,有三种方案进行Logo消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...
随机推荐
- How to using code post packingSlip on Quality Orders Form[AX2009]
For simple user operation posting packing slip with purchase order. we added a function button on Qu ...
- bert做阅读理解的一个细节
如上图所示,展示了如何用BERT来做信息抽取任务的结构图.注意一下几点即可: 1.将Question和Paragraph分别作为BERT的text1和text2输入. 2.start/end span ...
- 记一次ns3的安装过程
官方安装教程:https://www.nsnam.org/wiki/Installation 推荐使用Ubuntu18.04,Ubuntu20.04有些依赖无法下载. 准备工作 # 如果下载速度很慢, ...
- 面试题:能谈谈Date、Datetime、Time、Timestamp、year的区别吗?
一. 推荐阅读 首发地址:https://mp.weixin.qq.com/s/9zKX86P4kzlKla6-NyS3EA 使用推荐阅读,有更好的阅读体验 二.准备 如果面试官问你:了解 date. ...
- Spider_基础总结5--动态网页抓取--元素审查--json--字典
# 静态网页在浏览器中展示的内容都在HTML的源码中,但主流网页使用 Javascript时,很多内容不出现在HTML的源代码中,此时仍然使用 # requests+beautifulsoup是不能够 ...
- 【】JSON和JSONP
http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html http://www.cnblogs.com/do ...
- 经典c程序100例==71--80
[程序71] 题目:编写input()和output()函数输入,输出5个学生的数据记录. 1.程序分析: 2.程序源代码: #define N 5 struct student { char num ...
- MySQL主从复制的原理和注意事项都在这儿了!!
写在前面 最近在写Mycat专题,由于不少小伙伴最近要出去面试,问我能不能简单写下MySQL的主从复制原理和注意事项,因为在之前的面试中被问到了这些问题.我:可以啊,安排上了!! 主从复制原理 (1) ...
- 四、API Gateway相关------微服务构架设计模式
- TIME_WAIT状态存在的原因
TIME_WAIT状态存在有两个理由: 1.可靠地实现TCP全双工连接的中断 2.允许老的重复分节在网络中消失 第一个理由:如果客户端的ACK丢失了,服务器将会重新发送它的最终的那个FIN,因此客户端 ...