☞ ░ 前往老猿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 即可。

注意:

百度云上分享的《咖啡狗免费工具软件共享空间》下的不同软件安装时必须解压到不同目录,如果解压到同一目录可能有冲突导致不能正常运行,但解压后遵循如下要求可以将其聚合到同一个目录:

  1. 放置到同一目录的不同软件的版本必须相同,版本为压缩文件名中VX.X标注;
  2. 聚合拷贝时除拷贝执行文件外,还有resource目录必须拷贝,如果resource目录下有相同文件名可以覆盖;
  3. 聚合拷贝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的图形化工具实现的更多相关文章

  1. Python音视频开发:消除抖音短视频Logo和去电视台标

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 对于带Logo(如抖音Logo.电视台标)的视频,有三种方案进行Logo消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...

  2. from appium import webdriver 使用python爬虫,批量爬取抖音app视频(requests+Fiddler+appium)

    使用python爬虫,批量爬取抖音app视频(requests+Fiddler+appium) - 北平吴彦祖 - 博客园 https://www.cnblogs.com/stevenshushu/p ...

  3. 使用Flutter开发的抖音国际版

    简介 最近花了两天时间研究使用Flutter开发一个抖音国际版. 先上图,个人感觉使用Flutter开发app快得不要不要的额.  两天就基本可以开发个大概出来.   最主要是热更新,太方便实时调整U ...

  4. Moviepy音视频开发:视频转gif动画或jpg图片exe图形化工具开发案例

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 老猿之所以学习和研究Moviepy的使用,是因为需要一个将视频转成动画的工具,当时在网上到处搜索查找免费使用工具,结果找了很多自称免费的工具,但转完 ...

  5. Moviepy音视频开发:开发视频转gif动画或jpg图片exe图形化工具的案例

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 老猿之所以学习和研究Moviepy的使用,是因为需要一个将视频转成动画的工具,当时在网上到处搜索查找免费使用工具,结果找了很多自称免费的工具,但转完 ...

  6. JavaWeb-SpringBoot(抖音)_一、抖音项目制作

    JavaWeb-SpringBoot(抖音)_一.抖音项目制作 传送门 JavaWeb-SpringBoot(抖音)_二.服务器间通讯 传送门 JavaWeb-SpringBoot(抖音)_三.抖音项 ...

  7. JavaWeb-SpringBoot(抖音)_三、抖音项目后续

    JavaWeb-SpringBoot(抖音)_一.抖音项目制作 传送门 JavaWeb-SpringBoot(抖音)_二.服务器间通讯 传送门 JavaWeb-SpringBoot(抖音)_三.抖音项 ...

  8. 最快1天搭建短视频APP!阿里云短视频解决方案上线

    短视频行业的发展前景乐观是毋庸置疑的,整个短视频的市场规模一直在增长,网络数据显示2018年已经突破100亿大关,在2019年预测将超过200亿.那么,对于短视频从业者来讲,要持续推动业务的发展,必须 ...

  9. Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 对于带Logo(如抖音Logo.电视台标)的视频,有三种方案进行Logo消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...

随机推荐

  1. c++ 从vector扩容看noexcept应用场景

    c++11提供了关键字noexcept,用来指明某个函数无法--或不打算--抛出异常: void foo() noexcept; // a function specified as will nev ...

  2. 【Kata Daily 190917】Numericals of a String(字符出现的次数)

    题目: You are given an input string. For each symbol in the string if it's the first character occuren ...

  3. php 导出excel 10万数据

    php导出excel 10万数据(此代码主要测试用) 在工作当中要对一些基本信息和其他信息导出 起初信息比较小无所谓.... 但当信息超出65535的时候 发现点问题了 超出了 而且 反应速度很慢 实 ...

  4. 2、CPU详解

    一.五大组成单元 => 三大核心组件 组成计算机五大单元可以合并成三大核心组件:CPU.IO设备.主存储器 1.控制单元+算数逻辑单元 => CPU 2.主存储器,即主记忆体 3.输入单元 ...

  5. DTU的工作原理和流程

    DTU是无线数据传输模块,采用2G,3G,4G网络,将本地串口数据经DTU打包成TCP或者UDP数据进行远程传输的设备.使用方便.已经在各行业远程数据传输,设备监控等领域大量应用.如智能仪器仪表.智能 ...

  6. git clone克隆github仓库慢,问题解决

    导读 转载自:https://www.hangge.com/blog/cache/detail_2670.html 原因     由于国内网络问题,当我们使用 git clone 命令从 github ...

  7. 调试HotSpot源代码(配视频)

    本文将详细介绍在Ubuntu16.04 LTS上对OpenJDK8进行编译,为了方便大家快速搭建起OpenJDK8的调试开发环境,我还录制了对应的视频放到了B站上,大家可以参考. 视频地址:https ...

  8. epoll oneshot

    /* Epoll private bits inside the event mask */#define EP_PRIVATE_BITS (EPOLLWAKEUP | EPOLLONESHOT | ...

  9. 【linux】gpio子系统

    目录 前言 linux子系统 gpio子系统 gpio子系统实战-系统调用 前言 目前不涉及驱动源码 参考链接 linux子系统 在 Linux 系统中 绝大多数硬件设备都有非常成熟的驱动框架 驱动工 ...

  10. 常见mysql后台线程

     1.IO THREAD  MySQL有很多后台线程 其中包括了负责IO的相关线程IO THREAD 1. 参数innodb_write_io_threads  写线程 默认四个,负责数据块的写入 2 ...