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消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...
随机推荐
- [Codeforces 580D]Fizzy Search(FFT)
[Codeforces 580D]Fizzy Search(FFT) 题面 给定母串和模式串,字符集大小为4,给定k,模式串在某个位置匹配当且仅当任意位置模式串的这个字符所对应的母串的位置的左右k个字 ...
- IAuthorizationFilter学习笔记(权限控制)以及非全局的filter
第一步:新建类CheckLoginFilter实现接口IAuthorizationFilter.请注意接口位于命名空间using System.Web.Mvc; public void OnAutho ...
- 跟我一起学Redis之Redis事务简单了解一下
前言 关系数据库中的事务,小伙伴们应该是不陌生了,不管是在开发还是在面试过程中,总有两个问题逃不掉: 说说事务的特性: 事务隔离级别是怎么一回事? 事务处理不好,数据就可能不准确,最终就会导致业务出问 ...
- 一致性(ECMAScript语法标准翻译)
Conformance A conforming implementation of ECMAScript must provide and support all the types, values ...
- 92. Reverse Linked List II 翻转链表II
Reverse a linked list from position m to n. Do it in one-pass. Note: 1 ≤ m ≤ n ≤ length of list. Exa ...
- 02、Hibernate开发步骤
1.创建Hibernate配置文件(hibernate.cfg.xml) <?xml version="1.0" encoding="UTF-8"?> ...
- IDEA 2019.3.3 + Pycharm 2020.2.1 安装包及破解步骤
IDEA IDEA的破解流程就不用再说了,免费试用,添加VMOptions参数,选择破解jar的路径,重启IDEA. 下载地址:链接:https://pan.baidu.com/s/1aTRATVTL ...
- xss攻击与防范
xss攻击方式以及防范 通常来说,网站一般都是有着,用户注册,用户登录,实名认证等等这些需要用户把信息录入数据库的接口 xss找的就是这种接口,他们可以在传递数据的时候,传递恶意的 script ...
- mysql密码问题
这位老哥的: 版权声明:本文为CSDN博主「csdn-华仔」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/ ...
- C#推流RTMP,摄像头、麦克风、桌面、声卡(附源码)
这段时间一直都在研究推流的技术,经过断断续续将近两个月的摸索实践,终于能稳定地推流了. 这个demo的主要功能就是将采集到的摄像头或桌面的视频.以及麦克风或声卡的音频数据推到Nginx-RTMP服务器 ...