离线视频水印清除工具:手动选定位置(ROI)与强制修复功能详解,支持命令行ROI定位

文章目录

仓库基于 WatermarkRemover,由于我是在命令行环境,没有图形化界面,所以 扩展了这个仓库的功能,可以直接手动输入roi的位置 。此外,原项目在roi界面内还有一层水印检测逻辑,由于逻辑过于简单,有时会遗留一些水印,所以我 加入了一层逻辑,直接把roi区域打上mask

仓库概述

这个仓库是 WatermarkRemover-local,是一个基于 LAMA 模型的视频水印移除工具,主要用于批量清除视频中的固定水印。以下是其核心信息介绍:

核心功能

  • 视频水印移除:基于 LAMA 模型实现对视频中固定水印的自动检测和移除,输出处理后的 MP4 格式视频。
  • 本地运行支持:解决原项目依赖模型自动从 Hugging Face Hub 下载的问题,支持离线环境运行(需提前准备模型文件)。
  • 命令行适配:无 GUI 界面,支持通过命令行参数手动指定水印区域(ROI)的坐标(左上角 x/y、宽度、高度),适合 Linux 命令行环境使用。

关键特点

  1. 本地模型部署

    依赖的 LAMA 模型(big-lama.pt)需手动放置到默认路径 ~/.cache/huggingface/hub/,无需在线下载,适配离线环境。

  2. 灵活的 ROI 选择

    • 支持图形化界面框选 ROI(有 GUI 环境时);
    • 命令行环境下可通过 --roi-x--roi-y--roi-width--roi-height 参数指定水印区域,解决无界面场景下的操作问题。
  3. 批量处理:可处理指定目录下的多个视频文件,输出到指定的输出目录。

安装与依赖

  • 系统要求:Python 3.10。
  • 安装步骤
    1. 克隆仓库并进入目录;
    2. 可选:创建并激活虚拟环境;
    3. 安装基础依赖:pip install -r requirements.txt
    4. 安装 PyTorch(CPU 或 GPU 版本,GPU 需配合 NVIDIA 显卡、CUDA 和 cuDNN)。

工作流程

  1. 水印区域选择:通过命令行参数指定或图形化框选水印区域;
  2. 效果预览(可选):显示处理效果,确认后继续或取消;
  3. 视频处理:使用 LAMA 模型对视频帧中的水印区域进行修复;
  4. 输出结果:处理后的视频保存到指定输出目录。

仓库结构

  • 核心代码:watermark_remover.py(实现水印检测、ROI 处理、模型调用等逻辑);
  • 依赖清单:requirements.txt(包含 lama_cleanermoviepyopencv-python 等);
  • 示例图片:image/ 目录下的 origin.jpg(原始帧)和 no_watermark.jpg(去水印后效果);
  • 配置文件:.gitignore(忽略虚拟环境、输出目录等)、LICENSE(许可证文本)。

项目改进

  • 命令行环境下直接输入roi区域
  • 强制将roi设为待修复区域,不进行水印检测

解决命令行环境下无法手动框选 ROI 的问题

以下是基于 watermark_remover.py 现有代码结构的具体修改方案,解决命令行环境无法手动框选ROI的问题:

1. 修改命令行参数解析(parse_args 函数)

在现有参数基础上添加ROI坐标参数,用于指定水印区域的左上角坐标和宽高:

python 复制代码
def parse_args():
    parser = argparse.ArgumentParser(description="Video Watermark Remover")
    parser.add_argument("--input", "-i", type=str, default=".", help="Input directory containing videos")
    parser.add_argument("--output", "-o", type=str, default="output", help="Output directory")
    parser.add_argument("--preview", "-p", action="store_true", help="Preview effect before processing")
    # 新增ROI参数
    parser.add_argument("--roi-x", type=int, help="ROI左上角x坐标 (命令行模式必传)")
    parser.add_argument("--roi-y", type=int, help="ROI左上角y坐标 (命令行模式必传)")
    parser.add_argument("--roi-width", type=int, help="ROI宽度 (命令行模式必传)")
    parser.add_argument("--roi-height", type=int, help="ROI高度 (命令行模式必传)")
    return parser.parse_args()
