Python 视频水印批量添加器

功能如下可以

一、选择水印位置

二、批量添加水印

三、可添加文本或图片

复制代码
# -*- 编码:utf-8 -*-
import cv2
import os
import numpy as np
from moviepy.editor import VideoFileClip
from concurrent.futures import ThreadPoolExecutor
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import ImageFont, ImageDraw, Image
 
 
def add_dynamic_watermarks_with_audio(video_path, output_path, watermark_image_paths, watermark_sizes, watermark_speeds,
add_text_watermark, text_watermark_text, text_watermark_color,
text_watermark_position):
try:
video_clip = VideoFileClip(video_path)
audio_clip = video_clip.audio
width, height = video_clip.size
 
if add_text_watermark:
font_path = "msyh.ttc" # Windows字体路径,可以根据需要更改
font_size = 50
font = ImageFont.truetype(font_path, font_size)
text_watermark_canvas = np.zeros((高度,宽度,3),dtype=np.uint8)
text_pil = 图像.fromarray(text_watermark_canvas)
绘制 = ImageDraw.Draw(text_pil)
text_bbox = draw.textbbox((0, 0), text_watermark_text, font=font)
text_width = text_bbox[2] - text_bbox[0]
text_height = text_bbox[3] - text_bbox[1]
 
如果 text_watermark_position == "中心":
text_x = (宽度 - text_width) / 2
text_y = (高度 - text_height) / 2
elif text_watermark_position == "左上":
text_x = 10
text_y = 10
elif text_watermark_position == "右上":
text_x = 宽度 - text_width - 10
text_y = 10
elif text_watermark_position == "左下":
text_x = 10
text_y = 高度 - text_height - 10
elif text_watermark_position == "右下":
text_x = 宽度 - text_width - 10
text_y = 高度 - text_height - 10
 
draw.text((text_x, text_y), text_watermark_text, font=font, fill=text_watermark_color)
text_watermark_canvas = np.array(text_pil)
 
watermark_positions = [(0, 0)] * len(watermark_image_paths)
 
def process_frame(t, x):
非本地 watermark_positions
frame = video_clip.get_frame(t)
 
for i in range(len(watermark_image_paths)):
watermark_image_path = watermark_image_paths[i]
watermark_size = watermark_sizes[i]
watermark_speed = watermark_speeds[i]
watermark_image = cv2.imread(watermark_image_path)
 
watermark_height, watermark_width, _ = watermark_image.shape
如果宽度或watermark_height >高度watermark_width >:
scale_factor = min(宽度 / watermark_width, 高度 / watermark_height)
watermark_image = cv2.resize(watermark_image, (
int(watermark_width * scale_factor), int(watermark_height * scale_factor)),
interpolation=cv2.INTER_LINEAR)
 
if t % watermark_speed == 0:
while True:
x = np.random.randint(0, width - watermark_image.shape[1])
y = np.random.randint(0, height - watermark_image.shape[0])
too_close = 范围 (i) 中 j 的 False
 
:
dist = np.sqrt((x - watermark_positions[j][0]) ** 2 + (y - watermark_positions[j][1]) ** 2)
if dist < watermark_image.shape[1] 或 dist < watermark_image.shape[0]:
too_close = True
break
 
if not too_close:
watermark_positions[i] = (x, y)
break
else:
x, y = watermark_positions[i]
 
watermark_resized = cv2.resize(watermark_image, (
int(watermark_size * watermark_width), int(watermark_size * watermark_height)))
alpha = watermark_resized[:, :, 0] / 255.0
for c in range(3):
frame[y: y + watermark_resized.shape[0], x: x + watermark_resized.shape[1], c] = (
frame[y: y + watermark_resized.shape[0], x: x + watermark_resized.shape[1], c] * (1 - alpha)
+ watermark_resized[:, :, c] * alpha
)
 
if add_text_watermark:
frame_with_text = cv2.addWeighted(frame, 1, text_watermark_canvas, 0.7, 0)
frame = frame_with_text
 
返回帧
 
processed_clip = video_clip.fl(lambda gf, t: process_frame(t, gf))
final_clip = processed_clip.set_audio(audio_clip)
final_clip.write_videofile(output_path, codec='libx264', audio_codec="aac")
 
return "水印添加完成!"
except Exception as e:
print(f"处理视频时出错 {video_path}: {e}")
return f"处理视频 {video_path} 时出错:{e}"
 
 
def batch_add_watermarks_in_directory_with_audio(directory, output_directory, watermark_image_paths, watermark_sizes,
watermark_speeds, add_text_watermark=False, text_watermark_text=None,
text_watermark_position='右下'):
file_list = os.listdir(directory)
video_files = [文件在file_list if file.lower().endswith(('.avi', '.mp4', '.mov', '.mkv'))]
 
