作者 | 李秋键

头图 | 下载于视觉中国

出品 | AI 科技大本营(ID:rgznai100)

引言:

视频和图像的隐身术是指在视频或者图像中中,在没有任何输入遮罩的情况下,通过框选目标体,使得程序实现自动去除视频中的文本叠加和修复被遮挡部分的问题。并且最近的基于深度学习的修复方法只处理单个图像,并且大多假设损坏像素的位置是已知的,故我们的目标是在没有蒙皮信息的视频序列中自动去除文本。

今天,我们通过搭建一个简单而有效的快速视频解码器框架去实现视频中物体的去除。流程是构建一个编码器-解码器模型,其中编码器采用多个源帧,可以提供从场景动态显示的可见像素。这些提示被聚合并输入到解码器中。然后通过应用循环反馈进一步改进加强模型。循环反馈不仅加强了时间相干性,而且提供了强大的线索。

实现效果如下可见:

模型建立

1.1 环境要求

本次环境使用的是python3.6.5+windows平台

主要用的库有:

argparse模块是python自带的命令行参数解析包,可以用来方便地读取命令行参数;

subprocess是Python 2.4中新增的一个模块,它允许你生成新的进程,连接到它们的 input/output/error 管道,并获取它们的返回(状态)码。这个模块的目的在于替换几个旧的模块和方法

numpy模块用来矩阵和数据的运算处理,其中也包括和深度学习框架之间的交互等。

torch模块是一个python优先的深度学习框架,是一个和tensorflow,Caffe,MXnet一样,非常底层的框架在这里我们用来搭建网络层和直接读取数据集操作,简单方便。

Matplotlib模块用来可视化训练效果等数据图的制作。

1.2 程序的启动

程序的运行方式如下:

1、直接运行demo.py文件对图片进行处理

2、对视频进行处理python demo.py --data data/bag.avi。

import argparse
from mask import mask
from inpaint import inpaint
parser = argparse.ArgumentParser(description='Demo')
parser.add_argument('--resume', default='cp/SiamMask_DAVIS.pth', type=str,metavar='PATH', help='path to latest checkpoint (default: none)')
parser.add_argument('--data', default='data/Human6', help='videos or image files')
parser.add_argument('--mask-dilation', default=32, type=int, help='mask dilation when inpainting')
args = parser.parse_args()
mask(args)
inpaint(args)

1.3 算法概述

视频中物体的移除目的是从有字幕、有噪声的视频帧中预测原始帧。恢复的区域应该和原始的相同大小,或者无缝地融合到周围的像素中。基本的算法思想是从多个相邻帧(源帧)中收集提示,然后恢复目标帧。这是为了利用视频中的场景动态,在视频中,随着物体的移动或字幕的变化,被遮挡的部分通常会在滞后或引导帧中显示。同时还可以使用循环反馈连接作为额外的源流。直接估计一帧中的所有像素可能会不必要地接触到未损坏的像素。为了解决像素指标缺失的问题,采用残差学习算法对模型进行训练。具体来说,最终输出是通过按像素顺序将输入中心帧和预测残差图像相加得到的。这使得我们的网络明确地只关注损坏的像素,也防止全局色调失真。

1.4模型的搭建

模型算法核心设计是一个混合的编码器-解码器模型,其中编码器包括两个子网络:3D CNN和2D CNN。解码器遵循一个正常的2D CNN设计,该网络被设计成完全卷积的,可以处理任意大小的输入。最后的输出视频是通过自回归的方式应用函数得到的,我们的策略是从多个源帧中收集潜在的线索,这些帧可以提供从场景动态中显示的可见像素。此外,我们强制目标帧的生成与前一代保持一致。通过构造一个双流混合编码器,其中每个源流都经过训练以实现我们的目标。第一个编码器流由3D卷积组成,它可以直接从相邻帧捕获时空特征,第二个流是一个2D CNN,它将先前生成的尺寸为H×W×1×C的帧作为输入。

其中模型生成如下:

