视频去水印

我爱海鲸 2025-10-09 23:08:03 暂无标签

简介py、opencv

相关命令:

# 基础依赖包
pip install opencv-python numpy pillow pytesseract -i https://pypi.tuna.tsinghua.edu.cn/simple

# 或者分开安装(如果上面命令有问题)
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install pillow -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install pytesseract -i https://pypi.tuna.tsinghua.edu.cn/simple

基础视频处理(必须)
pip install opencv-python numpy -i https://pypi.tuna.tsinghua.edu.cn/simple

OCR文字识别(可选)
pip install pytesseract pillow -i https://pypi.tuna.tsinghua.edu.cn/simple

 音频处理(必须)
# 确保系统已安装 ffmpeg
# Windows: 下载 ffmpeg 并添加到 PATH
# Linux: sudo apt install ffmpeg
# Mac: brew install ffmpeg

创建一个 requirements.txt 文件:

opencv-python>=4.5.0
numpy>=1.21.0
Pillow>=8.0.0
pytesseract>=0.3.8

pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

pip install opencv-python numpy pillow pytesseract -i https://pypi.tuna.tsinghua.edu.cn/simple

1、选择水印位置并显示坐标

import cv2

def quick_area_select(video_path):
    """
    极简交互式选择 - 最快速有效的方法
    """
    cap = cv2.VideoCapture(video_path)
    ret, frame = cap.read()
    cap.release()

    if ret:
        roi = cv2.selectROI("拖动选择'需要视频的私聊我'文字区域,按空格确认", frame)
        cv2.destroyAllWindows()

        if roi[2] > 0 and roi[3] > 0:
            x, y, w, h = map(int, roi)
            print(f"\n✅ 水印区域坐标:")
            print(f"({x}, {y}, {w}, {h})")
            return (x, y, w, h)

    return None

# 直接使用
position = quick_area_select("1.mp4")

2、在视频60秒的位置显示该帧:

import cv2

def quick_area_select_at_60s(video_path):
    """
    在60秒位置显示帧进行交互式选择
    """
    cap = cv2.VideoCapture(video_path)

    if not cap.isOpened():
        print("错误:无法打开视频文件")
        return None

    # 获取视频信息
    fps = cap.get(cv2.CAP_PROP_FPS)
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    total_duration = total_frames / fps

    print(f"视频信息: {fps:.2f}fps, 总时长: {total_duration:.2f}秒")

    # 计算60秒对应的帧
    target_frame = int(60 * fps)

    # 确保目标帧在范围内
    if target_frame >= total_frames:
        print(f"❌ 60秒超出视频范围(最大 {total_duration:.2f}秒)")
        cap.release()
        return None

    # 跳转到60秒位置
    cap.set(cv2.CAP_PROP_POS_FRAMES, target_frame)
    ret, frame = cap.read()
    cap.release()

    if not ret:
        print("❌ 无法读取60秒位置的帧")
        return None

    print("✅ 成功跳转到60秒位置")

    # 在图像上显示时间信息
    display_frame = frame.copy()
    cv2.putText(display_frame, f"Time: 60.0s - Drag to select text area, press SPACE to confirm",
                (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)

    # 选择区域
    roi = cv2.selectROI("60秒位置 - 拖动选择'需要视频的私聊我'文字区域,按空格确认", display_frame, showCrosshair=True)
    cv2.destroyAllWindows()

    if roi[2] > 0 and roi[3] > 0:
        x, y, w, h = map(int, roi)
        print(f"\n✅ 水印区域坐标 (60秒位置):")
        print(f"({x}, {y}, {w}, {h})")
        return (x, y, w, h)

    return None

# 直接使用
position = quick_area_select_at_60s("1.mp4")

3、直接在坐标位置打马赛克:

import cv2
import numpy as np
import subprocess
import os

def remove_watermark_with_ffmpeg_audio(input_path, output_path, watermark_rect):
    """
    使用OpenCV处理视频,用ffmpeg合并音频
    """
    # 处理视频(无音频)
    temp_video = "temp_video_no_audio.mp4"
    temp_audio = "temp_audio.aac"

    # 先用OpenCV处理视频
    remove_watermark_from_video(input_path, temp_video, watermark_rect)

    # 使用ffmpeg提取音频
    extract_audio_cmd = [
        'ffmpeg', '-i', input_path, '-vn', '-acodec', 'copy', temp_audio, '-y'
    ]

    # 合并视频和音频
    merge_cmd = [
        'ffmpeg', '-i', temp_video, '-i', temp_audio,
        '-c', 'copy', '-map', '0:v:0', '-map', '1:a:0',
        output_path, '-y'
    ]

    try:
        print("正在提取音频...")
        subprocess.run(extract_audio_cmd, check=True, capture_output=True)

        print("正在合并音频...")
        subprocess.run(merge_cmd, check=True, capture_output=True)

        # 清理临时文件
        if os.path.exists(temp_video):
            os.remove(temp_video)
        if os.path.exists(temp_audio):
            os.remove(temp_audio)

        print(f"处理完成!输出文件: {output_path}")

    except subprocess.CalledProcessError as e:
        print(f"FFmpeg处理出错: {e}")

# 修改原来的函数,返回临时文件路径
def remove_watermark_from_video(input_path, output_path, watermark_rect):
    """
    使用OpenCV去除视频水印(不包含音频)
    """
    cap = cv2.VideoCapture(input_path)

    if not cap.isOpened():
        print("错误:无法打开视频文件")
        return False

    fps = cap.get(cv2.CAP_PROP_FPS)
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))

    frame_count = 0
    while True:
        ret, frame = cap.read()
        if not ret:
            break

        processed_frame = remove_watermark_from_frame(frame, watermark_rect)
        out.write(processed_frame)

        frame_count += 1
        if frame_count % 30 == 0:
            print(f"处理进度: {frame_count}帧")

    cap.release()
    out.release()
    return True

