视频水印自动识别和去除

背景

在之前学习爬虫项目中,得到的部分视频是有水印的,因此有能通过比较好的技术手段实现水印去除的需求。一般情况下,如果能获取到无水印的原始素材是最好,但某些网站本身的原始素材就是加了水印。对于这种情况,少量可以通过某些视频剪辑软件完成水印去除,但对于大量素材,依赖人工完成是不现实的。

描述

这篇文章将提供一种方法,描述在特定类型视频中,使用技术手段完成水印去除的实现,仅供参考学习,请合理使用,避免法律风险。

主要的实现方式其实非常简单,主要是各种现有工具的整合,最终也达到了比较好的效果。在限定品类之后,去除效果评估合格率达到了97%。

调研

在网上调研之后,主要有以下可参考的实现,可以看到,他们各自有不同的优势和缺点。

  1. 高端大气上AI
    首先AI有比较高的接入成本和学习门槛,而且本身有些玄学。抛开算法,最终的效果还是依赖输入样本的训练。再回到我们素材自身,不同作者其水印会是变化的(id为水印)。算法训练,其实获得准确位置的能力有待确定。
    总结缺点: 依赖众多,需要训练,Id+logo变化的情况预计训练模型不会容易适配,效果也不理想。

  2. ffmpeg delogo
    实际是在水印位置添加滤镜,类似毛玻璃效果。这种是比较直接的方式,但问题的核心变成了如何获取水印的位置。还有个问题就是,ffmpeg delogo 的效果在不同视频素材不稳定。例如,如果一个视频帧水印位置画面内容比较多,去除水印后会比较明显。不过一般情况下,水印在右上或者左上,画面内容相对较少。
    总结缺点:产生模糊区域,需要确定位置和大小。

  3. 蒙版+opencv + python 逐帧处理
    可否将视频处理成图片,然后再按每张图片来处理?当然理论是可行的,这就将问题变成了图片去水印,而且像openCV有比较成熟的去水印算法。但是几个问题。
    首先是openCV的图片去水印需要一个蒙版,即有个纯色+水印的图片,当然也不太适合不同视频水印logo变化的情况。按每个视频创建蒙版也是没法做成自动化的。

另一个是视频处理成图片后,内容过大。测试中,一个19MB的1080P60hz视频,处理成图片变成了3GB大小,而且每帧处理也比较耗时,更不说合并成视频的耗时。
缺点明确: 生成蒙版+逐帧处理+耗时较大

  1. cv 获取固定图标+ id生成位置坐标
    最后一种方案是折衷的方式,也是最终采用的。首先,水印的获取仍然使用openCV,不过是采用CV的图像识别。对于视频,也不是按照所有帧的方式,而是随机得选取某些帧获取截图,然后用cv去拿到水印坐标。这里有个前提,是水印中有部分是不变的,比如logo。先人工将这部分抠图下来,然后代入CV做识别,拿到了logo的坐标。因为不同帧会有变化,造成CV失败的误差,需要在失败的坐标中筛选成功率高的。
    然后由于水印是 logo+id的形式,再根据id的字数和字体字号占的像素数,通过之前获取的坐标算出水印的大小。如此我们就知道了水印的位置和大小,就可以使用ffmpeg delogo做去除了。

总结,最后实际是采用了第四种方案和第二种的结合,当然这也是根据具体场景综合考虑的,未必就是通用和最优的实现。

技术方案

描述

如上面的介绍,最终识别部分方案可以汇总成如下的流程:既然已经知道了水印的位置和大小,就可以使用ffmpeg delogo 的方式来去除。绝大部分视频的处理效果是可以接受的。

抠图获取统一logo ---> 视频随机分帧 ---> CV识别logo坐标 ---> 根据视频作者昵称计算水印大小 ---> ffmpeg delogo去除水印。

计算水印位置大小核心代码

import cv2
from matplotlib import pyplot as plt

# source=input('source:')
# tpl=input('template:')
source = '/export/data/晴天独奏/mask/1.png'
tpl = 'mark_bili_1280.png'

img = cv2.imread(source, 0)
img2 = img.copy()
template = cv2.imread(tpl, 0)
# 非1080*1920需要等比例缩放
w, h = template.shape[::-1]

ow, oh = img.shape[::-1]

# # All the 6 methods for comparison in a list
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
           'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
#
# methods = ['cv2.TM_CCOEFF_NORMED']
for meth in methods:
    img = img2.copy()
    method = eval(meth)

    # Apply template Matching
    res = cv2.matchTemplate(img, template, method)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

    # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc
    bottom_right = (top_left[0] + w, top_left[1] + h)
    cv2.rectangle(img, top_left, bottom_right, 255, 1)
    print('x={},y={},w={},h={}'.format(top_left[0], top_left[1], bottom_right[0]-top_left[0], bottom_right[1] - top_left[1]))

    plt.subplot(121), plt.imshow(res, cmap='gray')
    plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
    plt.subplot(122), plt.imshow(img, cmap='gray')
    plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
    plt.suptitle(meth)

    plt.show()

比较识别效果

不同算法的比较

最终去除效果对比

去除后

去除前

视频分帧代码


import os
import sys

import cv2

video_name = sys.argv[1]
if video_name is None:
    print("input video name!")
    exit(1)

