Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之十二 简单把视频的水印去掉效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之十二 简单把视频的水印去掉效果

目录

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之十二 简单把视频的水印去掉效果

一、简单介绍

二、简单把视频的水印去掉效果实现原理

三、简单把视频的水印去掉效果案例实现简单步骤

四、注意事项


一、简单介绍

Python是一种跨平台的计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。Python是一种解释型脚本语言,可以应用于以下领域: Web 和 Internet开发、科学计算和统计、人工智能、教育、桌面界面开发、软件开发、后端开发、网络爬虫。

这里使用 Python  基于 OpenCV 进行视觉图像处理,......

二、简单把视频的水印去掉效果实现原理

去除视频水印是指在视频中移除嵌入的标识、图标、文字或任何其他可视元素的过程。这些水印通常是为了保护知识产权、标识所有权或添加额外信息而添加到视频中的。去除水印可以提高视频的质量和观看体验,特别是当水印影响了视频的内容或美观性时。去除水印的方法通常包括使用图像处理技术,如图像修复、遮罩生成、内容填充等。

实现原理

  • 代码首先获取视频的第一个有效帧,用于选择水印的ROI(感兴趣区域)。
  • 然后用户可以通过交互式界面在视频中选择水印的ROI,以便后续处理。
  • 接着,通过自适应的方法检测水印并生成水印的遮罩。
  • 最后,利用生成的水印遮罩,对视频进行修复,去除水印。

实现方法

  • get_first_valid_frame(video_clip, threshold=10, num_frames=10):获取视频的第一个有效帧,用于选择水印的ROI。它通过计算视频中多个帧的均值来确定第一个有效帧。
  • select_roi_for_mask(video_clip):通过交互式界面在视频中选择水印的ROI,返回水印的ROI坐标和尺寸。
  • detect_watermark_adaptive(frame, roi):自适应检测水印并生成水印的遮罩。它在水印的ROI上应用灰度化和二值化来检测水印。
  • generate_watermark_mask(video_clip, num_frames=10, min_frame_count=7):生成水印的遮罩。它在视频的多个帧中检测水印,并根据水印像素点在至少指定数量的帧中出现的次数来生成最终的水印遮罩。
  • process_video(video_clip, output_path, apply_mask_func):处理视频并保存结果。它将给定的应用遮罩函数应用于视频的每一帧,并将处理后的视频保存到指定路径。

涉及的关键函数及其说明:

  1. get_first_valid_frame(video_clip, threshold=10, num_frames=10)

    • 功能:获取视频的第一个有效帧,用于选择水印的ROI。
    • 参数:
      • video_clip:视频剪辑对象。
      • threshold:判断帧是否有效的阈值,默认为10。
      • num_frames:用于选择的帧的数量,默认为10。
    • 返回值:第一个有效帧的图像数据。
  2. select_roi_for_mask(video_clip)

    • 功能:从视频剪辑中选择水印的ROI。
    • 参数:
      • video_clip:视频剪辑对象。
    • 返回值:水印ROI的坐标和尺寸 (x, y, w, h)。
  3. detect_watermark_adaptive(frame, roi)

    • 功能:自适应检测水印并生成遮罩。
    • 参数:
      • frame:视频帧的图像数据。
      • roi:水印的ROI坐标和尺寸 (x, y, w, h)。
    • 返回值:水印的遮罩图像数据。
  4. generate_watermark_mask(video_clip, num_frames=10, min_frame_count=7)

    • 功能:生成水印的遮罩。
    • 参数:
      • video_clip:视频剪辑对象。
      • num_frames:用于生成遮罩的帧的数量,默认为10。
      • min_frame_count:水印像素点在至少多少帧中出现才被认为是水印,默认为7。
    • 返回值:水印的遮罩图像数据。
  5. process_video(video_clip, output_path, apply_mask_func)

    • 功能:处理视频并保存结果。
    • 参数:
      • video_clip:视频剪辑对象。
      • output_path:输出视频路径。
      • apply_mask_func:应用遮罩的函数。
    • 返回值:无。

三、简单把视频的水印去掉效果案例实现简单步骤

1、编写代码

2、运行效果

操作:1、选择水印区域,2、然后空格或者回车,后台开始去除视频水印

3、具体代码