try: assert(opt.model == 'vinet_final')model = vinet.VINet_final(opt=opt)
except:print('Model name should be: vinet_final')
assert(opt.no_cuda is False)
model = model.cuda()
model = nn.DataParallel(model)
loaded, empty = 0,0
if opt.pretrain_path:print('Loading pretrained model {}'.format(opt.pretrain_path))pretrain = torch.load(opt.pretrain_path)child_dict = model.state_dict()parent_list = pretrain['state_dict'].keys()parent_dict = {}for chi,_ in child_dict.items():if chi in parent_list:parent_dict[chi] = pretrain['state_dict'][chi]#print('Loaded: ',chi)loaded += 1else:#print('Empty:',chi)empty += 1print('Loaded: %d/%d params'%(loaded, loaded+empty))child_dict.update(parent_dict)model.load_state_dict(child_dict)

视频处理

2.1 预定义

我们的任务将视频去除目标后尽可能的还原成背景场景。如果场景移动或者字幕在相邻帧中消失,被遮挡的部分就会被显示出来,这就为潜在的内容提供了关键的线索。为了使增益参数的最大化,需要为我们的模型找到最佳的帧采样间隔。当最小间隔为1时,输入帧将包含不重要的动态。另一方面,如果我们以较大的步伐跳跃,不相干的新场景就会被包括进来。最终通过测试,设定的参数如下:

opt = Object()
opt.crop_size = 512
opt.double_size = True if opt.crop_size == 512 else False
########## DAVIS
DAVIS_ROOT =os.path.join('results', args.data)
DTset = DAVIS(DAVIS_ROOT, mask_dilation=args.mask_dilation, size=(opt.crop_size, opt.crop_size))
DTloader = data.DataLoader(DTset, batch_size=1, shuffle=False, num_workers=1)
opt.search_range = 4  # fixed as 4: search range for flow subnetworks
opt.pretrain_path = 'cp/save_agg_rec_512.pth'
opt.result_path = 'results/inpainting'
opt.model = 'vinet_final'
opt.batch_norm = False
opt.no_cuda = False  # use GPU
opt.no_train = True
opt.test = True
opt.t_stride = 3
opt.loss_on_raw = False
opt.prev_warp = True
opt.save_image = False
opt.save_video = True

2.2 视频处理

我们的模型不仅从当前帧中收集线索,还从未来和过去相邻帧中收集线索。另外,为了保持时间一致性,有条件地生成每一帧到前一帧的输出帧。

with torch.no_grad():for seq, (inputs, masks, info) in enumerate(DTloader):idx = torch.LongTensor([i for i in range(pre - 1, -1, -1)])pre_inputs = inputs[:, :, :pre].index_select(2, idx)pre_masks = masks[:, :, :pre].index_select(2, idx)inputs = torch.cat((pre_inputs, inputs), 2)masks = torch.cat((pre_masks, masks), 2)bs = inputs.size(0)num_frames = inputs.size(2)seq_name = info['name'][0]save_path = os.path.join(opt.result_path, seq_name)if not os.path.exists(save_path) and opt.save_image:os.makedirs(save_path)inputs = 2. * inputs - 1inverse_masks = 1 - masksmasked_inputs = inputs.clone() * inverse_masksmasks = to_var(masks)masked_inputs = to_var(masked_inputs)inputs = to_var(inputs)total_time = 0.in_frames = []out_frames = []lstm_state = Nonefor t in range(num_frames):masked_inputs_ = []masks_ = []if t < 2 * ts:masked_inputs_.append(masked_inputs[0, :, abs(t - 2 * ts)])masked_inputs_.append(masked_inputs[0, :, abs(t - 1 * ts)])masked_inputs_.append(masked_inputs[0, :, t])masked_inputs_.append(masked_inputs[0, :, t + 1 * ts])masked_inputs_.append(masked_inputs[0, :, t + 2 * ts])masks_.append(masks[0, :, abs(t - 2 * ts)])masks_.append(masks[0, :, abs(t - 1 * ts)])masks_.append(masks[0, :, t])masks_.append(masks[0, :, t + 1 * ts])masks_.append(masks[0, :, t + 2 * ts])elif t > num_frames - 2 * ts - 1:masked_inputs_.append(masked_inputs[0, :, t - 2 * ts])masked_inputs_.append(masked_inputs[0, :, t - 1 * ts])masked_inputs_.append(masked_inputs[0, :, t])masked_inputs_.append(masked_inputs[0, :, -1 - abs(num_frames - 1 - t - 1 * ts)])masked_inputs_.append(masked_inputs[0, :, -1 - abs(num_frames - 1 - t - 2 * ts)])masks_.append(masks[0, :, t - 2 * ts])masks_.append(masks[0, :, t - 1 * ts])masks_.append(masks[0, :, t])masks_.append(masks[0, :, -1 - abs(num_frames - 1 - t - 1 * ts)])masks_.append(masks[0, :, -1 - abs(num_frames - 1 - t - 2 * ts)])else:masked_inputs_.append(masked_inputs[0, :, t - 2 * ts])masked_inputs_.append(masked_inputs[0, :, t - 1 * ts])masked_inputs_.append(masked_inputs[0, :, t])masked_inputs_.append(masked_inputs[0, :, t + 1 * ts])masked_inputs_.append(masked_inputs[0, :, t + 2 * ts])masks_.append(masks[0, :, t - 2 * ts])masks_.append(masks[0, :, t - 1 * ts])masks_.append(masks[0, :, t])masks_.append(masks[0, :, t + 1 * ts])masks_.append(masks[0, :, t + 2 * ts])masked_inputs_ = torch.stack(masked_inputs_).permute(1, 0, 2, 3).unsqueeze(0)masks_ = torch.stack(masks_).permute(1, 0, 2, 3).unsqueeze(0)start = time.time()最终完成效果如下:

