Python實(shí)現(xiàn)批量添加視頻文本水印
1. 簡(jiǎn)介
這個(gè)是一個(gè)基于PyQt5開(kāi)發(fā)的視頻水印批量添加工具,旨在為多個(gè)視頻文件添加文本水印。用戶可以自定義水印的文本內(nèi)容、字體顏色、字號(hào)大小以及位置(如左上角、右上角、左下角、右下角和中心位置)。程序支持常見(jiàn)的視頻格式,如MP4、AVI、MOV和MKV,并能夠批量處理視頻文件,輸出帶有水印的新視頻。
2.功能介紹
選擇輸入和輸出目錄: 用戶可以通過(guò)文件對(duì)話框選擇視頻文件的輸入目錄和保存帶水印視頻的輸出目錄。
自定義水印文本: 用戶可以在輸入框中填寫水印的文本內(nèi)容,水印會(huì)被添加到視頻上。
自定義水印位置: 水印可以選擇顯示在視頻的不同位置,包括左上角、右上角、左下角、右下角和中心。
自定義水印字體顏色: 用戶可以通過(guò)顏色選擇器來(lái)選擇水印文本的顏色,支持豐富的顏色選擇。
選擇水印字體大?。?提供了多個(gè)字體大小選項(xiàng)(20到100),用戶可以根據(jù)需要選擇合適的字號(hào)。
批量處理視頻: 程序會(huì)遍歷輸入目錄中的所有視頻文件,逐一為其添加水印并保存到輸出目錄。支持的視頻格式包括MP4、AVI、MOV、MKV等。
進(jìn)度條與日志顯示: 程序提供實(shí)時(shí)進(jìn)度條,顯示當(dāng)前視頻處理的進(jìn)度。同時(shí),日志框顯示詳細(xì)的處理信息和錯(cuò)誤提示,幫助用戶實(shí)時(shí)了解處理狀態(tài)。
處理完成提示: 所有視頻處理完成后,會(huì)彈出提示框,告知用戶所有視頻水印已成功添加。
3. 運(yùn)行效果