"""
简单的框选水印位置,移除水印1、代码首先获取视频的第一个有效帧,用于选择水印的ROI(感兴趣区域)。2、然后用户可以通过交互式界面在视频中选择水印的ROI,以便后续处理。3、接着,通过自适应的方法检测水印并生成水印的遮罩。4、最后,利用生成的水印遮罩,对视频进行修复,去除水印。
"""import cv2
import numpy as np
from moviepy.editor import VideoFileClip
import os
from tqdm import tqdmdef get_first_valid_frame(video_clip, threshold=10, num_frames=10):"""获取视频的第一个有效帧,用于选择水印的ROI:param video_clip: 视频剪辑对象:param threshold: 判断帧是否有效的阈值:param num_frames: 用于选择的帧的数量:return: 第一个有效帧的图像数据"""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):"""从视频剪辑中选择水印的ROI:param video_clip: 视频剪辑对象:return: 水印ROI的坐标和尺寸 (x, y, w, h)"""frame = get_first_valid_frame(video_clip)# 将视频帧调整为720p显示display_height = 720scale_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_SIMPLEXcv2.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))return r_originaldef detect_watermark_adaptive(frame, roi):"""自适应检测水印并生成遮罩。:param frame: 视频帧的图像数据:param roi: 水印的ROI坐标和尺寸 (x, y, w, h)。:return: 水印的遮罩图像数据。"""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]] = binary_framereturn maskdef generate_watermark_mask(video_clip, num_frames=10, min_frame_count=7):"""生成水印的遮罩:param video_clip: 视频剪辑对象:param num_frames: 用于生成遮罩的帧的数量:param min_frame_count: 水印像素点在至少多少帧中出现才被认为是水印:return: 水印的遮罩图像数据"""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):"""处理视频并保存结果:param video_clip: 视频剪辑对象:param output_path: 输出视频路径:param apply_mask_func: 应用遮罩的函数:return:"""total_frames = int(video_clip.duration * video_clip.fps)progress_bar = tqdm(total=total_frames, desc="Processing Frames", unit="frames")def process_frame(frame):result = apply_mask_func(frame)progress_bar.update(1000)return resultprocessed_video = video_clip.fl_image(process_frame, apply_to=["each"])processed_video.write_videofile(f"{output_path}.mp4", codec="libx264")if __name__ == "__main__":input_video_path = "Videos/CatRun_Wartermark.mp4"output_video_path = "Videos/CatRun_Wartermark_ToRemove.mp4"watermark_mask = Nonevideo_clip = VideoFileClip(input_video_path)if watermark_mask is None: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(input_video_path)process_video(video_clip, output_video_path, mask_func)print(f"Successfully processed {video_name}")

四、注意事项

  1. 代码中使用了交互式界面让用户选择水印的ROI,因此运行代码时需要有图形界面的支持。
  2. 自适应检测水印的方法在一定程度上能够应对不同类型的水印,但并不是万能的,可能会存在一定的误差。
  3. 在检测水印时,需要根据实际情况调整参数,以获得最佳的检测效果。
  4. 在去除水印时,采用了基于遮罩的修复方法,可能会对图像的质量产生一定的影响,需要根据实际需求权衡。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/310522.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于有序抖动块截断编码的水印嵌入和提取算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 噪声测试 旋转测试 压缩测试 2.算法运行软件版本 matlab2022a 3.部分核心程序 ............................................................…

Day23_学点儿JSON_定义、数据格式、和XML比较、插件

1 JSON定义 定义&#xff1a;是一种轻量级的数据交换格式 JSON是JavaScript Object Notation缩写 特点&#xff1a; 易于程序员阅读和编写。易于计算机解析和生成。其实是javascript的子集&#xff1a;原生javascript支持JSON <script type"text/javascript">…

关于沃进科技无线模块demo软件移植问题

文章目录 一、无线模块开发测试准备二、开发板硬件三、开发板默认功能上电默认界面功能选择界面数据包发送界面数据包接收显示界面射频性能测试界面参数设置界面固件信息显示界面 四、软件开发软件SDK框图1、射频硬件驱动&#xff08;详见./radio/myRadio_gpio.c&#xff09;2、…

【ARM 裸机】汇编 led 驱动之烧写 bin 文件

1、烧写概念 bin 文件烧写到哪里呢&#xff1f;使用 STM32 的时候烧写到内部 FLASH&#xff0c;6ULL 没有内部 FLASH&#xff0c;是不是就不能烧写呢&#xff1f;不&#xff0c;6ULL 支持 SD卡、EMMC、NAND FLASH、NOR FLASH 等方式启动&#xff0c;在裸机学习的工程中&#x…

c语言顺序表的简单介绍

顺序表的分类&#xff1a; 静态顺序表物理结构上呈线性存储&#xff0c;而动态在逻辑结构上呈线性存储&#xff08;何为线性存储&#xff1f;数据按照线性顺序&#xff08;也称为顺序存储&#xff09;排列在连续的存储单元中。&#xff09;动态顺序表当空间不够时可以自行增容&…

