基于​Segment-and-Track Anything与ProPainter实现视频一键目标移除与一键祛除水印

一、 ProPainter

1.算法简介

ProPainter是由新加坡南洋理工大学(Nanyang Technological University)的S-Lab团队开发的一款视频修复工具。它融合了图像和特征修复的优势,以及高效的Transformer技术,旨在提供高质量的视频修复效果,同时保持高效性。
ProPainter包含以下功能:

  1. 对象去除:能够轻松去除视频中的不需要的对象。
  2. 水印删除:可用于删除视频中的水印,提高视觉质量。
  3. 视频内容完整性修复:能够修复损坏的视频内容,使其看起来 完整和连贯。

2.项目部署

想对ProPainter有更多了解或者想部署ProPainter项目的可以我之前的博客:
一键智能视频编辑与视频修复算法——ProPainter源码解析与部署

3.项目局限性

ProPainter当前开源的代码只有视频移除对象部分的源码,但在移除对象之前,要生成mask图,ProPainter不提供生成mask图像的代码,生成mask图像的代码要借助目标分割与目标追踪。
比如我要移动掉桌子中间的投影仪,那要借助Segment-and-Track Anything对目标进行分割与追踪,然后每一帧都生成mask图像:
在这里插入图片描述
生成的mask图像:
在这里插入图片描述

二、Segment-and-Track Anything

1.算法简介

“Segment-and-Track Anything” 是由浙江大学 ReLER 实验室开发的一款多功能视频分割和目标跟踪模型,它深度整合了 SAM(Segment Anything Model)和视频分割技术,使其能够高效地跟踪视频中的目标,并支持多种交互方式(如点、画笔和文字输入)。

在这个基础上,SAM-Track 实现了多个传统视频分割任务的统一,使其能够一键分割和追踪任意视频中的任意目标,将传统视频分割技术推向通用视频分割领域。SAM-Track 在复杂场景下表现出卓越的性能,即使在单一GPU卡上也能高质量地稳定跟踪数百个目标。

SAM-Track 模型基于 ECCV’22 VOT Workshop 四个赛道的冠军方案 DeAOT。DeAOT 是一种高效的多目标视频对象分割模型,在提供首帧物体标注的情况下,可以对视频的其余帧中的物体进行追踪分割。DeAOT 使用一种识别机制,将一个视频中的多个目标嵌入到同一高维空间中,从而实现对多个物体的同时跟踪。DeAOT 在多物体追踪方面的速度表现媲美其他专注于单个物体追踪的 VOS 方法。此外,通过基于分层 Transformer 的传播机制,DeAOT 更好地整合了长时序和短时序信息,表现出卓越的追踪性能。然而,DeAOT 需要参考帧的标注来初始化,为了提高方便性,SAM-Track 利用了图像分割领域的明星模型 SAM,以获取高质量的参考帧标注信息。SAM 凭借出色的零样本迁移能力以及多种交互方式,使 SAM-Track 能够为 DeAOT 高效获取高质量的参考帧标注信息。

虽然 SAM 模型在图像分割领域表现出色,但它无法输出语义标签,并且文本提示也无法有效地支持 Referring Object Segmentation 以及其他依赖深层语义理解的任务。因此,SAM-Track 模型进一步集成了 Grounding DINO,实现了高精度的语言引导视频分割。Grounding DINO 是一种开放集合目标检测模型,具备出色的语言理解能力。

2.项目部署

可参考之前的博客:
​Segment-and-Track Anything——通用智能视频分割、目标追踪、编辑算法解读与源码部署

三、项目整合

1.目标分割与追踪

把Segment-and-Track Anything和ProPainter整合在一起之后,实现目标分割与目标追踪。
目标分割与目标追踪:

def tracking_objects_in_video(SegTracker, input_video, input_img_seq=None, frame_num=0):

    if input_video is not None:
        video_name = os.path.basename(input_video).split('.')[0]
    else:
        return None, None

    # create dir to save result
    tracking_result_dir = f'{os.path.join(os.path.dirname(__file__), "output", f"{video_name}")}'
    create_dir(tracking_result_dir)

    io_args = {
        'tracking_result_dir': tracking_result_dir,
        'output_mask_dir': f'{tracking_result_dir}/{video_name}_masks',
        'output_masked_frame_dir': f'{tracking_result_dir}/{video_name}_masked_frames',
        'output_video': f'{tracking_result_dir}/{video_name}_seg.mp4',  # keep same format as input video
        # 'output_gif': f'{tracking_result_dir}/{video_name}_seg.gif',
    }

    return video_type_input_tracking(SegTracker, input_video, io_args, video_name, frame_num)