def remove_watermark_from_frame(frame, watermark_rect):
    x, y, w, h = watermark_rect

    if (x >= 0 and y >= 0 and
            x + w <= frame.shape[1] and
            y + h <= frame.shape[0]):

        roi = frame[y:y+h, x:x+w]

        # 方法1: 更强的模糊效果
        # 增大模糊核大小 (51,51) 比 (25,25) 更模糊
        blurred_roi = cv2.GaussianBlur(roi, (51, 51), 0)
        frame[y:y+h, x:x+w] = blurred_roi

    return frame

# 使用示例
if __name__ == "__main__":
    input_video = "1.mp4"
    output_video = "2.mp4"
    watermark_area = (626, 337, 306, 42)

    remove_watermark_with_ffmpeg_audio(input_video, output_video, watermark_area)

4、去除智能水印:

import cv2
import numpy as np
import subprocess
import os

def remove_watermark_content_aware(frame, watermark_rect):
    """
    智能内容感知填充(模拟Photoshop的内容感知填充)
    """
    x, y, w, h = watermark_rect

    if (x >= 0 and y >= 0 and
            x + w <= frame.shape[1] and
            y + h <= frame.shape[0]):

        # 扩展修复区域
        expand = 8
        x1 = max(0, x - expand)
        y1 = max(0, y - expand)
        x2 = min(frame.shape[1], x + w + expand)
        y2 = min(frame.shape[0], y + h + expand)
        expanded_w = x2 - x1
        expanded_h = y2 - y1

        # 创建掩码
        mask = np.zeros(frame.shape[:2], dtype=np.uint8)
        cv2.rectangle(mask, (x1, y1), (x2, y2), 255, -1)

        # 多次修复以获得更好效果
        result_frame = frame.copy()
        for radius in [3, 5, 7]:  # 尝试不同的修复半径
            temp_result = cv2.inpaint(result_frame, mask, radius, cv2.INPAINT_NS)

            # 只更新修复区域
            repair_region = temp_result[y1:y2, x1:x2]
            result_frame[y1:y2, x1:x2] = repair_region

        return result_frame

    return frame