4.相關(guān)源碼
import os
import time
import cv2
import numpy as np
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QThreadPool, QRunnable, QObject
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QFileDialog, QTextBrowser, QProgressBar, QComboBox, QLabel, QLineEdit, QColorDialog, QMessageBox, QHBoxLayout
from PyQt5.QtGui import QFont
from PIL import Image, ImageDraw, ImageFont
class WatermarkWorker(QObject):
update_log_signal = pyqtSignal(str)
update_progress_signal = pyqtSignal(int)
processing_complete_signal = pyqtSignal()
def __init__(self, input_dir, output_dir, watermark_text, watermark_position, watermark_color, font_size, video_file):
super().__init__()
self.input_dir = input_dir
self.output_dir = output_dir
self.watermark_text = watermark_text
self.watermark_position = watermark_position
self.watermark_color = watermark_color
self.font_size = font_size
self.video_file = video_file
def add_watermark(self):
input_video_path = os.path.join(self.input_dir, self.video_file)
output_video_path = os.path.join(self.output_dir, "watermarked_" + self.video_file)
self.update_log_signal.emit(f"[{self.get_current_time()}] 開(kāi)始處理視頻: {self.video_file}")
cap = cv2.VideoCapture(input_video_path)
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_video_path, fourcc, 30.0, (frame_width, frame_height))
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
processed_frames = 0
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
frame = self.add_text_watermark(frame, self.watermark_text, self.watermark_position, frame_width, frame_height)
out.write(frame)
processed_frames += 1
progress = int((processed_frames / total_frames) * 100)
self.update_progress_signal.emit(progress)
cap.release()
out.release()
self.update_log_signal.emit(f"[{self.get_current_time()}] 水印已添加并保存到: {output_video_path}")
self.update_progress_signal.emit(100)
self.processing_complete_signal.emit()
def add_text_watermark(self, frame, text, position, width, height):
pil_image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(pil_image)
try:
font = ImageFont.truetype("simhei.ttf", self.font_size)
except IOError:
font = ImageFont.load_default()
bbox = draw.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
x, y = 10, 30
if position == "左上角":
x, y = 10, 30
elif position == "右上角":
x, y = width - text_width - 10, 30
elif position == "左下角":
x, y = 10, height - text_height - 10
elif position == "右下角":
x, y = width - text_width - 10, height - text_height - 10
elif position == "中心位置":
x, y = (width - text_width) // 2, (height - text_height) // 2
color = (self.watermark_color.red(), self.watermark_color.green(), self.watermark_color.blue())
draw.text((x, y), text, font=font, fill=color)
return cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
def get_current_time(self):
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
class WatermarkApp(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("視頻水印批量添加軟件")
self.setGeometry(300, 300, 650, 400)
self.input_dir = ""
self.output_dir = ""
self.watermark_text = ""
self.watermark_position = "center"
self.watermark_color = QColor(255, 255, 255)
self.font_size = 30
self.thread_pool = QThreadPool()
self.initUI()
def initUI(self):
main_layout = QHBoxLayout()
left_layout = QVBoxLayout()
self.setStyleSheet("background-color: #F5F5F5;")
self.input_button = QPushButton("選擇視頻輸入目錄")
self.input_button.setStyleSheet("background-color: #4CAF50; color: white; font-size: 14px; padding: 5px;")
self.input_button.clicked.connect(self.select_input_directory)
left_layout.addWidget(self.input_button)
self.output_button = QPushButton("選擇視頻輸出目錄")
self.output_button.setStyleSheet("background-color: #4CAF50; color: white; font-size: 14px; padding: 5px;")
self.output_button.clicked.connect(self.select_output_directory)
left_layout.addWidget(self.output_button)
watermark_layout = QHBoxLayout()
self.watermark_label = QLabel("水印文本:")
self.watermark_label.setStyleSheet("font-size: 14px; color: #333333;")
watermark_layout.addWidget(self.watermark_label)
self.watermark_input = QLineEdit(self)
self.watermark_input.setFont(QFont("Arial", 10))
self.watermark_input.setStyleSheet("padding: 5px; border-radius: 5px; border: 1px solid #ccc;")
self.watermark_input.textChanged.connect(self.update_watermark_text)
watermark_layout.addWidget(self.watermark_input)
left_layout.addLayout(watermark_layout)
self.color_button = QPushButton("選擇字體顏色")
self.color_button.setStyleSheet("background-color: #4CAF50; color: white; font-size: 14px; padding: 5px;")
self.color_button.clicked.connect(self.select_color)
left_layout.addWidget(self.color_button)
font_size_layout = QHBoxLayout()
self.font_size_label = QLabel("選擇字號(hào)大小:")
self.font_size_label.setStyleSheet("font-size: 14px; color: #333333;")
font_size_layout.addWidget(self.font_size_label)
self.font_size_combo = QComboBox(self)
self.font_size_combo.addItem("20")
self.font_size_combo.addItem("30")
self.font_size_combo.addItem("40")
self.font_size_combo.addItem("50")
self.font_size_combo.addItem("60")
self.font_size_combo.addItem("70")
self.font_size_combo.addItem("80")
self.font_size_combo.addItem("90")
self.font_size_combo.addItem("100")
self.font_size_combo.setStyleSheet("padding: 5px; border-radius: 5px; border: 1px solid #ccc;")
self.font_size_combo.currentTextChanged.connect(self.update_font_size)
font_size_layout.addWidget(self.font_size_combo)
left_layout.addLayout(font_size_layout)
position_layout = QHBoxLayout()
self.position_label = QLabel("選擇水印位置:")
self.position_label.setStyleSheet("font-size: 14px; color: #333333;")
self.position_combo = QComboBox(self)
self.position_combo.addItem("左上角")
self.position_combo.addItem("右上角")
self.position_combo.addItem("左下角")
self.position_combo.addItem("右下角")
self.position_combo.addItem("中心位置")
self.position_combo.setStyleSheet("padding: 5px; border-radius: 5px; border: 1px solid #ccc;")
self.position_combo.currentTextChanged.connect(self.update_watermark_position)
position_layout.addWidget(self.position_label)
position_layout.addWidget(self.position_combo)
left_layout.addLayout(position_layout)
self.process_button = QPushButton("添加水印并保存視頻")
self.process_button.setStyleSheet("background-color: #FF5722; color: white; font-size: 14px; padding: 10px;")
self.process_button.clicked.connect(self.add_watermark)
left_layout.addWidget(self.process_button)
self.progress_bar = QProgressBar(self)
self.progress_bar.setRange(0, 100)
self.progress_bar.setValue(0)
self.progress_bar.setTextVisible(True)
self.progress_bar.setStyleSheet("height: 20px; background-color: #ddd;")
left_layout.addWidget(self.progress_bar)
self.log_browser = QTextBrowser(self)
self.log_browser.setStyleSheet("background-color: #F5F5F5; border: 1px solid #ccc; padding: 5px;")
self.log_browser.setFont(QFont("Arial", 10))
main_layout.addLayout(left_layout)
main_layout.addWidget(self.log_browser)
self.setLayout(main_layout)
def select_input_directory(self):
self.input_dir = QFileDialog.getExistingDirectory(self, "選擇輸入目錄")
self.log_browser.append(f"[<font color='red'>{self.get_current_time()}</font>] 選擇的輸入目錄: {self.input_dir}")
def select_output_directory(self):
self.output_dir = QFileDialog.getExistingDirectory(self, "選擇輸出目錄")
self.log_browser.append(f"[<font color='red'>{self.get_current_time()}</font>] 選擇的輸出目錄: {self.output_dir}")
def update_watermark_text(self):
self.watermark_text = self.watermark_input.text()
def update_watermark_position(self):
self.watermark_position = self.position_combo.currentText()
def update_font_size(self):
self.font_size = int(self.font_size_combo.currentText())
def select_color(self):
color = QColorDialog.getColor(self.watermark_color, self, "選擇字體顏色")
if color.isValid():
self.watermark_color = color
self.log_browser.append(f"[<font color='red'>{self.get_current_time()}</font>] 已選擇水印字體顏色: {self.watermark_color.name()}")
def add_watermark(self):
if not self.input_dir or not self.output_dir or not self.watermark_text:
self.log_browser.append(f"[<font color='red'>{self.get_current_time()}</font>] 錯(cuò)誤: 請(qǐng)檢查輸入目錄、輸出目錄和水印文本")
return
video_files = [f for f in os.listdir(self.input_dir) if f.endswith(('.mp4', '.avi', '.mov', '.mkv'))]
for video_file in video_files:
# 創(chuàng)建WatermarkWorker實(shí)例
worker = WatermarkWorker(self.input_dir, self.output_dir, self.watermark_text, self.watermark_position,
self.watermark_color, self.font_size, video_file)
# 連接信號(hào)
worker.update_log_signal.connect(self.log_browser.append)
worker.update_progress_signal.connect(self.progress_bar.setValue)
worker.processing_complete_signal.connect(self.show_completion_message)
# 啟動(dòng)處理
worker.add_watermark()
def show_completion_message(self):
QMessageBox.information(self, "處理完成", "所有視頻水印添加完畢!", QMessageBox.Ok)
def get_current_time(self):
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
if __name__ == '__main__':
app = QApplication([])
window = WatermarkApp()
window.show()
app.exec_()
5. 總結(jié)
這款視頻水印批量添加軟件通過(guò)PyQt5實(shí)現(xiàn)了一個(gè)簡(jiǎn)潔且功能強(qiáng)大的圖形用戶界面,支持對(duì)多個(gè)視頻文件進(jìn)行水印添加。用戶可以輕松自定義水印的各項(xiàng)參數(shù),程序在處理過(guò)程中提供實(shí)時(shí)進(jìn)度條和日志顯示,確保用戶能夠清晰了解每個(gè)視頻的處理狀態(tài)。該工具特別適合需要批量處理視頻并添加水印的用戶,提供了便捷且高效的視頻編輯功能
到此這篇關(guān)于Python實(shí)現(xiàn)批量添加視頻文本水印的文章就介紹到這了,更多相關(guān)Python視頻添加水印內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
實(shí)例解析Python設(shè)計(jì)模式編程之橋接模式的運(yùn)用
這篇文章主要介紹了Python設(shè)計(jì)模式編程之橋接模式的運(yùn)用,橋接模式主張把抽象部分與它的實(shí)現(xiàn)部分分離,需要的朋友可以參考下2016-03-03
在django view中給form傳入?yún)?shù)的例子
今天小編就為大家分享一篇在django view中給form傳入?yún)?shù)的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07
python利用PyQt5設(shè)計(jì)鼠標(biāo)顯示形狀
不知道大家有沒(méi)有發(fā)現(xiàn),我們?cè)诰W(wǎng)頁(yè)移動(dòng)鼠標(biāo)時(shí),不同的網(wǎng)頁(yè)會(huì)有不同的鼠標(biāo)移動(dòng)特效,通過(guò)移動(dòng)鼠標(biāo),會(huì)形成類似蜘蛛網(wǎng)等等的特效,本文將用PyQt5實(shí)現(xiàn)這一特效,需要的可以參考一下2024-07-07
關(guān)于Python Socket編程的要點(diǎn)詳解
Socket是網(wǎng)絡(luò)編程的一個(gè)抽象概念,通常我們用一個(gè)Socket表示“打開(kāi)了一個(gè)網(wǎng)絡(luò)鏈接”,而打開(kāi)一個(gè)Socket需要知道目標(biāo)計(jì)算機(jī)的IP地址和端口號(hào),再指定協(xié)議類型即可,這篇文章主要給大家介紹了關(guān)于Python Socket編程的相關(guān)資料,需要的朋友可以參考下2021-08-08
Django中URL的參數(shù)傳遞的實(shí)現(xiàn)
這篇文章主要介紹了Django中URL的參數(shù)傳遞的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
Python根據(jù)Windows窗口截圖的幾種實(shí)現(xiàn)方法
文章介紹了Windows下Python截圖的四種方法:PIL庫(kù)(簡(jiǎn)單快速)、win32gui(精準(zhǔn)控制窗口)、mss庫(kù)(跨平臺(tái)高性能)及win32API處理隱藏窗口,需注意窗口標(biāo)題匹配、權(quán)限問(wèn)題和DPI縮放調(diào)整,推薦常規(guī)截圖用PIL或mss,需精準(zhǔn)控制時(shí)使用win32API,需要的朋友可以參考下2025-10-10