2. 修改 WatermarkDetector 类以支持命令行ROI

修改 __init__ 方法接收ROI参数,并调整 select_roi 方法优先使用命令行参数:

python 复制代码
class WatermarkDetector:
    # 新增roi参数,默认None
    def __init__(self, num_sample_frames=10, min_frame_count=7, dilation_kernel_size=5, roi=None):
        self.num_sample_frames = num_sample_frames
        self.min_frame_count = min_frame_count
        self.dilation_kernel_size = dilation_kernel_size
        self.roi = roi  # 从外部传入的ROI(命令行参数)
    
    # 修改select_roi方法,优先使用已传入的roi
    def select_roi(self, video_clip):
        # 如果已通过命令行指定ROI,直接返回
        if self.roi is not None:
            return self.roi
        
        # 原有图形化框选逻辑(仅在有GUI的环境下生效)
        frame = self.get_first_valid_frame(video_clip)
        frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)

        display_height = 720
        scale_factor = display_height / frame.shape[0]
        display_width = int(frame.shape[1] * scale_factor)
        display_frame = cv2.resize(frame, (display_width, display_height))

        instructions = "Select ROI and press SPACE or ENTER"
        font = cv2.FONT_HERSHEY_SIMPLEX
        cv2.putText(display_frame, instructions, (10, 30), font, 1, (255, 255, 255), 2, cv2.LINE_AA)

        r = cv2.selectROI(display_frame)
        cv2.destroyAllWindows()

        self.roi = (
            int(r[0] / scale_factor), 
            int(r[1] / scale_factor), 
            int(r[2] / scale_factor), 
            int(r[3] / scale_factor)
        )
        
        return self.roi
3. 在主程序中传递命令行ROI参数

main 函数中解析ROI参数,并传递给 WatermarkDetector

python 复制代码
if __name__ == "__main__":
    args = parse_args()
    
    # 校验命令行ROI参数(必须同时提供4个参数)
    roi = None
    if any([args.roi_x, args.roi_y, args.roi_width, args.roi_height]):
        if not all([args.roi_x, args.roi_y, args.roi_width, args.roi_height]):
            print("Error: --roi-x, --roi-y, --roi-width, --roi-height must be provided together")
            sys.exit(1)
        roi = (args.roi_x, args.roi_y, args.roi_width, args.roi_height)
        print(f"Using command line ROI: {roi}")
    
    # 初始化水印检测器时传入ROI
    watermark_detector = WatermarkDetector(roi=roi)
    watermark_mask = None
    
    # 后续逻辑不变...
    lama_model, lama_config = initialize_lama(device=use_device)
    
    for video in videos:
        print(f"Processing {video}")
        video_clip = VideoFileClip(video)

        # 生成掩码时会自动使用命令行传入的ROI(无需手动框选)
        if watermark_mask is None:
            watermark_mask = watermark_detector.generate_mask(video_clip)
        
        # 禁用预览(命令行环境无法显示窗口)
        if preview_enabled:
            print("Warning: Preview is disabled in command line ROI mode")
            preview_enabled = False
        
        # 后续处理逻辑不变...
4. 禁用命令行模式下的图形化操作