def video_type_input_tracking(SegTracker, input_video, io_args, video_name, frame_num=0):

    pred_list = []
    masked_pred_list = []

    # source video to segment
    cap = cv2.VideoCapture(input_video)
    fps = cap.get(cv2.CAP_PROP_FPS)

    if frame_num > 0:
        output_mask_name = sorted([img_name for img_name in os.listdir(io_args['output_mask_dir'])])
        output_masked_frame_name = sorted([img_name for img_name in os.listdir(io_args['output_masked_frame_dir'])])

        for i in range(0, frame_num):
            cap.read()
            pred_list.append(
                np.array(Image.open(os.path.join(io_args['output_mask_dir'], output_mask_name[i])).convert('P')))
            masked_pred_list.append(
                cv2.imread(os.path.join(io_args['output_masked_frame_dir'], output_masked_frame_name[i])))

    # create dir to save predicted mask and masked frame
    if frame_num == 0:
        if os.path.isdir(io_args['output_mask_dir']):
            # os.system(f"rm -r {io_args['output_mask_dir']}")
            pass
        if os.path.isdir(io_args['output_masked_frame_dir']):
            # os.system(f"rm -r {io_args['output_masked_frame_dir']}")
            pass
    output_mask_dir = io_args['output_mask_dir']
    create_dir(io_args['output_mask_dir'])
    create_dir(io_args['output_masked_frame_dir'])

    torch.cuda.empty_cache()
    gc.collect()
    sam_gap = SegTracker.sam_gap
    frame_idx = 0

    with torch.cuda.amp.autocast():
        while cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

            if frame_idx == 0:
                pred_mask = SegTracker.first_frame_mask
                torch.cuda.empty_cache()
                gc.collect()
            elif (frame_idx % sam_gap) == 0:
                seg_mask = SegTracker.seg(frame)
                torch.cuda.empty_cache()
                gc.collect()
                track_mask = SegTracker.track(frame)
                # find new objects, and update tracker with new objects
                new_obj_mask = SegTracker.find_new_objs(track_mask, seg_mask)
                save_prediction(new_obj_mask, output_mask_dir, str(frame_idx + frame_num).zfill(5) + '_new.png')
                pred_mask = track_mask + new_obj_mask
                # segtracker.restart_tracker()
                SegTracker.add_reference(frame, pred_mask)
            else:
                pred_mask = SegTracker.track(frame, update_memory=True)
            torch.cuda.empty_cache()
            gc.collect()

            save_prediction(pred_mask, output_mask_dir, str(frame_idx + frame_num).zfill(5) + '.png')
            pred_list.append(pred_mask)

            print("processed frame {}, obj_num {}".format(frame_idx + frame_num, SegTracker.get_obj_num()), end='\r')
            frame_idx += 1
        cap.release()
        print('\nfinished')

    ##################
    # Visualization
    ##################

    # draw pred mask on frame and save as a video
    cap = cv2.VideoCapture(input_video)
    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(io_args['output_video'], fourcc, fps, (width, height))

    frame_idx = 0
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break

        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        pred_mask = pred_list[frame_idx]
        masked_frame = draw_mask(frame, pred_mask)
        cv2.imwrite(f"{io_args['output_masked_frame_dir']}/{str(frame_idx).zfill(5)}.png", masked_frame[:, :, ::-1])

        masked_pred_list.append(masked_frame)
        masked_frame = cv2.cvtColor(masked_frame, cv2.COLOR_RGB2BGR)
        out.write(masked_frame)

        print('frame {} writed'.format(frame_idx), end='\r')
        frame_idx += 1
    out.release()
    cap.release()
    print("\n{} saved".format(io_args['output_video']))
    print('\nfinished')

    # manually release memory (after cuda out of memory)
    del SegTracker
    torch.cuda.empty_cache()
    gc.collect()

    return io_args['output_video']

在这里插入图片描述
执行之后,在项目根目录的output目录下生成mask图:
在这里插入图片描述

2. 目标移除

得到mask图之后就可以使用ProPainter进行视频目标移除:

