MP4如何让去水印?python带你实现~

news2024/11/29 10:32:47

前言

嗨喽,大家好呀~这里是爱看美女的茜茜呐

开发环境:

  • 解释器版本: python 3.8

  • 代码编辑器: pycharm 2021.2

模块使用:

内置模块(无需安装)

  • os —> python系统编程的操作模块,提供了非常丰富的功能去处理文件和目录

  • sys —> 是与Python解释器交互的桥梁

  • cv2 —> 流行的开源计算机视觉库,提供了丰富的图像和视频处理功能

第三方模块

  • numpy —> 用于数值计算的基础模块,支持大量的维度数值与矩阵计算

  • moviepy —> 用于视频剪辑、合成和处理

第三方模块安装:

  1. win + R 输入 cmd 点击确定, 输入安装命令 pip install 模块名 (pip install requests) 回车

  2. 在pycharm中点击Terminal(终端) 输入安装命令

模块可能安装失败原因:出现大量报红 (read time out)

解决方法: 因为是网络链接超时, 需要切换镜像源

可使用镜像源例举:

  1. 清华:https://pypi.tuna.tsinghua.edu.cn/simple

  2. 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/

  3. 华中理工大学:https://pypi.hustunique.com/

  4. 山东理工大学:https://pypi.sdutlinux.org/

例如:pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple/ 模块名


👇 👇 👇 更多精彩机密、教程,尽在下方,赶紧点击了解吧~

素材、视频教程、完整代码、插件安装教程我都准备好了,直接在文末名片自取就可


代码展示

导入模块

import os
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  # 阈值分割所用阈值
        self.kernel_size = kernel_size  # 膨胀运算核尺寸

    def select_roi(self, img: numpy.ndarray, hint: str) -> list:

框选水印或字幕位置,SPACE或ENTER键退出

:param img: 显示图片

:return: 框选区域坐标

        COFF = 0.7
        w, h = int(COFF * img.shape[1]), int(COFF * 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] / COFF), int(roi[1] / COFF), int(roi[2] / COFF), int(roi[3] / COFF)]
        return watermark_roi

    def dilate_mask(self, mask: numpy.ndarray) -> numpy.ndarray:

对蒙版进行膨胀运算

:param mask: 蒙版图片

:return: 膨胀处理后蒙版

        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:

通过手动选择的ROI区域生成单帧图像的水印蒙版

:param img: 单帧图像

:param roi: 手动选择区域坐标

:param threshold: 二值化阈值

:return: 水印蒙版

        # 区域无效,程序退出
        if len(roi) != 4:
            print('NULL ROI!')
            sys.exit()

        # 复制单帧灰度图像ROI内像素点
        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(roi[0]), int(roi[0] + roi[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]

        # 阈值分割
        _, mask = cv2.threshold(roi_img, threshold, 255, cv2.THRESH_BINARY)
        return mask

    def generate_watermark_mask(self, video_path: str) -> numpy.ndarray:

截取视频中多帧图像生成多张水印蒙版,通过逻辑与计算生成最终水印蒙版

:param video_path: 视频文件路径

:return: 水印蒙版

        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:

通过手动选择ROI区域生成单帧图像字幕蒙版

:param frame: 单帧图像

:param roi: 手动选择区域坐标

:return: 字幕蒙版

        mask = self.generate_single_mask(frame, [0, roi[1], frame.shape[1], roi[3]], self.threshold)  # 仅使用ROI横坐标区域
        return self.dilate_mask(mask)

    def inpaint_image(self, img: numpy.ndarray, mask: numpy.ndarray) -> numpy.ndarray:

修复图像

:param img: 单帧图像

:parma mask: 蒙版

:return: 修复后图像

        telea = cv2.inpaint(img, mask, 1, cv2.INPAINT_TELEA)
        return telea

    def merge_audio(self, input_path: str, output_path: str, temp_path: str):

合并音频与处理后视频

:param input_path: 原视频文件路径

:param output_path: 封装音视频后文件路径

:param temp_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):