def remove_watermark_background_reconstruction(frame, watermark_rect):
    """
    通过采样周围背景来重建水印区域
    """
    x, y, w, h = watermark_rect

    if (x >= 0 and y >= 0 and
            x + w <= frame.shape[1] and
            y + h <= frame.shape[0]):

        # 采样水印周围的背景区域
        sample_width = 10  # 采样宽度

        # 上方采样区域
        top_sample = frame[max(0, y-sample_width):y, x:x+w]
        # 下方采样区域
        bottom_sample = frame[y+h:min(frame.shape[0], y+h+sample_width), x:x+w]
        # 左侧采样区域
        left_sample = frame[y:y+h, max(0, x-sample_width):x]
        # 右侧采样区域
        right_sample = frame[y:y+h, x+w:min(frame.shape[1], x+w+sample_width)]

        result_frame = frame.copy()

        # 重建水印区域
        if top_sample.size > 0 and bottom_sample.size > 0:
            # 使用上下采样的渐变填充
            for i in range(h):
                # 计算垂直位置的权重
                top_weight = (h - i) / h
                bottom_weight = i / h

                # 混合上下采样区域的颜色
                if top_sample.shape[0] > 0 and bottom_sample.shape[0] > 0:
                    top_color = np.mean(top_sample, axis=0)
                    bottom_color = np.mean(bottom_sample, axis=0)
                    blended_color = top_color * top_weight + bottom_color * bottom_weight
                    result_frame[y+i, x:x+w] = blended_color.astype(np.uint8)

        return result_frame

    return frame

def remove_watermark_advanced_inpainting(frame, watermark_rect):
    """
    改进的图像修复方法
    """
    x, y, w, h = watermark_rect

    if (x >= 0 and y >= 0 and
            x + w <= frame.shape[1] and
            y + h <= frame.shape[0]):

        # 扩展修复区域,避免边缘痕迹
        expand = 5
        x1 = max(0, x - expand)
        y1 = max(0, y - expand)
        x2 = min(frame.shape[1], x + w + expand)
        y2 = min(frame.shape[0], y + h + expand)

        # 创建更柔和的掩码
        mask = np.zeros(frame.shape[:2], dtype=np.uint8)
        cv2.rectangle(mask, (x1, y1), (x2, y2), 255, -1)

        # 对掩码进行模糊,使边缘过渡更自然
        mask_blurred = cv2.GaussianBlur(mask, (5, 5), 0)

        # 使用NS算法(更适合大区域修复)
        inpainted_frame = cv2.inpaint(frame, mask_blurred, 5, cv2.INPAINT_NS)

        return inpainted_frame

    return frame

import cv2
import numpy as np
import subprocess
import os

def remove_watermark_with_inpainting(input_path, output_path, watermark_rect):
    """
    使用图像修复技术真正去除水印,而不是模糊
    """
    # 处理视频(无音频)
    temp_video = "temp_video_no_audio.mp4"
    temp_audio = "temp_audio.aac"

    # 先用OpenCV处理视频
    remove_watermark_with_inpainting_video(input_path, temp_video, watermark_rect)

    # 使用ffmpeg提取音频
    extract_audio_cmd = [
        'ffmpeg', '-i', input_path, '-vn', '-acodec', 'copy', temp_audio, '-y'
    ]

    # 合并视频和音频
    merge_cmd = [
        'ffmpeg', '-i', temp_video, '-i', temp_audio,
        '-c', 'copy', '-map', '0:v:0', '-map', '1:a:0',
        output_path, '-y'
    ]

    try:
        print("正在提取音频...")
        subprocess.run(extract_audio_cmd, check=True, capture_output=True)

        print("正在合并音频...")
        subprocess.run(merge_cmd, check=True, capture_output=True)

        # 清理临时文件
        if os.path.exists(temp_video):
            os.remove(temp_video)
        if os.path.exists(temp_audio):
            os.remove(temp_audio)

        print(f"处理完成!输出文件: {output_path}")

    except subprocess.CalledProcessError as e:
        print(f"FFmpeg处理出错: {e}")