def remove_watermark(input_video):
    print("开始祛除目标")
    # print('cwd', os.getcwd())
    root_path = os.getcwd()

    os.chdir(os.path.join(root_path,'ProPainter'))

    python_exe = resolve_relative_path(os.path.join(root_path,'env/python.exe'))
    inference = resolve_relative_path(os.path.join(root_path,'ProPainter/inference_propainter.py'))

    video_name = os.path.basename(input_video).split('.')[0].split('_')[0]
    output_base_path = resolve_relative_path('./output/')
    output_path = f'{output_base_path}/{video_name}/'
    mask = f'{output_path}/{video_name}_masks/'

    command = f'{python_exe} {inference} --video {input_video} --mask {mask}  --output {output_path} --fp16 --subvideo_length 50'
    print(command)
    result = subprocess.run(command, shell=True)

    if result.returncode != 0:
        error_message = result.stderr.decode('utf-8', 'ignore')
        print(f"错误 {error_message}")
    else:
        print("成功")
    file_name = input_video.split('\\')[-1].split('.')[0]
    print(file_name)
    os.chdir(resolve_relative_path('./'))
    print('cwd', os.getcwd())
    return output_path + '/' + file_name + '/' + 'inpaint_out' + '.mp4'
    # return input_video

在这里插入图片描述

四、项目源码

1.项目配置

我使用的硬件环境是GPU是3080,在目前项目只能处理短视频,对输入视频的尺寸也有限制,输入的尺寸过大会出现GPU内存不够用的现象,输入的视频太长,超过1分钟的视频,会出现卡死的现象。

2.项目源码

为了运行方便,这里把项目打包成一个包,下载之后直接运行,不用安装任何环境,但要在GPU下使用。 下载地址:https://download.csdn.net/download/matt45m/88460539

3.源码运行

下载之后,点start.bat启动项目,使用浏览器打开http://127.0.0.1:7860显示操作界面,运行完成的项目在项目根目录的output目录下。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

libcurl Socks5 堆缓冲区溢出漏洞(CVE-2023-38545)详细分析

简介 curl 是用于在各种网络协议之间传输数据的命令行工具,libcurl 用于提供处理网络通信和数据传输的 Api 接口。curl 默认下载缓冲区为 102400 字节,但如果设置低于每秒 102400 字节,缓冲区大小会自动设置为更小的值。libcurl 下载缓冲区默…

AIO开放接口平台免费畅享ChatGPT聊天、联网互动、学术等服务!更有DALL·E 3最强AI绘图功能!

免费畅享! AIO平台ChatGPT联网、聊天、学术等服务! AIO开放接口平台 | 服务介绍 ALL IN ONE (AIO)API服务是LLM(大语言模型)开放接口平台:持续接入各种主流的大模型接口,并提供简单、易用、统一的API交互…

第四章 路由基础

目录 4.1 路由器概述 4.1.1 路由器定义 4.1.2 路由器工作原理 4.1.3 路由表的生成方式 (1)直连路由 (2)静态路由 (3)动态路由 4.1.4 路由器的接口 (1)配置接口 &#xff0…

css中px、em、rem、%、vw、vh、vm、rpx 这些单位的区别

序言 px:像素 相对长度单位,相对于显示器屏幕分辨率(推荐使用) em:相对长度单位 基准点为父节点字体的大小,如果自身定义了font-size按自身来计算(浏览器默认字体是16px),整个页面内1em不是一个…

如何将 Helm Chart 推送至 Harbor ?

Author:rab 前言:我们说 Helm 的私有仓库可以是任何 HTTP Server(如 Nginx、Apache 等),而 Harbor 自带 Helm 私有仓库的功能(但默认是禁用的,需要我们手动启用),如果为了…

电子元器件管理系统 JAVA语言开发

目录 一、系统介绍 二、系统下载 三、系统截图 一、系统介绍 基于VueSpringBootMySQL的电子元器件管理系统包含元器件单位模块、元器件仓库模块、元器供应商模块、元器件品类模块、元器件明细模块、元器件采购模块、元器件采购审核模块、元器件领用模块、学生元器件申请模块…

Cisco IOS XE Web UI 命令执行漏洞

Cisco IOS XE Web UI 命令执行漏洞 受影响版本 Cisco IOS XE全版本 漏洞描述 Cisco IOS XE Web UI 是一种基于GUI的嵌入式系统管理工具,能够提供系统配置、简化系统部署和可管理性以及增强用户体验。它带有默认映像,因此无需在系统上启用任何内容或安…

ideaSSM在线商务管理系统VS开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 SSM 在线商务管理系统是一套完善的信息管理系统,结合SSM框架和bootstrap完成本系统,对理解JSP java编程开发语言有帮助系统采用SSM框架(MVC模式开发),系统具有完整的源代码 和数据库,系统主…

VS Code C# 开发工具包正式发布

前言 微软于本月正式发布Visual Studio Code C#开发工具包,此前该开发套件已经以预览版的形式在6月份问世。经过4个月的测试和调整,微软修复了350多个问题,其中大部分是用户反馈导致的问题。此外,微软还对产品进行了300多项有针对…