完整代码链接:

https://pan.baidu.com/s/1tCB0MTBbvfSokeU1AAKBQQ

提取码:nfhk

作者简介:李秋键,CSDN博客专家,CSDN达人课作者。硕士在读于中国矿业大学,开发有taptap竞赛获奖等。


你还知道哪些 Python 的新奇用法

欢迎来评论区唠唠~

AI科技大本营将选出三名优质留言

携手【北京大学出版社】送出

《Python入门到人工智能实战》一本

截至4月18日14:00点

更多精彩推荐
无人机、IoT 设备都有漏洞?专访以色列老牌安全企业Check Point
听完姚期智的一句“嘟囔”,他开始第二次创业AI 3D 传感器市场竞争白热化,中国掌握自主可控核心技术时不我待!小心!你家的 IoT 设备可能已成为僵尸网络“肉鸡”点分享点收藏点点赞点在看

用 Python 实现隐身,我可以 | 文末福利相关推荐

  1. 精通python爬虫框架-精通Python爬虫从Scrapy到移动应用(文末福利)

    原标题:精通Python爬虫从Scrapy到移动应用(文末福利) 我能够听到人们的尖叫声:"Appery.io是什么,一个手机应用的专用平台,它和Scrapy有什么关系?"那么,眼 ...

  2. python识别手写文字_如何快速使用Python神经网络识别手写字符?(文末福利)

    原标题:如何快速使用Python神经网络识别手写字符?(文末福利) 点击标题下[异步社区]可快速关注 在本文中,我们将进一步探讨一些使用Python神经网络识别手写字符非常有趣的想法.如果只是想了解神 ...

  3. 最强旅游攻略 | 用Python分析国庆中秋最佳旅游景点 (文末福利)

    作者 | 裸睡的猪 头图 | CSDN下载自视觉中国 文末福利,不要错过哦! 正文 2020年国庆中秋双节马上就要到来 昨天和朋友聊天: 我:"这8天你准备去哪里玩" 朋友:&qu ...

  4. 文末福利 | Python3 网络爬虫:老板,需要特殊服务吗?

    文末福利!送书啦! 您若喜欢,给公众号设置星标,第一时间获取推送 1 前言 网络爬虫,爬天爬地爬空气. 除了常规的下载文字.图片.音频这些,还能干啥? 还能干的有很多,比如一些「多种多样」的特殊服务. ...

  5. 10年软件测试工程师感悟——写给还在迷茫中的朋友「十年磨一剑,文末福利」

    不知不觉在软件测试行业,野蛮生长了10年之久.这一路上拥有了非常多的故事.有迷茫,有踩过坑,有付出有收获,有坚持! 我一直都在软件测试行业奋战,有许多同学好友都已经转行,去选择了更适合自己的路. 这两 ...

  6. 【文末福利】CSDN深圳城市开发者社区第一波线下技术交流活动,蓄势启航,本周六0617为你揭开神秘面纱

    [文末福利]CSDN深圳城市开发者社区第一波线下技术交流活动,蓄势启航,本周六0617为你揭开神秘面纱 文章目录 1 写在前面 2 CSDN深圳城市开发者社区简介 3 聚焦本周六的线下技术交流活动 4 ...

  7. 【文末福利】我用英飞凌的PSoC™ 62搞了点智能家居的创意

    [英飞凌创意创客大赛]基于Infineon和ChatGPT的人工智能语音小管家 概要 本文给大家介绍一个Infineon和ChatGPT的人工智能语音小管家项目,该项目是博主架构师李肯参加由RT-Th ...

  8. 【文末福利】算法大赛评委共话技术趋势,这场直播值得一看!

    2020腾讯广告算法大赛初赛如火如荼,赛事热度亦不断升级,截止目前已吸引近两万名技术人才关注.为了更好的以产研结合的形式助推行业人才培养,让专业高校学生及技术从业者更全面深入地了解AI技术发展趋势,腾 ...

  9. 推荐几个比较骚的技术公众号【文末福利】

    nIT行业技术变更周期越来越快,作为技术人最重要的是持续学习,现在的学习途径有很多,我们到底该如何做出选择?我觉得最重要有两方面:第一,需要保持良好的技术视野,持续关注行业内技术新动向:第二,多向IT ...

  10. 使用Spring Boot构建微服务(文末福利)

    本文主要内容 学习微服务的关键特征 了解微服务是如何适应云架构的 将业务领域分解成一组微服务 使用Spring Boot实现简单的微服务 掌握基于微服务架构构建应用程序的视角 学习什么时候不应该使用微 ...

