Implementing video watermark removal based on python

When we move videos, we often encounter the problem of video watermarks
as follows

The following uses python to remove video watermarks

Create a new project in pycharm and create the image and video directories. No other need exists


Necessary conditions

Download related dependency packages in the terminal

pip install moviepy==1.0.3
pip installnumpy==1.21.5
pip install opencv_python==4.5.5.62

Place the video you want to remove the watermark in the video directory and run it        

Use the mouse to remove the part and press Enter.

The video with the watermark removed is output to the output folder.

Check the effect, not bad 

 

Code

import us
import sys

import cv2
import numpy
from moviepy import editor

VIDEO_PATH = 'video'
OUTPUT_PATH = 'output'
TEMP_VIDEO = 'temp.mp4'

class WatermarkRemover():
  
  def __init__(self, threshold: int, kernel_size: int):
    self.threshold = threshold #Threshold used for threshold segmentation
    self.kernel_size = kernel_size #Expansion operation core size
  
  def select_roi(self, img: numpy.ndarray, hint: str) -> list:
    '''
    Frame select the watermark or subtitle position, press SPACE or ENTER to exit
    :param img: display image
    :return: coordinates of the selected area
    '''
    MEMORY = 0.7
    w, h = int(MEMORY * img.shape[1]), int(MEMORY * img.shape[0])
    resize_img = cv2.resize(img, (w, h))
    roi = cv2.selectROI(hint, resize_img, False, False)
    cv2.destroyAllWindows()
    watermark_roi = [int(roi[0] / MEMORY), int(roi[1] / MEMORY), int(roi[2] / MEMORY), int(roi[3] / MEMORY)]
    return watermark_roi

  def dilate_mask(self, mask: numpy.ndarray) -> numpy.ndarray:
    
    '''
    Dilate the mask
    :param mask: mask image
    :return: mask after expansion processing
    '''
    kernel = numpy.ones((self.kernel_size, self.kernel_size), numpy.uint8)
    mask = cv2.dilate(mask, kernel)
    return mask

  def generate_single_mask(self, img: numpy.ndarray, roi: list, threshold: int) -> numpy.ndarray:
    '''
    Generating a watermark mask of a single frame image from a manually selected ROI area
    :param img: single frame image
    :param roi: Manually select area coordinates
    :param threshold: Binarization threshold
    :return: watermark mask
    '''
    #The area is invalid and the program exits
    if len(roi) != 4:
      print('NULL ROI!')
      sys.exit()
    
    #Copy the pixels in the ROI of a single frame grayscale image
    roi_img = numpy.zeros((img.shape[0], img.shape[1]), numpy.uint8)
    start_x, end_x = int(roi[1]), int(roi[1] + roi[3])
    start_y, end_y = int(king[0]), int(king[0] + king[2])
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    roi_img[start_x:end_x, start_y:end_y] = gray[start_x:end_x, start_y:end_y]

    #threshold segmentation
    _, mask = cv2.threshold(roi_img, threshold, 255, cv2.THRESH_BINARY)
    return mask

  def generate_watermark_mask(self, video_path: str) -> numpy.ndarray:
    '''
    Intercept multiple frames of images in the video to generate multiple watermark masks, and generate the final watermark mask through logic and calculation.
    :param video_path: video file path
    :return: watermark mask
    '''
    video = cv2.VideoCapture(video_path)
    success, frame = video.read()
    roi = self.select_roi(frame, 'select watermark ROI')
    mask = numpy.ones((frame.shape[0], frame.shape[1]), numpy.uint8)
    mask.fill(255)

    step = video.get(cv2.CAP_PROP_FRAME_COUNT) // 5
    index = 0
    while success:
      if index % step == 0:
        mask = cv2.bitwise_and(mask, self.generate_single_mask(frame, roi, self.threshold))
      success, frame = video.read()
      index += 1
    video.release()

    return self.dilate_mask(mask)

  def generate_subtitle_mask(self, frame: numpy.ndarray, roi: list) -> numpy.ndarray:
    '''
    Generate single-frame image subtitle masks by manually selecting ROI areas
    :param frame: single frame image
    :param roi: Manually select area coordinates
    :return: subtitle mask
    '''
    mask = self.generate_single_mask(frame, [0, roi[1], frame.shape[1], roi[3]], self.threshold) #Only use the ROI abscissa area
    return self.dilate_mask(mask)

  def inpaint_image(self, img: numpy.ndarray, mask: numpy.ndarray) -> numpy.ndarray:
    '''
    Repair image
    :param img: single frame image
    :parma mask: mask
    :return: Repaired image
    '''
    telea = cv2.inpaint(img, mask, 1, cv2.INPAINT_TELEA)
    return a lot
  
  def merge_audio(self, input_path: str, output_path: str, temp_path: str):
    '''
    Merge audio and processed video
    :param input_path: Original video file path
    :param output_path: file path after encapsulating audio and video
    :param temp_path: Silent video file path
    '''
    with editor.VideoFileClip(input_path) as video:
      audio = video.audio
      with editor.VideoFileClip(temp_path) as opencv_video:
        clip = opencv_video.set_audio(audio)
        clip.to_videofile(output_path)

  def remove_video_watermark(self):
    '''
    Remove video watermark
    '''
    if not os.path.exists(OUTPUT_PATH):
      os.makedirs(OUTPUT_PATH)

    filenames = [os.path.join(VIDEO_PATH, i) for i in os.listdir(VIDEO_PATH)]
    mask = None

    for i, name in enumerate(filenames):
      if i == 0:
        #Generate watermark mask
        mask = self.generate_watermark_mask(name)

      #Create file object to be written
      video = cv2.VideoCapture(name)
      fps = video.get(cv2.CAP_PROP_FPS)
      size = (int(video.get(cv2.CAP_PROP_FRAME_WIDTH)), int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)))
      video_writer = cv2.VideoWriter(TEMP_VIDEO, cv2.VideoWriter_fourcc(*'mp4v'), fps, size)
    
      #Process images frame by frame
      success, frame = video.read()

      while success:
        frame = self.inpaint_image(frame, mask)
        video_writer.write(frame)
        success, frame = video.read()

      video.release()
      video_writer.release()

      #packagevideo
      (_, filename) = os.path.split(name)
      output_path = os.path.join(OUTPUT_PATH, filename.split('.')[0] + '_no_watermark.mp4')#Output file path
      self.merge_audio(name, output_path, TEMP_VIDEO)
  
  if os.path.exists(TEMP_VIDEO):
    os.remove(TEMP_VIDEO)

  def remove_video_subtitle(self):
    '''
    Remove video subtitles
    '''
    if not os.path.exists(OUTPUT_PATH):
      os.makedirs(OUTPUT_PATH)

    filenames = [os.path.join(VIDEO_PATH, i) for i in os.listdir(VIDEO_PATH)]
    roi = []

    for i, name in enumerate(filenames):
      #Create file object to be written
      video = cv2.VideoCapture(name)
      fps = video.get(cv2.CAP_PROP_FPS)
      size = (int(video.get(cv2.CAP_PROP_FRAME_WIDTH)), int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)))
      video_writer = cv2.VideoWriter(TEMP_VIDEO, cv2.VideoWriter_fourcc(*'mp4v'), fps, size)
    
      #Process images frame by frame
      success, frame = video.read()
      if i == 0:
        roi = self.select_roi(frame, 'select subtitle ROI')

      while success:
        mask = self.generate_subtitle_mask(frame, roi)
        frame = self.inpaint_image(frame, mask)
        video_writer.write(frame)
        success, frame = video.read()

      video.release()
      video_writer.release()

      #packagevideo
      (_, filename) = os.path.split(name)
      output_path = os.path.join(OUTPUT_PATH, filename.split('.')[0] + '_no_sub.mp4')#Output file path
      self.merge_audio(name, output_path, TEMP_VIDEO)

    if os.path.exists(TEMP_VIDEO):
      os.remove(TEMP_VIDEO)

if __name__ == '__main__':
  #Remove video watermark
  remover = WatermarkRemover(threshold=80, kernel_size=5)
  remover.remove_video_watermark()

  #Remove video subtitles
  remover = WatermarkRemover(threshold=80, kernel_size=10)
  remover.remove_video_subtitle()

Guess you like

Origin blog.csdn.net/m0_70638653/article/details/131105162