1. 从需求到方案:为什么选择Python处理视频水印与字幕
最近在整理一些教学视频和素材时,我遇到了一个挺烦人的问题:从不同平台下载的视频,要么带着硕大的平台水印,要么嵌入了无法关闭的硬字幕。直接裁剪画面会损失内容,用一些在线工具又担心隐私和画质。作为一个习惯用代码解决问题的开发者,我自然把目光投向了Python。你可能也搜过“python 视频水印”或者“豆包视频去水印”,发现网上教程要么太旧,要么只讲个大概,真正自己动手时一堆报错。今天,我就把自己趟过坑的完整方案分享出来,从原理到代码,一步步教你如何用Python实现一个本地化、可定制的视频水印与字幕去除工具。
这个方案的核心价值在于可控和灵活。你不再需要依赖那些功能受限、可能有广告的在线网站,也不用去折腾那些界面复杂、学习成本高的专业软件(比如纠结“pr2025能自动识别字幕吗”)。通过Python脚本,你可以精确控制处理区域(比如只去掉右下角的水印),可以批量处理大量视频,甚至可以根据水印的颜色、透明度等特征进行智能修复。整个过程在本地完成,原始视频数据不会上传到任何第三方服务器,安全又高效。
适合谁来看这篇内容呢?如果你是一个有Python基础(哪怕刚看完“python安装教程”),经常需要处理视频素材的创作者、自媒体人、或者只是单纯想清理个人视频库的技术爱好者,这篇实战指南应该能给你提供一条清晰的路径。我们会用到OpenCV和MoviePy这两个强大的库,它们就像是Python在图像和视频处理领域的“瑞士军刀”。不用担心,即使你对NumPy数组操作还不熟,我也会把关键步骤拆解得足够细。我们不止步于“跑通代码”,更要弄明白“为什么这么做”,以及在实际操作中会遇到哪些“坑”(比如OpenCV读视频的奇怪报错,或者MoviePy处理音频时的内存问题),并给出经过验证的解决方案。
2. 环境搭建与核心工具链选型:避开版本兼容的“天坑”
工欲善其事,必先利其器。第一步就是把环境准备好。这里最大的“坑”往往不是安装本身,而是库版本之间的兼容性问题。你可能按照一篇2021年的教程安装了某个版本,结果在2023年的系统上死活跑不起来,弹出一堆像“Cannot read properties of undefined”或者关于FFmpeg的诡异错误。为了避免大家重复踩坑,我直接给出一个经过验证的、稳定的环境配置方案。
首先,是Python环境。我强烈建议使用Python 3.8到3.10之间的版本。Python 3.11或更高版本在某些科学计算库的预编译轮子上可能支持还不完善,容易出问题。你可以通过python --version检查。如果还没安装,去“python官网”下载安装包,记得勾选“Add Python to PATH”,这是很多新手(搜索“vscode配置python”的人)遇到第一个障碍的地方。
接下来是核心工具链,我们主要依赖两个库:
- OpenCV-Python (
opencv-python): 这是计算机视觉的基石库,我们将用它来读取视频帧、定位水印区域、进行图像修复(去水印)和字幕检测。它的功能强大,但接口偏向底层,需要一些图像处理的基本概念。 - MoviePy (
moviepy): 这是一个基于FFmpeg的高级视频编辑库,封装得非常好用。我们将用它来轻松地剪辑视频、处理音频、以及最终合成输出。它让很多复杂的视频操作变得像操作列表一样简单。
为什么是这两个库的组合?OpenCV擅长像素级的图像分析和处理,比如找到水印的精确位置并把它“抹掉”。而MoviePy擅长视频文件级别的操作,比如无损地提取一段视频、合并音轨、以及用正确的编码格式输出。它们俩分工协作,比单独使用任何一个都更高效。想象一下,OpenCV是精细的外科手术刀,MoviePy是负责整体治疗方案和术后康复的主任医师。
安装命令如下。我强烈建议你使用pip安装时指定版本,以确保兼容性:
pip install opencv-python==4.8.1.78 moviepy==1.0.3 numpy==1.24.3这里有一个至关重要的隐形依赖:FFmpeg。MoviePy和OpenCV的某些视频读写功能背后都需要它。很多人在“pycharm配置python环境”后跑代码,遇到“FFmpeg找不到”的错误,根源就在这里。你需要去FFmpeg官网下载可执行文件,并将其所在目录(比如C:\ffmpeg\bin)添加到系统的环境变量PATH中。添加后,在命令行输入ffmpeg -version,如果能显示版本信息,才算成功。
注意:如果你在后续操作中遇到诸如“
AttributeError: module ‘moviepy.video.fx.all‘ has no attribute ‘crop‘”或关于音频编解码器的错误,90%的可能性是FFmpeg路径没设对,或者MoviePy/OpenCV版本冲突。回退到我上面指定的版本,是最省事的解决办法。
最后是IDE的选择,VSCode或PyCharm都可以。VSCode轻量灵活,需要自己配置“vscode python环境配置”;PyCharm开箱即用,但更吃资源。根据你的习惯来。确保你的IDE解释器指向了刚才安装好这些包的环境。
3. 原理深潜:水印与字幕是如何被“看见”并“移除”的
在写代码之前,我们必须搞清楚背后的原理。这能帮助我们在遇到问题时(比如去水印后画面模糊,或者字幕没去干净)知道该调整哪个“旋钮”,而不是盲目地乱试参数。处理水印和处理字幕,在思路上有共通之处,也有显著区别。
3.1 视频水印的常见类型与应对策略
水印通常是半透明的、位置固定的Logo或文字。它的核心特征是位置和外观在时间维度上高度一致。基于此,我们有两种主流思路:
基于位置和颜色的静态去除:这是最简单直接的方法。如果我们事先知道水印在画面的哪个矩形区域(比如右下角10%的范围),我们可以直接对这个区域进行处理。处理方式又分两种:
- 覆盖/裁剪:用一个纯色块(比如黑色)或从视频其他干净区域复制过来的像素块,直接盖住水印区域。或者,直接裁剪掉包含水印的那部分画面。这种方法简单粗暴,但会永久损失那部分画面信息,适合水印在边缘且内容不重要的场景。
- 图像修复(Inpainting):这是更高级的方法,也是我们重点要实现的。
OpenCV提供了cv2.inpaint()函数。它的原理是:算法将水印区域视为“破损区”,然后利用周围完好的像素信息,根据一定的规则(如快速行进法cv2.INPAINT_TELEA或基于流体动力学的cv2.INPAINT_NS)来推测并填充“破损区”的颜色和纹理。这就好比用周围的墙壁颜色和纹理,去修复墙上的一处涂鸦。这种方法能最大程度保留背景内容,但对复杂、动态的背景效果可能不完美。
基于帧间差异的动态检测与去除:如果水印位置不固定,或者我们不知道其确切位置,就需要先检测它。一个经典思路是利用帧间差分法。水印是静止的,而视频内容是运动的。理论上,连续两帧图像相减,运动的前景会被凸显,而静止的背景(包括水印)则会减弱。通过对多帧差分结果进行统计,就可以大致定位出水印所在的像素区域。但这种方法计算量较大,且对于背景也静止或水印半透明度过高的情况,效果会打折扣。
对于大多数从平台下载的、水印位置固定的视频,我们采用第一种方法中的图像修复技术。难点在于如何精确界定水印的“掩膜”(Mask)。一个实用的技巧是:手动选取一帧,用OpenCV的交互式功能粗略画出水印区域,作为初始掩膜。然后可以对这个掩膜进行膨胀操作,确保完全覆盖水印的边缘。
3.2 视频字幕的识别与处理逻辑
字幕,尤其是硬字幕(内嵌字幕),是视频图像的一部分,其处理比水印更复杂,因为它和背景融合得更紧密,且可能出现的位置不固定(顶部、底部)。
字幕区域检测:我们无法像水印一样假设位置。这里需要借助一些图像特征。字幕通常具有以下特征:
- 高对比度:白色字幕在深色背景上,或者黑色字幕在亮色背景上。
- 成行的文本形状:字符排列成行,具有特定的宽高比和轮廓。
- 出现位置集中:通常位于画面底部或顶部的一个水平带状区域。
我们可以利用
OpenCV进行如下步骤检测:- 帧预处理:将彩色帧转为灰度图,然后进行二值化处理(比如使用自适应阈值
cv2.adaptiveThreshold),让字幕区域变成醒目的白色块,背景变成黑色。 - 轮廓查找:使用
cv2.findContours()查找二值图像中的所有白色轮廓。 - 轮廓过滤:根据轮廓的面积、宽高比、以及其外接矩形在画面中的y坐标(高度位置),过滤出最可能是字幕文本行的轮廓。例如,只保留位于画面下方20%区域内,且宽度大于高度若干倍的轮廓。
- 区域合并:将检测到的多个文本行轮廓的外接矩形,合并成一个大矩形,这就是字幕区域。
字幕区域处理:检测到区域后,处理方式和水印类似,主要是图像修复。但字幕区域的修复挑战更大,因为字幕背景可能是变化的(电影镜头从暗场景切换到亮场景)。单纯修复可能导致修复区域与周围背景过渡不自然。一种改进策略是,不仅修复字幕像素,还对修复区域进行轻微的高斯模糊或边缘融合,使其与周围背景的纹理和颜色变化更平滑。
实操心得:在实际处理中,没有任何一种检测算法是100%准确的。你可能会遇到将画面中某些条状物体误判为字幕的情况。因此,一个健壮的程序应该允许人工复核和调整检测参数(如二值化阈值、轮廓面积下限等)。我的经验是,先用手动框选几帧字幕区域,统计其典型的高度和位置,然后用这个统计信息去约束自动检测算法,能极大提高准确率。
4. 实战代码拆解:构建你的去水印与字幕工具
理论说得再多,不如一行代码。接下来,我们分模块构建这个工具。我会先给出去除固定位置水印的完整示例,然后再扩展到字幕检测与去除。请确保你已经完成了第二部分的环境搭建。
4.1 核心模块一:去除固定位置水印
这个函数接受视频路径、水印区域坐标、以及输出路径,完成去水印任务。
import cv2 import numpy as np from moviepy.editor import VideoFileClip import os def remove_watermark_fixed(video_path, output_path, watermark_rect, method='inpaint'): """ 去除视频中固定位置的水印。 参数: video_path: 输入视频文件路径。 output_path: 输出视频文件路径。 watermark_rect: 水印区域,格式为 (x, y, width, height)。 method: 去除方法,'inpaint'为图像修复,'cover'为覆盖,'crop'为裁剪。 """ # 使用OpenCV读取视频 cap = cv2.VideoCapture(video_path) if not cap.isOpened(): print(f"错误:无法打开视频文件 {video_path}") return # 获取视频基本信息 fps = int(cap.get(cv2.CAP_PROP_FPS)) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 根据方法调整输出尺寸(如果是裁剪) out_width, out_height = width, height if method == 'crop': # 假设裁剪掉水印区域,这里需要重新计算画幅,逻辑略复杂,本例暂不展开 # 通常需要用户提供裁剪后的目标区域 pass # 定义视频写入器 fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 或 'avc1' out = cv2.VideoWriter('temp_no_watermark.mp4', fourcc, fps, (out_width, out_height)) frame_count = 0 x, y, w, h = watermark_rect print(f"开始处理视频,总帧数约:{total_frames}") while True: ret, frame = cap.read() if not ret: break frame_count += 1 if frame_count % 30 == 0: # 每处理30帧打印一次进度 print(f"处理进度: {frame_count}/{total_frames}") # 处理水印区域 if method == 'inpaint': # 创建掩膜:水印区域为白色(255),其他区域为黑色(0) mask = np.zeros(frame.shape[:2], dtype=np.uint8) mask[y:y+h, x:x+w] = 255 # 为了修复效果更好,可以稍微扩大掩膜区域,确保覆盖水印边缘 kernel = np.ones((3,3), np.uint8) mask = cv2.dilate(mask, kernel, iterations=1) # 使用图像修复算法 # INPAINT_TELEA 速度较快,INPAINT_NS 质量可能稍好 inpainted_frame = cv2.inpaint(frame, mask, inpaintRadius=3, flags=cv2.INPAINT_TELEA) processed_frame = inpainted_frame elif method == 'cover': # 简单覆盖:用水印区域周围像素的平均颜色进行覆盖(简单示例,也可用固定色) # 获取水印区域上方的一小条像素的平均颜色 sample_height = 5 if y > sample_height: sample_area = frame[y-sample_height:y, x:x+w] avg_color = np.mean(sample_area, axis=(0,1)).astype(np.uint8) frame[y:y+h, x:x+w] = avg_color processed_frame = frame elif method == 'crop': # 裁剪逻辑(需要更复杂的处理,本例暂不实现完整裁剪重编码) processed_frame = frame else: processed_frame = frame out.write(processed_frame) cap.release() out.release() print("视频帧处理完成,正在重新封装音频...") # 使用MoviePy合并原视频音频和处理后的无声视频 try: # 读取原始视频的音频 original_clip = VideoFileClip(video_path) audio = original_clip.audio # 读取我们刚生成的无声音频视频 video_clip = VideoFileClip('temp_no_watermark.mp4') # 将音频设置到新视频上 final_clip = video_clip.set_audio(audio) # 输出最终视频 final_clip.write_videofile(output_path, codec='libx264', audio_codec='aac') # 关闭所有clip,释放资源 original_clip.close() video_clip.close() final_clip.close() # 删除临时文件 os.remove('temp_no_watermark.mp4') print(f"处理完成!输出文件:{output_path}") except Exception as e: print(f"音频合并过程中发生错误:{e}")如何使用这个函数?假设你的水印在视频右下角,坐标区域是(宽度-200, 高度-80, 180, 60)(即从离右边200像素、离底边80像素开始,宽180,高60的区域)。你可以这样调用:
# 你需要先获取视频的实际宽高,这里假设是1920x1080 video_height = 1080 video_width = 1920 watermark_area = (video_width - 200, video_height - 80, 180, 60) remove_watermark_fixed('input_video.mp4', 'output_no_watermark.mp4', watermark_area, method='inpaint')踩坑提醒:
cv2.VideoWriter生成的中间视频temp_no_watermark.mp4默认可能使用MP4V编解码器,某些播放器兼容性不好。这只是中间文件,最终由MoviePy用libx264重新编码,所以不用担心。另外,图像修复cv2.inpaint是一个计算密集型操作,处理高清视频会非常慢。强烈建议先截取视频的一小段(比如前10秒)进行测试,确认水印区域坐标和方法效果,再处理全片。
4.2 核心模块二:动态检测并去除字幕
接下来是更复杂的字幕去除。我们将实现一个自动检测字幕区域并修复的函数。
def detect_and_remove_subtitles(video_path, output_path, subtitle_region='bottom', confidence_threshold=0.5): """ 自动检测并去除视频中的硬字幕。 参数: video_path: 输入视频路径。 output_path: 输出视频路径。 subtitle_region: 字幕大致区域,'bottom' 或 'top'。 confidence_threshold: 轮廓面积置信度阈值,用于过滤小噪点。 """ cap = cv2.VideoCapture(video_path) fps = int(cap.get(cv2.CAP_PROP_FPS)) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 根据字幕区域设定检测范围,减少计算量 if subtitle_region == 'bottom': roi_y_start = int(height * 0.7) # 检测画面底部30%的区域 roi_y_end = height else: # 'top' roi_y_start = 0 roi_y_end = int(height * 0.3) # 检测画面顶部30%的区域 # 读取一些帧来“学习”字幕的稳定位置 sample_frames = [] sample_count = 10 for _ in range(sample_count): ret, frame = cap.read() if ret: sample_frames.append(frame) else: break if not sample_frames: print("无法读取视频帧") return # 分析样本帧,确定字幕的公共区域 all_contour_rects = [] for frame in sample_frames: # 1. 截取感兴趣区域(ROI) roi = frame[roi_y_start:roi_y_end, :] gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) # 2. 自适应二值化,增强字幕与背景的对比度 # 使用高斯自适应阈值,对光照不均更有效 binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) # 反转,让文字成为白色前景 binary = cv2.bitwise_not(binary) # 3. 形态学操作,连接相邻的文字像素 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 2)) # 水平方向连接 morphed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel) # 4. 查找轮廓 contours, _ = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 5. 过滤轮廓:基于面积和宽高比 for cnt in contours: area = cv2.contourArea(cnt) x, y, w, h = cv2.boundingRect(cnt) aspect_ratio = w / h if h > 0 else 0 # 过滤条件:面积足够大,且宽高比符合文本特征(宽远大于高) if area > 100 and aspect_ratio > 2: # 将ROI坐标转换回原图坐标 x_abs = x y_abs = y + roi_y_start all_contour_rects.append((x_abs, y_abs, w, h)) cap.release() if not all_contour_rects: print("未检测到可能的字幕区域。") # 可以在这里退回手动指定区域 return # 6. 合并所有检测到的矩形,得到字幕的大致区域 # 简单方法:取所有矩形在x方向的最小/最大值,在y方向的最小/最大值 all_rects_np = np.array(all_contour_rects) x_min = np.min(all_rects_np[:, 0]) y_min = np.min(all_rects_np[:, 1]) x_max = np.max(all_rects_np[:, 0] + all_rects_np[:, 2]) y_max = np.max(all_rects_np[:, 1] + all_rects_np[:, 3]) # 给区域一些扩展边距 margin = 5 subtitle_rect = (max(0, x_min - margin), max(0, y_min - margin), min(width, x_max + margin) - max(0, x_min - margin), min(height, y_max + margin) - max(0, y_min - margin)) print(f"检测到的字幕区域为:{subtitle_rect}") # 7. 使用之前的水印去除函数,对检测到的区域进行修复 # 注意:这里我们直接调用修复功能,但为了效率,可以重写一个只处理该区域的循环 # 为了简化,我们复用 remove_watermark_fixed 的逻辑,但只处理检测到的区域 # 由于 remove_watermark_fixed 是完整流程,这里我们重新打开视频处理 remove_watermark_fixed(video_path, output_path, subtitle_rect, method='inpaint')这个函数的工作流程是:先采样一些帧,通过图像处理技术检测出字幕文本的轮廓,将这些轮廓的边界框合并,得到一个覆盖所有字幕的“大区域”,然后对这个大区域进行图像修复。这种方法对于位置相对固定、对比度明显的字幕效果很好。
实操心得:
adaptiveThreshold的参数(11, 2)不是银弹。对于背景非常复杂或字幕半透明的视频,你需要调整这两个值。11是块大小,必须是奇数,它决定了局部区域的大小。2是从平均值中减去的常数,用于微调二值化阈值。如果字幕检测不全,尝试减小块大小或调整常数。反之,如果误检了很多背景噪点,就增大块大小。这是一个需要根据你的具体视频进行“调参”的过程。
5. 高级技巧与性能优化:让脚本真正实用起来
基础的跑通只是第一步。要想让这个工具真正高效、实用地处理你的视频库,还需要考虑更多。
5.1 批量处理与进度反馈
没有人愿意一个个手动处理视频。我们可以很容易地扩展脚本,使其能遍历一个文件夹下的所有视频文件。
import glob def batch_process_videos(input_folder, output_folder, watermark_rect=None, process_type='watermark'): """ 批量处理文件夹中的视频。 参数: input_folder: 输入视频所在文件夹。 output_folder: 输出视频保存文件夹。 watermark_rect: 水印区域,如果为None且process_type='subtitle',则尝试自动检测。 process_type: 'watermark' 或 'subtitle'。 """ if not os.path.exists(output_folder): os.makedirs(output_folder) # 支持常见视频格式 video_extensions = ['*.mp4', '*.avi', '*.mov', '*.mkv', '*.flv'] video_files = [] for ext in video_extensions: video_files.extend(glob.glob(os.path.join(input_folder, ext))) for i, video_path in enumerate(video_files): print(f"\n正在处理 ({i+1}/{len(video_files)}): {os.path.basename(video_path)}") output_path = os.path.join(output_folder, f"processed_{os.path.basename(video_path)}") if process_type == 'watermark' and watermark_rect: remove_watermark_fixed(video_path, output_path, watermark_rect) elif process_type == 'subtitle': detect_and_remove_subtitles(video_path, output_path) else: print(f"跳过 {video_path},参数配置不正确。")5.2 性能瓶颈分析与优化
处理视频,尤其是高清视频,最大的敌人是时间。图像修复(Inpainting)是算法中最耗时的部分。以下是一些优化思路:
- 降低分辨率处理:如果输出视频不需要原始分辨率,可以先将帧缩放(如缩小到50%),在低分辨率下进行修复操作,然后再放大回原尺寸。这能极大减少计算量,虽然会损失一些细节,但对于水印/字幕这种小区域处理,效果往往可以接受。可以使用
cv2.resize(frame, None, fx=0.5, fy=0.5)。 - 跳帧处理:对于水印,由于其静态性,不一定需要每一帧都修复。可以每隔N帧(比如5帧)修复一次,中间帧的水印区域直接用上一帧修复好的结果填充。这会导致快速运动场景下水印区域可能出现“拖影”,但对于静态或慢速场景的视频很有效。
- 并行处理:视频帧的处理是相互独立的,非常适合并行化。可以使用Python的
concurrent.futures库或multiprocessing模块,将视频分片,交给多个进程同时处理,最后再合并。不过,这需要处理帧顺序和文件写入的同步问题,复杂度较高。 - 使用GPU加速:
OpenCV的部分操作如果编译时启用了CUDA支持,可以利用GPU加速。但这对环境配置要求较高。对于绝大多数用户,前两种软件优化方法更实际。
5.3 处理失败案例与兜底方案
不是所有视频都能完美处理。可能会遇到:
- 水印/字幕半透明且颜色复杂:修复后区域可能出现色块或模糊。这时可以尝试结合
cover方法,用区域周围像素进行纹理合成,而不是简单的颜色平均。OpenCV没有直接的内置函数,但可以通过克隆算法(cv2.seamlessClone)尝试,不过需要更精细的掩膜。 - 检测完全失败:对于艺术字体、与背景颜色接近的字幕,自动检测可能失效。兜底方案就是手动指定区域。我们可以写一个简单的交互程序,用
OpenCV的cv2.selectROI函数让用户在第一帧上手动框选水印或字幕区域,然后将这个坐标用于后续所有帧的处理。 - 音频流丢失或不同步:这是使用
OpenCV写视频再与MoviePy音频合并时常见的问题。确保在cv2.VideoWriter中使用的fps和原视频完全一致。如果仍出现问题,可以尝试用MoviePy直接进行逐帧处理,虽然慢,但音视频同步更可靠。
# 手动选择ROI的示例代码片段 def manual_select_roi(video_path): cap = cv2.VideoCapture(video_path) ret, frame = cap.read() if ret: # 显示第一帧,让用户框选 roi = cv2.selectROI("请框选水印或字幕区域,按Enter确认,按ESC取消", frame, fromCenter=False) cv2.destroyAllWindows() cap.release() return roi # 返回 (x, y, w, h) cap.release() return None把这个函数集成到你的流程中,当自动检测失败时,调用它获取手动坐标,然后继续处理。
6. 完整项目整合与使用指南
现在,我们将所有模块整合到一个脚本中,并提供一个简单的命令行界面,让它看起来像一个真正的工具。
# video_cleaner.py import argparse import sys def main(): parser = argparse.ArgumentParser(description='Python视频水印与字幕去除工具') parser.add_argument('input', help='输入视频文件或文件夹路径') parser.add_argument('-o', '--output', default='./output', help='输出文件或文件夹路径(默认./output)') parser.add_argument('-t', '--type', choices=['watermark', 'subtitle'], required=True, help='处理类型:watermark(固定水印) 或 subtitle(硬字幕)') parser.add_argument('--rect', help='手动指定区域,格式为 \"x,y,width,height\"。适用于水印或检测失败时。') parser.add_argument('--method', choices=['inpaint', 'cover'], default='inpaint', help='修复方法:inpaint(修复)或cover(覆盖),默认inpaint') args = parser.parse_args() # 解析区域 rect = None if args.rect: try: x, y, w, h = map(int, args.rect.split(',')) rect = (x, y, w, h) except ValueError: print("错误:区域格式不正确,请使用 'x,y,width,height' 格式。") sys.exit(1) # 判断输入是文件还是文件夹 if os.path.isfile(args.input): # 单文件处理 if args.type == 'watermark': if not rect: print("错误:处理水印需通过 --rect 参数指定区域,或使用交互模式(未实现)。") sys.exit(1) remove_watermark_fixed(args.input, args.output, rect, method=args.method) elif args.type == 'subtitle': if rect: # 如果提供了区域,直接按该区域处理(视为手动指定字幕区域) remove_watermark_fixed(args.input, args.output, rect, method=args.method) else: detect_and_remove_subtitles(args.input, args.output) elif os.path.isdir(args.input): # 批量处理 if args.type == 'watermark' and rect: batch_process_videos(args.input, args.output, watermark_rect=rect, process_type='watermark') elif args.type == 'subtitle': batch_process_videos(args.input, args.output, process_type='subtitle') else: print("错误:批量处理水印需指定区域,批量处理字幕将尝试自动检测。") else: print(f"错误:输入路径 '{args.input}' 不存在。") if __name__ == '__main__': main()使用方式:
处理单个视频水印(已知水印在(100,100,200,50)):
python video_cleaner.py input.mp4 -o output.mp4 -t watermark --rect "100,100,200,50"处理单个视频字幕(自动检测):
python video_cleaner.py input.mp4 -o output.mp4 -t subtitle批量处理一个文件夹内所有视频的字幕:
python video_cleaner.py ./videos_folder -o ./cleaned_videos -t subtitle
这个脚本只是一个起点,你可以根据自己的需求继续扩展,比如增加预览功能、调整修复参数、支持更多视频格式、或者集成一个简单的图形界面。最重要的是,通过这个项目,你不仅学会了如何用Python处理视频,更掌握了面对一个实际问题时,从分析、选型、编码、调试到优化的完整思考路径。这种能力,远比单纯复制一段代码更有价值。