最新文章

  1. 使用多个MQTT调试工具mqtt.fx连接同个服务器地址报错,只能连接一个,修改Client ID即可
  2. 图片质量低怎么办?这个网站很不错!
  3. 从地心到宇宙,再到治疗癌症与“赋灵”智能,这届腾讯WE都聊了些啥?
  4. java如何让控制台不输出报错_Java 控制台输入输出操作记录
  5. 日本3D打印最贵牛肉!人工组装肌肉脂肪和血管,两天即完成,网友:赛博朋克的仿制肉...
  6. Spring Security认证过程
  7. 想对你们每个人说的话
  8. Android之数据库操作
  9. zabbix巡检脚本
  10. .NET学习笔记:文件和注册表操作
  11. matlab对文本文件的读写
  12. jsp转换java_JSP编码转换
  13. CentOS6.5上增加中文字体库,确保前端WEB可以正常显示
  14. 教你写页游自动化Python脚本,取色,大漠识别和后台点击
  15. c++ vector随机排序
  16. Android Wi-Fi subsystem_ramdump简介(以QCOM为Base)
  17. oracle导出为dmp文件,oracle导出dmp文件的2种方法
  18. vue登录时验证码获取
  19. 数据结构总结与知识网图
  20. 本地安装MySQL详细步骤

热门文章

  1. 微信小程序把玩(三十五)Video API
  2. 模仿Hibernate的逆向工程_java版_源码下载
  3. MOSS 2010:Visual Studio 2010开发体验(14)——列表开发之事件接收器
  4. linux下jsp环境的搭建
  5. 在SpringBoot启动类上添加ComponentScan出现springbootapplication already applies given @ComponentScan
  6. 如何将本地项目上传到自己的GitHub上
  7. 常用的分布式事务解决方案介绍有多少种?
  8. maven生命周期理解
  9. PAT1036:Boys vs Girls
  10. 【代码片段】如何使用CSS来快速定义多彩光标