在命令行环境下,cv2.imshowcv2.selectROI 会导致程序崩溃,需确保命令行模式下不执行这些操作:

  • 当通过 --roi-* 参数指定ROI时,自动禁用 --preview(如上述代码中强制 preview_enabled = False
  • 若用户同时传入 --preview--roi-*,打印警告并忽略预览
使用方法

通过命令行直接指定ROI坐标运行(无需图形界面):

bash 复制代码
python watermark_remover.py \
  --input /path/to/videos \
  --output /path/to/output \
  --roi-x 100 \  # 水印区域左上角x坐标
  --roi-y 200 \  # 水印区域左上角y坐标
  --roi-width 300 \  # 水印区域宽度
  --roi-height 150   # 水印区域高度

强制将roi设为待修复区域

从代码逻辑来看,原脚本并非直接对整个选中的ROI区域进行无差别修改,而是在ROI范围内增加了一层"水印检测"逻辑------通过分析采样帧中的像素特征,动态生成"水印掩码"(只标记真正的水印区域),最终只对掩码覆盖的部分进行修复。这就是为什么即使ROI完全覆盖水印,仍可能出现修复不彻底的情况。

原项目逻辑拆解:ROI ≠ 最终修复区域

脚本的核心流程是:
用户指定ROI → 在ROI内检测水印 → 生成"水印掩码" → 只修复掩码覆盖的区域

WatermarkDetector类的generate_mask方法做了这些事:

  1. 采样帧分析:从视频中抽取10帧(默认),聚焦到用户指定的ROI区域;
  2. 水印检测 :对每帧的ROI区域做二值化处理(cv2.threshold),区分"可能是水印"的亮/暗区域(假设水印与背景有明暗差异);
  3. 掩码生成 :只有在至少7帧(默认min_frame_count=7) 中都被检测为"水印"的区域,才会被纳入最终的修复掩码(其他区域即使在ROI内,也不会被修复)。

具体来说:

  • 脚本依赖cv2.threshold(..., cv2.THRESH_BINARY + cv2.THRESH_OTSU)自动区分水印和背景,但如果水印与背景的对比度低(比如半透明水印、颜色接近背景),二值化可能会"漏检"部分帧中的水印;
  • 即使实际每一帧都有水印,但如果采样的10帧中有3帧以上未被检测到(比如因光线变化导致某几帧水印模糊),这部分水印区域会因"出现次数不足7次"被排除在掩码外,最终未被修复。
解决方案:跳过检测,强制修复整个ROI

如果确认ROI内只有水印(无其他重要内容),可以跳过检测逻辑,直接用整个ROI作为掩码。修改方法如下:

  1. 修改generate_mask方法:删除动态检测逻辑,直接生成覆盖整个ROI的掩码
python 复制代码
def generate_mask(self, video_clip):
    if self.roi is None:
        self.select_roi(video_clip)
    
    # 直接生成覆盖整个ROI的掩码(全白,代表整个ROI都需要修复)
    mask = np.zeros((video_clip.h, video_clip.w), dtype=np.uint8)
    x, y, w, h = self.roi
    mask[y:y+h, x:x+w] = 255  # 整个ROI区域标记为需要修复
    
    # 保持原有的膨胀操作,让修复边缘更平滑
    kernel = np.ones((self.dilation_kernel_size, self.dilation_kernel_size), np.uint8)
    dilated_mask = cv2.dilate(mask, kernel, iterations=2)
    
    return dilated_mask
  1. 效果:无论水印与背景的对比度如何,整个ROI区域都会被LAMA模型修复,避免因检测漏检导致的残留。
  2. roi确认工具 :系统自带「画图」(Paint)。无需安装,随系统自带,适合快速查看。用「画图」打开图片,鼠标移动到目标位置,状态栏左下角会显示当前坐标(格式:X: xxx Y: xxx)。
相关推荐
说私域2 小时前
基于开源链动2+1模式AI智能名片S2B2C商城小程序的线上向线下导流运营研究
人工智能·小程序·开源
hljqfl2 小时前
traffic-filter,traffic-secure和traffic-policy的区别
网络·智能路由器
Charlo2 小时前
Open-AutoGLM Windows 安装部署教程
算法·设计模式·github
骥龙2 小时前
3.11、终端安全最后一道屏障:EDR 原理与 Evil-WinRM 实战
网络·安全·网络安全
彡皮2 小时前
VMware没有网络问题解决
网络·虚拟机
Hy行者勇哥2 小时前
虚拟机性能优化实战:卡顿解决与效率提升全指南
网络
爬山算法2 小时前
Netty(2)Netty的核心组件是什么?
网络
EAIReport2 小时前
合规风控:自动数据分析软件如何满足等保2.0要求
网络·数据挖掘·数据分析
AI即插即用2 小时前
即插即用系列 | CVPR 2024 FADC:频域自适应空洞卷积,完美解决语义分割“网格效应”
图像处理·人工智能·深度学习·目标检测·计算机视觉·视觉检测