使用python 去除视频中的水印
1. 需要安装的包
pip install moviepy
pip install numpy
pip install opencv_python
pip install tqdm
2. 代码
import cv2
import numpy as np
import glob
from moviepy.editor import VideoFileClip
import os
from tqdm import tqdm
# 判断输入是否为视频
def is_valid_video_file(file):
try:
with VideoFileClip(file) as video_clip:
return True
except Exception as e:
print(f"Invalid video file: {file}, Error: {e}")
return False
def get_first_valid_frame(video_clip, threshold=10, num_frames=10):
total_frames = int(video_clip.fps * video_clip.duration)
frame_indices = [int(i * total_frames / num_frames) for i in range(num_frames)]
for idx in frame_indices:
frame = video_clip.get_frame(idx / video_clip.fps)
if frame.mean() > threshold:
return frame
return video_clip.get_frame(0)
def select_roi_for_mask(video_clip):
frame = get_first_valid_frame(video_clip)
# 将视频帧调整为720p显示
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()
r_original = (int(r[0] / scale_factor), int(r[1] / scale_factor), int(r[2] / scale_factor), int(r[3] / scale_factor))
print("r_original: ", r_original)
return r_original
#return (18, 28, 230, 43)
def detect_watermark_adaptive(frame, roi):
roi_frame = frame[roi[1]:roi[1] + roi[3], roi[0]:roi[0] + roi[2]]
gray_frame = cv2.cvtColor(roi_frame, cv2.COLOR_BGR2GRAY)
_, binary_frame = cv2.threshold(gray_frame, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
mask = np.zeros_like(frame[:, :, 0], dtype=np.uint8)
mask[roi[1]:roi[1] + roi[3], roi[0]:roi[0] + roi[2]] = 255 #binary_frame
return mask
def generate_watermark_mask(video_clip, num_frames=10, min_frame_count=7):
total_frames = int(video_clip.duration * video_clip.fps)
frame_indices = [int(i * total_frames / num_frames) for i in range(num_frames)]
frames = [video_clip.get_frame(idx / video_clip.fps) for idx in frame_indices]
r_original = select_roi_for_mask(video_clip)
masks = [detect_watermark_adaptive(frame, r_original) for frame in frames]
final_mask = sum((mask == 255).astype(np.uint8) for mask in masks)
# 根据像素点在至少min_frame_count张以上的帧中的出现来生成最终的遮罩
final_mask = np.where(final_mask >= min_frame_count, 255, 0).astype(np.uint8)
kernel = np.ones((5, 5), np.uint8)
return cv2.dilate(final_mask, kernel)
def process_video(video_clip, output_path, apply_mask_func):
total_frames = int(video_clip.duration * video_clip.fps)
progress_bar = tqdm(total=total_frames, desc="Processing Frames", unit="frames")
#num=0
def process_frame(frame):
result = apply_mask_func(frame)
progress_bar.update(1000)
#global num
#num += 1
#result.save('0%5d.png' % num)
return result
processed_video = video_clip.fl_image(process_frame, apply_to=["each"])
processed_video.write_videofile(f"{output_path}.mp4", codec="libx264")
if __name__ == "__main__":
video = "1476212253-1-192.mp4"
output_video_path = "output/1476212253-1-192.mp4"
if is_valid_video_file(video):
video_clip = VideoFileClip(video)
watermark_mask = generate_watermark_mask(video_clip)
mask_func = lambda frame: cv2.inpaint(frame, watermark_mask, 3, cv2.INPAINT_NS)
video_name = os.path.basename(video)
process_video(video_clip, output_video_path, mask_func)
print(f"Successfully processed {video_name}")
3. 运行
使用鼠标框选水印,回车继续。
开始处理
4. 完成后效果对比
去除前:
1476212253-1-192_o
去除后:
1476212253-1-192.mp4