? ? 前往老猿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博文目錄 ?
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/2819.html
標籤:其他
上一篇:專案實戰:Qt+Ffmpeg+OpenCV相機程式(打開攝像頭、支持多種攝像頭、解析度調整、翻轉、旋轉、亮度調整、拍照、錄像、回放圖片、回放錄像)