将 ThreadPoolExecutor() 作为执行器:
futures = []
for file_name in video_files:
file_path = os.path.join(directory, file_name)
output_file_path = os.path.join(output_directory, file_name)
futures.append(executor.submit(
add_dynamic_watermarks_with_audio,
file_path, output_file_path, watermark_image_paths, watermark_sizes, watermark_speeds,
add_text_watermark, text_watermark_text, (255, 255, 255), text_watermark_position
))
 
for future in futures:
result = future.result()
print(result)
 
return "批量处理完成!"
 
 
def select_directory(entry):
directory =filedialog.askdirectory()
entry.delete(0, tk.END)
entry.insert(0, directory)
 
 
def select_files(entry, file_list, size_list, speed_list):
files = filedialog.askopenfilenames(filetypes=[("Image files", "*.png;*.jpg;*.jpeg")])
for file in files:
file_list.append(file)
entry.insert(tk.END, file)
size_list.append(float(input(f"请输入水印图片{file}的大小(0~1之间):")))
speed_list.append(int(input(f"请输入水印图片{file}的速度:"))))def
 
 
start_processing():
directory = input_dir_entry.get()
output_directory = output_dir_entry.get()
os.makedirs(output_directory, exist_ok=True)
 
add_text_watermark = text_watermark_var.get()
text_watermark_text = text_watermark_entry.get() 如果add_text_watermark其他 None text_watermark_position
= text_watermark_position_var.get()
 
batch_add_watermarks_in_directory_with_audio(
directory, output_directory, watermark_image_paths, watermark_sizes, watermark_speeds, add_text_watermark,
text_watermark_text, text_watermark_position
)
 
messagebox.showinfo("完成", "批量处理完成!")
 
 
root = tk.Tk()
root.title("视频水印批量添加器")
 
tk.Label(root, text="输入目录:").grid(row=0, column=0)
input_dir_entry = tk.Entry(root, width=50)
input_dir_entry.grid(row=0, column=1)
tk.Button(root, text="选择", command=lambda: select_directory(input_dir_entry)).grid(row=0, column=2)
 
tk.Label(root, text="输出目录:").grid(row=1, column=0)
output_dir_entry = tk.Entry(root, width=50)
output_dir_entry.grid(row=1, column=1)
tk.Button(root, text="选择", command=lambda: select_directory(output_dir_entry)).grid(row=1, column=2)
 
tk.Label(root, text="水印图片:").grid(row=2, column=0)
watermark_image_listbox = tk.Listbox(root, width=50)
watermark_image_listbox.grid(row=2, column=1)
watermark_image_paths = []
watermark_sizes = []
watermark_speeds = []
tk。Button(root, text="添加",
command=lambda: select_files(watermark_image_listbox, watermark_image_paths, watermark_sizes,
watermark_speeds)).grid(row=2, column=2)
 
text_watermark_var = tk.BooleanVar()
tk 中。Checkbutton(root, text="添加文本水印", variable=text_watermark_var).grid(row=3, column=0)
text_watermark_entry = tk.Entry(root, width=50)
text_watermark_entry.grid(row=3, column=1)
 
tk.Label(root, text="文本水印位置:").grid(row=4, column=0)
text_watermark_position_var = tk.StringVar(value="右下")
text_watermark_position_options = ["左上", "右上", "左下", "右下", "中心"]
text_watermark_position_menu = tk.OptionMenu(root, text_watermark_position_var, *text_watermark_position_options)
text_watermark_position_menu.grid(row=4, column=1)
 
tk。Button(root, text="开始处理", command=start_processing).grid(row=5, column=0, columnspan=3)
 
root.mainloop()
相关推荐
励志要当大牛的小白菜39 分钟前
ART配对软件使用
开发语言·c++·qt·算法
mortimer2 小时前
安装NVIDIA Parakeet时,我遇到的两个Pip“小插曲”
python·github
@昵称不存在3 小时前
Flask input 和datalist结合
后端·python·flask
爱装代码的小瓶子3 小时前
数据结构之队列(C语言)
c语言·开发语言·数据结构
赵英英俊3 小时前
Python day25
python
东林牧之4 小时前
Django+celery异步:拿来即用,可移植性高
后端·python·django
何双新4 小时前
基于Tornado的WebSocket实时聊天系统:从零到一构建与解析
python·websocket·tornado
源码_V_saaskw4 小时前
JAVA图文短视频交友+自营商城系统源码支持小程序+Android+IOS+H5
java·微信小程序·小程序·uni-app·音视频·交友
Maybe_ch4 小时前
.NET-键控服务依赖注入
开发语言·c#·.net
超浪的晨4 小时前
Java UDP 通信详解:从基础到实战,彻底掌握无连接网络编程
java·开发语言·后端·学习·个人开发