def remove_watermark_with_inpainting_video(input_path, output_path, watermark_rect):
    """
    使用图像修复技术处理视频
    """
    cap = cv2.VideoCapture(input_path)

    if not cap.isOpened():
        print("错误:无法打开视频文件")
        return False

    fps = cap.get(cv2.CAP_PROP_FPS)
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))

    frame_count = 0
    while True:
        ret, frame = cap.read()
        if not ret:
            break

        processed_frame = remove_watermark_inpainting(frame, watermark_rect)
        out.write(processed_frame)

        frame_count += 1
        if frame_count % 30 == 0:
            print(f"处理进度: {frame_count}帧")

    cap.release()
    out.release()
    return True

def remove_watermark_inpainting(frame, watermark_rect):
    """
    使用图像修复算法去除水印
    """
    x, y, w, h = watermark_rect

    if (x >= 0 and y >= 0 and
            x + w <= frame.shape[1] and
            y + h <= frame.shape[0]):

        # 创建掩码(标记需要修复的区域)
        mask = np.zeros(frame.shape[:2], dtype=np.uint8)
        mask[y:y+h, x:x+w] = 255

        # 方法1: 使用Telea算法进行图像修复
        inpainted_frame = cv2.inpaint(frame, mask, 3, cv2.INPAINT_TELEA)

        return inpainted_frame

    return frame

def remove_watermark_clean(input_path, output_path, watermark_rect, method='inpainting'):
    """
    真正去除水印而不是打马赛克

    参数:
    - method: 修复方法
        'inpainting': 图像修复(推荐)
        'advanced_inpainting': 改进修复
        'background': 背景重建
        'content_aware': 内容感知
    """
    temp_video = "temp_video_no_audio.mp4"
    temp_audio = "temp_audio.aac"

    # 使用指定的修复方法处理视频
    if method == 'inpainting':
        remove_watermark_with_inpainting_video(input_path, temp_video, watermark_rect)
    elif method == 'advanced_inpainting':
        remove_watermark_advanced_method(input_path, temp_video, watermark_rect)
    # elif method == 'background':
    #     remove_watermark_background_method(input_path, temp_video, watermark_rect)
    # elif method == 'content_aware':
    #     remove_watermark_content_method(input_path, temp_video, watermark_rect)

    # 合并音频
    try:
        # 提取音频
        subprocess.run([
            'ffmpeg', '-i', input_path, '-vn', '-acodec', 'copy', temp_audio, '-y'
        ], check=True, capture_output=True)

        # 合并
        subprocess.run([
            'ffmpeg', '-i', temp_video, '-i', temp_audio,
            '-c', 'copy', '-map', '0:v:0', '-map', '1:a:0',
            output_path, '-y'
        ], check=True, capture_output=True)

        # 清理
        if os.path.exists(temp_video):
            os.remove(temp_video)
        if os.path.exists(temp_audio):
            os.remove(temp_audio)

        print(f"✅ 水印去除完成!输出文件: {output_path}")

    except subprocess.CalledProcessError as e:
        print(f"FFmpeg处理出错: {e}")

def remove_watermark_advanced_method(input_path, output_path, watermark_rect):
    """使用改进的修复方法"""
    cap = cv2.VideoCapture(input_path)
    fps = cap.get(cv2.CAP_PROP_FPS)
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))

    frame_count = 0
    while True:
        ret, frame = cap.read()
        if not ret:
            break

        processed_frame = remove_watermark_advanced_inpainting(frame, watermark_rect)
        out.write(processed_frame)

        frame_count += 1
        if frame_count % 30 == 0:
            print(f"处理进度: {frame_count}帧")

    cap.release()
    out.release()

# 使用示例
if __name__ == "__main__":
    input_video = "1.mp4"
    output_video = "2_clean.mp4"
    watermark_area = (626, 337, 306, 42)

    # 推荐使用图像修复方法
    remove_watermark_clean(input_video, output_video, watermark_area, method='inpainting')

 

你好:我的2025