之前+opencv+python逐帧处理可否将视频处理成图片?
优采云 发布时间: 2021-08-19 20:00之前+opencv+python逐帧处理可否将视频处理成图片?
背景
在之前的学习爬虫项目中,得到的部分视频有水印,所以需要通过更好的技术手段来实现去水印。一般情况下,如果能拿到没有水印的原图最好,但是网站的一些原图本身是有水印的。在这种情况下,可以通过一些视频编辑软件去除少量水印,但对于大量素材,依靠人工完成是不现实的。
说明
这个文章将提供一种方法来描述在特定类型的视频中使用技术手段实现去除水印。仅供参考和学习。请合理使用,避免法律风险。
主要的实现方法其实很简单,主要是整合了现有的各种工具,最终取得了更好的效果。限制类别后,去除效果评价通过率达到97%。
研究
网上查了一下,主要有以下几个实现可以参考。你可以看到它们有不同的优点和缺点。
高端大气AI
首先,AI的接入成本和学习门槛都比较高,有点玄学。不管算法如何,最终的效果还是取决于对输入样本的训练。回到我们的素材本身,不同作者的水印会发生变化(id是水印)。算法训练,其实获得准确位置的能力还有待确定。
缺点总结:依赖较多,需要训练。预计训练模型不会容易适应Id+logo变化的情况,效果不理想。
ffmpeg delogo
其实就是在水印位置加了一个滤镜,类似于磨砂玻璃效果。这是一种比较直接的方式,但问题的核心是如何获取水印的位置。另一个问题是ffmpeg delogo在不同的视频素材中效果不稳定。例如,如果一个视频帧的水印位置有很多屏幕内容,去除水印后会更加明显。不过一般情况下,水印在右上或左上,屏幕内容比较少。
缺点总结:要产生模糊区域,需要确定位置和大小。
Mask+opencv + python 逐帧处理
能否将视频处理成图片,然后根据每张图片进行处理?当然,理论是可行的,把问题变成了图像去水印,还有更成熟的去水印算法,比如openCV。但是有一些问题。
首先,openCV的图片去水印需要一个mask,即纯色+水印的图片。当然,它不适合不同的视频水印标志变化。为每个视频自动创建蒙版是不可能的。
另一个是视频处理成图片后,内容过大。测试中,将19MB 1080P60hz的视频处理成3GB大小的图片,每一帧的处理也很耗时,更不用说合并成视频的耗时了。
缺点很明显:mask生成+逐帧处理+耗时
cv get fixed icon + 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
遇到的问题
错位是由以下原因造成的。
ffmpeg 占用 CPU 资源过多
这主要是因为ffmpeg的参数一开始没有太注意。默认情况下,所有 CPU 都被占用,这导致一开始就死机。去除毛玻璃效果太明显后可以使用-threads参数设置占用CPU视频水印
因为这种情况完全和视频内容有关,目前计划依赖ffmpeg,暂时没有解决方案。能想到的就是优化ffmpeg的水印算法,这是一个不切实际的快速可达的方案。项目全是java。有没有办法用java实现上面的openCV和ffmpeg调用?
这是一次尝试。当然,答案是可以实现的。使用现成的 Bytedeco,您可以避免自己编写大量命令行调用。总结
以上是本文文章的全部内容。限于篇幅,部分细节没有完全补充。在过程中的某些情况下,虽然方法是已知的,但仍然需要大量的时间来调试和验证才能知道最终的效果。当然,最后还是在不断的练习下有明显的提升。前面说过,在控制输入样本的前提下,比如只选择右上角的水印,并尽量保证视频分辨率一致,最终评测通过率达到了97%,还是令人满意的。
参考资料ziweipolaris/watermark-removal:通过减水印的方法从视频中去除水印,速度快但不完善。基于GAN的图像水印去除器效果堪比PS大师-Flash基因-个人技术,分享毫秒级图像噪声!全新AI系统完美去除水印! -云+社区-腾讯云去噪、水印、超分辨率,这个不用学习的神经网络无所不能-云+社区-腾讯云【深度学习水印】-CSDN去噪、加水印、超分辨率,这个不用学习的神经网络无所不能机器之心【论文分享(一)】自动去水印(一)---自动水印识别与特征提取-知乎短视频分析,去水印原理总结-博客Python实现超简单【抖音】 @]无水印视频批量下载fei347795790的博客-CSDN博客抖音@batch下载无水印近无损视频水印方法Python OpenCV去除图片水印_XerCis的博客-CSDN Blog_cv2去除水印python使用opencv去除水印方法-可用于水印去除-简书JavaCV入门示例和UnsatisfiedLinkError异常踏步记录Bytedeco-Home