com = 'ffmpeg -ss 10 -i {}  -f image2  -vframes 1 -y  frame.png'.format(video_name)
os.system(com)

cv2.namedWindow('frame', 0)
img = cv2.imread('frame.png')
cv2.imshow('frame', img)
cv2.waitKey(0)

批量匹配水印

用于在批量的截图中标记识别的水印,并打印出坐标


import os

import cv2

# source=input('source:')
# tpl=input('template:')
tpl = '/export/code/github/demo/src/test/resources/mark/mark_bili_1280-1.png'
template = cv2.imread(tpl, 0)
# 非1080*1920需要等比例缩放
w, h = template.shape[::-1]

# # All the 6 methods for comparison in a list
# methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
#            'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
#

dir = '/export/data/BV1dT4y1E7w3/out/'
# dir = '/export/code/github/demo/data/out/'
files = []
for f in os.walk(dir):
    f = f[2]
    for x in f:
        if '.png' not in x:
            continue
        files.append(x)
    break
count = 1
for f in files:
    source = dir + f
    img = cv2.imread(source, 0)

    img2 = img.copy()

    ow, oh = img.shape[::-1]
    meth = 'cv2.TM_CCOEFF_NORMED'
    img = img2.copy()
    method = eval(meth)

    # Apply template Matching
    res = cv2.matchTemplate(img, template, method)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

    # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc
    bottom_right = (top_left[0] + w, top_left[1] + h)
    cv2.rectangle(img, top_left, bottom_right, 255, 1)
    cv2.imwrite(source + ".mark.png", img)
    print('id:{} x={}:y={}:w={}:h={}'.format(count, top_left[0], top_left[1], bottom_right[0] - top_left[0], bottom_right[1] - top_left[1]))
    count = count + 1

遇到的问题

  • 1.识别错位

错位有以下几个原因造成。

  • 1.1 部分视频分辨率不统一,如变成1280*720。 解决办法是额外使用该分辨率下的logo 模板做CV识别。
  • 1.2 视频网站在某个时间之后更换了logo样式。 解决办法是只选取固定时间点之后的视频。
  • 1.3 水印中作者昵称部分,因为中英文字体大小,造成水印去除残留。 解决办法是根据不同字体用对应不同像素计算水印大小。以及多加些额外的冗余值,保证去除范围比实际水印范围大。
  • 1.4 其他识别错位。有极少数视频因为内容的原因,随机取的帧无法正确得到水印位置。解决方法是设置阈值,比如随机20帧,只有某个坐标重复达到或超过5次,才作为有效坐标,否则,重新截图分帧,再次失败。实际验证效果不是很理想,遂超过次数后,判断为失败,过滤掉。还有就是本身没有水印,这种目前只能以来人工介入。
  1. ffmpeg 消耗CPU资源过高
    这个主要是开始没有太注意ffmpeg的参数,默认占满全部CPU,导致开始时候卡顿。 可以通过-threads参数设置占用的CPU
  2. 视频水印去除后毛玻璃效果过于明显
    这种情况因为完全和视频内容有关系,目前的方案依赖ffmpeg,暂时无解。能想到的是优化ffmpeg的去水印算法,非现实快速可达的方案。
  3. 项目中都是java,有没有方法将如上包括openCV, ffmpeg的调用使用java实现?
    这算是个尝试,当然答案是可以实现的,有现成的Bytedeco,可以避免自己写大量命令行调用。

总结

以上就是本篇文章的所有内容,限于篇幅,部分细节没有全部补充。过程中某些情况下,虽然已经知道了方法,但是仍然需要花大量的时间去调试和验证才能知道最终的效果。当然最后也是在不断的实践下有了明显的提升。如之前所说,在控制输入样本的前提下,比如只选择右上角水印,尽量保证视频分辨率一致等,最终的评估合格率达到了97%,还是令人满意的。

参考资料

  1. ziweipolaris/watermark-removal: 通过水印减除方法去掉视频中的水印,快速但不完美
  2. 基于GAN的图像水印去除器,效果堪比PS高手 – 闪念基因 – 个人技术分享
  3. 毫秒级图像去噪!新AI系统完美去水印! - 云+社区 - 腾讯云
  4. 去噪、去水印、超分辨率,这款不用学习的神经网络无所不能 - 云+社区 - 腾讯云
  5. 【深度学习去水印】- CSDN
  6. 去噪、去水印、超分辨率,这款不用学习的神经网络无所不能 | 机器之心
  7. [论文分享(一)] 水印自动去除(上)---水印的自动识别和特征提取 - 知乎
  8. 短视频解析,去水印原理整理汇总-博客
  9. Python实现超简单【抖音】无水印视频批量下载fei347795790的博客-CSDN博客抖音批量下载 无水印
  10. 接近无损的视频去水印方法
  11. Python OpenCV去除图片水印_XerCis的博客-CSDN博客_cv2 去除水印
  12. python利用opencv去除水印方法 - 菲菲菲菲菲常新的新手 - 博客园
  13. 两种Python基于OpenCV的固定位置半透明水印去除方案 - 麦拂沙的个人空间 - OSCHINA
  14. 基于python的图片修复程序-可用于水印去除 - 简书
  15. JavaCV入门示例及UnsatisfiedLinkError异常踩坑记录
  16. Bytedeco - Home
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容