相关命令:
# 基础依赖包
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')