去除视频水印

        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:
                # 生成水印蒙版
                mask = self.generate_watermark_mask(name)

            # 创建待写入文件对象
            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)

            # 逐帧处理图像
            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()

            # 封装视频
            (_, filename) = os.path.split(name)
            output_path = os.path.join(OUTPUT_PATH, filename.split('.')[0] + '_no_watermark.mp4')  # 输出文件路径
            self.merge_audio(name, output_path, TEMP_VIDEO)

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

    def remove_video_subtitle(self):

去除视频字幕

        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):
            # 创建待写入文件对象
            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)

            # 逐帧处理图像
            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()

            # 封装视频
            (_, filename) = os.path.split(name)
            output_path = os.path.join(OUTPUT_PATH, filename.split('.')[0] + '_no_sub.mp4')  # 输出文件路径
            self.merge_audio(name, output_path, TEMP_VIDEO)

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


if __name__ == '__main__':
    sel=input('1:去水印, 2:去字幕\n')
    if sel=='1':
        remover = WatermarkRemover(threshold=80, kernel_size=5)
        remover.remove_video_watermark()
    if sel=='2':
        remover = WatermarkRemover(threshold=80, kernel_size=5)
        remover.remove_video_subtitle()

尾语

感谢你观看我的文章呐~本次航班到这里就结束啦 🛬

希望本篇文章有对你带来帮助 🎉,有学习到一点知识~

躲起来的星星🍥也在努力发光,你也要努力加油(让我们一起努力叭)。

最后,宣传一下呀~👇👇👇更多源码、资料、素材、解答、交流皆点击下方名片获取呀👇👇

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

我是00后,我卷一点怎么了?

前段时间去面试了一个公司,成功拿到了offer,薪资也从12k涨到了18k,对于工作都还没两年的我来说,还是比较满意的,毕竟一些工作3、4年的可能还没我高。 我可能就是大家说的卷王,感觉自己年轻,所以…

手动创建django项目和python虚拟环境

在使用pycharm创建django项目的时候,报错如下: C:\Users\12051\AppData\Local\Temp\tmplkz609ucpycharm-management\setuptools-40.8.0\setup.py install Traceback (most recent call last):File "C:\Users\12051\AppData\Local\Temp\tmpqphl…

合并两个有序链表(java)

leetcode 21题:合并两个有序链表 题目描述解题思路:链表的其它题型。 题目描述 leetcode21题:合并两个有序链表 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例: 输入&…

IO多路转接

目录 一、select 1.1 select初识 1.2 select函数 1.3 scoket就绪条件 1.4 select基本工作流程 1.5 select服务器 1.6 select的优点 1.7 select的缺点 1.8 select的适用场景 二、poll 2.1 poll函数 2.2 poll服务器 2.3 poll的优点 && 缺点 三、epoll 3.1…

设备快线客户端软件V1.0用户手册

1.前言欢迎使用设备快线客户端软件产品。设备快线客户端软件简称DYClient,DYClient客户端是东用科技有限公司推出的一款用于远程维护的控制软件,主要为客户远程访问现场终端设备提供便捷的接入服务,并且通过DYClient客户端软件用户可以非常方便快捷的访问…

ChatGPT和软件测试实践与思考

前言 关于最近大火的ChatGPT相信各位也听过不同渠道听说过他的厉害,目前发展趋势比较火热,科技公司都有在考虑怎么使用ChatGPT进行提高研发效率以及办公效率,最近我所在的公司也有在要求大家使用ChatGPT进行改善工作效率,所以引发…

支持导入 Eolink 插件,别小看这个开源 API 管理工具了

Postcat 有多达 30 款支持数据迁移、主题、API 安全等方面的插件。 导入 Eolink 插件。 使用 导入功能有多个入口,你可以在 API 分组处点击加号导入 API: 也可以换种方式,在首页里导入Eolink 如果你日常会用到 api 管理工具的话&#xff0c…

【九章斩题录】C/C++:二维数组中的查找(JZ4)