三.音视频编辑-音频混合-概述

引言 当我们在前两篇博客中成功地构建了一个媒体组合&#xff0c;并且略过了音频部分时&#xff0c;我们意识到了我们需要对这个项目进行更详细的探讨。在本篇博客中&#xff0c;我们将会展示如何创建一个包含视频轨道、配音音频轨道以及背景音频轨道的完整媒体组合。更进一步…

Python setuptools简介

distutils(包分发的始祖) 简介 distutils 是 Python 的一个标准库&#xff0c;从命名上很容易看出它是一个分发&#xff08;distribute&#xff09;工具&#xff08;utlis&#xff09;&#xff0c;它是 Python 官方开发的一个分发打包工具&#xff0c;所有后续的打包工具&…

Android IPC机制

在Android系统中&#xff0c;IPC&#xff08;Inter-Process Communication&#xff0c;进程间通讯&#xff09;是指在不同进程之间传送数据和通讯的机制。Android中的应用通常运行在独立的沙箱环境中的进程里&#xff0c;由于安全限制&#xff0c;这些进程无法直接访问彼此的内…

【vue】v-bind动态属性绑定

v-bind 简写:value <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><styl…

【深度学习实战(6)】搭建通用的语义分割推理流程

一、代码 #---------------------------------------------------# # 检测图片 #---------------------------------------------------# def detect_image(self, image, countFalse, name_classesNone):#---------------------------------------------------------## 在…

IDEA 找不到或无法加载主类

IDEA 中&#xff0c;有时候会遇到明明存在这个类&#xff0c;import 也没有报错&#xff0c;但编译时会报找不到或无法加载主类。 解决方法&#xff1a; 图像化操作 右侧 Maven > 根项目 > Lifecycle > clean > install 命令操作 mvn clean install

如何更好地理解 Vue 3 watch 侦听器的用法

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Vue error:can not find module ‘@/views/××ב

如果你线上环境遇到这个问题的话&#xff0c;请不要着急 因为我已经踩过坑了&#xff0c;下边咱们说一下这个原因以及解决错失。 从字面上来看是相应路由找不到模块&#xff0c;本地没有问题&#xff0c;线上有问题&#xff0c;就像是本机说话计算机能够理解&#xff0c;而线上…

M系Mac关闭SIP

文章目录 M系Mac关闭SIP一&#xff1a;查看SIP状态二&#xff1a;关闭SIP步骤 M系Mac关闭SIP 一&#xff1a;查看SIP状态 1、使用终端 打开终端 输入csrutil status&#xff0c;回车 你会看到以下信息中的一个&#xff0c;指示SIP状态 已打开 System Integrity Protection s…

康耐视visionpro-CogDistancePointLineTool操作工具详细说明

◆CogDistancePointLineTool:功能说明&#xff1a; 测量点到线的距离 备注&#xff1a;在“Geometry-Measurement”选项中的所有工具都是测量尺寸或角度工具&#xff0c;包括测量线与线的角度、点与线的距离、圆与圆的距离等测量工具&#xff0c;工具使用的方法相似。 ①.打开…

【LeetCode: 3117. 划分数组得到最小的值之和 + 动态规划】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

蓝桥杯 — —灵能传输

灵能传输 友情链接&#xff1a;灵能传输 题目&#xff1a; 输入样例&#xff1a; 3 3 5 -2 3 4 0 0 0 0 3 1 2 3输出样例&#xff1a; 3 0 3思路&#xff1a; 题目大意&#xff1a;给出一个数组&#xff0c;每次选择数组中的一个数&#xff08;要求不能是第一个数与最后一个…

分享一个 git stash 的实际使用场景。

当我将新的变更记录提交为 git commit --amend 后&#xff0c;发现这需要修改云端上的提交记录&#xff0c;也就是 vscode 中会出现这张图 于是&#xff0c;我通过 git reset head^ 撤销掉刚刚的提交。 reset 前&#xff1a; reset 后&#xff1a; 但在撤销的同时&#xf…

设计模式之观察者模式(上)

观察者模式 1&#xff09;概述 1.定义 定义对象之间的一种一对多依赖关系&#xff0c;使得每当一个对象状态发生改变时&#xff0c;其相关依赖对象皆得到通知并被自动更新。 观察者模式的别名包括发布-订阅&#xff08;Publish/Subscribe&#xff09;模式、模型-视图&#…

纯css实现switch开关

代码比较简单&#xff0c;有需要直接在下边粘贴使用吧~ html: <div class"switch-box"><input id"switch" type"checkbox"><label></label></div> css&#xff1a; .switch-box {position: relative;height: 25px…