OpenCV 笔记(3):基本图形的绘制

Part11. 绘制简单的图形 绘图功能是 OpenCV 最基础的功能,OpenCV 提供了基础的绘制函数,用于帮助我们绘制一些基本的图形。通过这些函数的组合,我们也可以做一些高级的应用。 11.1 绘制点和圆 OpenCV 的绘制函数相对简单,而且很多…

WPF Material Design UI框架

前言 Material Design in xaml 是开源免费的ui框架&#xff0c;工控软件主打的就是简单界面。 以下简称MD 相关资源 MaterialDesignInXamlToolkit Github 地址 MD 快速启动 MD 案例压缩包 MD 框架使用 启动环境配置 安装Nuget包 App.xaml 配置 <Application x:Class&qu…

部署:端口映射相关问题

图片仅作示意用途 在很多现场部署环境里&#xff0c;网络管理是相对严格的&#xff0c;设备所在的子网如果需要和办公网所在的服务器通讯&#xff0c;需要通过专门的中间节点&#xff0c;一般还有严格的防火墙配置。此时&#xff0c;研发环境里&#xff0c;服务器与设备子网各…

在edge浏览器中安装好了burp的ca证书,浏览器依旧不能访问https的原因

在edge浏览器中安装好了burp的ca证书&#xff0c;浏览器依旧不能访问https的原因 1.SwitchyOmega代理插件设置2.CA证书方法1方法2 1.SwitchyOmega代理插件设置 严格安装以下图片执行&#xff0c;不可少写或多写 2.CA证书 方法1 下载好证书&#xff0c;先导入到edge浏览器的中…

linux下部署nacos(单机、集群)

文章目录 nacos简介单机部署集群部署部署常见问题 官网文档地址&#xff1a;https://nacos.io/zh-cn/docs/deployment.html github地址&#xff1a;https://github.com/alibaba/nacos nacos简介 Nacos&#xff0c;全称阿里巴巴开源的动态服务发现、配置和服务管理平台&#x…

【数据结构】堆的详解

文章目录 堆的简介堆的实现堆的插入数据堆的删除数据 堆排序向上调整和向下调整的时间复杂度的分析 大量数据的topk问题 堆的简介 今天要写的数据结构是堆&#xff0c;什么是堆呢&#xff1f;堆其实是一种完全二叉树&#xff0c;只不过它是有条件的。 堆分为两种&#xff0c;一…

【AGC】更新应用信息报未知错误解决方法

【问题描述】 最近有几个开发者遇到了一个问题&#xff0c;他们在AGC控制台配置好应用信息的图标和截图之后&#xff0c;点击保存按钮会弹出“未知错误&#xff0c;请稍后再试”的异常报错&#xff0c;导致无法正确保存应用配置信息。 出错页面如图所示。 ​​ 【解决方案】 …

Real3D FlipBook jQuery Plugin 3.41 Crack

Real3D FlipBook 和 PDF 查看器 jQuery 插件 - CodeCanyon 待售物品 实时预览 截图 视频预览 Real3D Flipbook jQuery 插件 - 1 Real3D Flipbook jQuery 插件 - 2 Real3D Flipbook jQuery 插件 - 3 新功能 – REAL3D FLIPBOOK JQUERY 插件的 PDF 到图像转换器 一款用于将…

3分钟教你用Python+Appium实现自动化测试

一、环境准备 1.脚本语言&#xff1a;Python3.x IDE&#xff1a;安装Pycharm 2.安装Java JDK 、Android SDK 3.adb环境&#xff0c;path添加E:\Software\Android_SDK\platform-tools 4.安装Appium for windows&#xff0c;官网地址 Redirecting 点击下载按钮会到GitHub…

软硬件架构分层总结

一、前言 软件系统很多架构图我们经常看到是这样的三段 就是这三段就可以演化出很多层 二、硬件架构分层 硬件层&#xff0c;基本是计算机硬件的体系结构&#xff0c;包括硬盘设备&#xff0c;cpu&#xff0c;内存&#xff0c;控制器&#xff0c;运算器&#xff0c;寄存器&am…

【会议征稿通知】2024第四届神经网络、信息与通信工程国际学术会议(NNICE 2024)

2024第四届神经网络、信息与通信工程国际学术会议&#xff08;NNICE 2024&#xff09; 2024 4th International Conference on Neural Networks, Information and Communication Engineering 2024第四神经网络、信息与通信工程国际学术会议&#xff08;NNICE 2024&#xff0…