精品题解 👉 《九章刷题录》 📜 目录: 「 法一 」暴力美学 「 法二 」十字分割法 「 法三 」逐行二分 JZ4 - 二维数组中的查找 📚 题目描述:在一个二维数组 array 中(每个一维数组的长度相同&#xff…

[时间同步] vscode chatGPT提供的程序打包封装成api解决方案怎么样

背景 在完成gnss时间同步程序大部分需求串口配置、串口数据中找出推荐定位信息RMC解析UTC时间以及UTC时间更新系统时间等功能后,有个需求比较特别,需要客户来操作。当车辆在地库场景待时间过久后重新回到地面,一直在自走的系统时间与又定位好…

Three.js--》探索Three.js:学习和就业的完整指南

目录 three.js的学习建议 WebGL前端工程师工作待遇相关问题 本篇文章主要给大家介绍一下如何学习Web3D可视化,具体说就是怎么学习WebGL、Three.js、3D建模等。 three.js的学习建议 在过去互联网是人联网的时代,开发人和人之间的联系的Web应用&#x…

MoveIt2中使用trac_ik

文章目录 1.下载trac_ik的源码2.安装 NLopt library3.编译源码4.使用 在ros1moveit1中,使用trac_ik是很简单的一件事情:【TRAC-IK Kinematics Solver】 但是在Ros2中,无论MoveIt2也好,还是trac_ik也好,都没有提供标准的…

如何编写快速高效的SQL查询(三)——高性能索引策略与样例

是时候开始讨论使用索引了!正确地创建和使用索引是实现高性能查询的基础,现在我们一起来看看如何真正地发挥这些索引的优势。 高效地选择和使用索引有很多种方式,其中有些是针对特殊案例的优化方法,有些则是针对特定行为的优化。…

Redis7实战加面试题-高阶篇(Redis线程与IO多路复用,BigKey,缓存双写)

Redis线程 面试题:Redis为什么选择单线程? 这种问法其实并不严谨,为啥这么说呢?Redis的版本很多3.x、4.x、6.x,版本不同架构也是不同的,不限定版本问是否单线程也不太严谨。 1 版本3.x ,最早版本,也就是…

高压放大器在3D打印中的应用

随着3D打印技术的快速发展,高压放大器在3D打印中的应用越来越受到人们的关注。高压放大器在3D打印中扮演着非常重要的角色,可以提高3D打印的效率和精度,从而实现更高的打印质量。本文将详细介绍高压放大器在3D打印中的应用及其原理。 高压放…

SAP 从入门到放弃系列之安全库存

概念 安全库存的主要目的是以一定数量的库存或时间的作为缓冲区间,以应对供需之间波动的影响。SAP ERP 系统提供两种类型的安全库存:静态安全库存和动态安全库存(即安全天数供应)。 静态安全库…

《程序员面试金典(第6版)》面试题 02.08. 环路检测(哈希法,双指针,检测链表是否有环)

题目描述 给定一个链表,如果它是有环链表,实现一个算法返回环路的开头节点。若环不存在,请返回 null。 题目传送门:面试题 02.08. 环路检测 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链…

操作系统第一章练习题

目录 问答题 选择题 填空题 判断题 问答题 1、设计现代OS的主要目标是什么? 答:设计现代OS的主要目标是:方便性、有效性、可扩充性、开放性 2、OS的作用可表现在哪几个方面? 答:(1)从一…

每个软件测试人员必须具备的12大技能

作者 | Kiran Beladiya 赛希翻译组 译 作为一名软件测试员,掌握一些技术技能是非常必要的,这可以使应用程序变得更好。让我们来看看对任何软件测试员来说必不可少的技能。 没有人能成为这样的软件测试员。要获得这个职业,每个测试人员都必…

公文写作技巧:作风建设类排比句40例

1.面对突发任务时,是主动请缨还是被动服从;遇到棘手问题时,是迎难而上还是推诿回避;在荣誉面前,是正确对待还是邀功请赏;汇报工作时,是真实客观还是弄虚作假。 2.不是敷衍了事图轻松&#xff0…

Spring、SpringMVC

文章目录 Spring一、Spring概述二、Spring快速入门1. Spring开发步骤2. Spring配置文件2.1 Bean标签基本2.2 Bean标签范围2.3 Bean生命周期2.4 Bean实例化三种方式 3. Bean的依赖注入3.1 Bean依赖注入概念3.2 Bean依赖注入方式3.3 Bean的依赖注入的数据类型3.4 引入其他配置文件…