视频场景切换检测(镜头边界检测镜头分割)
Posted Python图像识别
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了视频场景切换检测(镜头边界检测镜头分割)相关的知识,希望对你有一定的参考价值。
👨💻个人简介: 深度学习图像领域工作者
🎉总结链接:
链接中主要是个人工作的总结,每个链接都是一些常用demo,代码直接复制运行即可。包括:
📌1.工作中常用深度学习脚本
📌2.torch、numpy等常用函数详解
📌3.opencv 图片、视频等操作
📌4.个人工作中的项目总结(纯干活)
链接: https://blog.csdn.net/qq_28949847/article/details/128552785
🎉视频讲解: 以上记录,通过B站等平台进行了视频讲解使用,可搜索 ‘Python图像识别’ 进行观看
B站:Python图像识别
抖音:Python图像识别
西瓜视频:Python图像识别
一、现有开源方案
深度学习算法
1. TransNetV2
结论:
这个算法通过测试看,准确度还是很高的,偶尔检测错误(镜头过渡切换),但是因为输入的数据是100帧,那么此算法只能是跑离线视频,无法在实时流中使用。
简介:
TransNetV2 算法输入是一个视频,模型会对视频每一帧压缩到统一的小尺寸48x27x3,每隔100帧作为一个片段(但只取中间50帧的结果,前后25帧类似于overlap)输入神经网络得到每一帧是否是边界帧的概率,以此计算完整段视频后,大于阈值(默认是0.5)的则判定为镜头边界帧。
作者提供了Tensorflow2.x的训练代码,torch只提供了predict代码。
传统算法
1. Pysencedetect
Pysencedetect中提供的也是处理视频的脚本以及命令行,可以自己把识别算法提出来,改成处理实时流的。
由于传统算法准确率比较低,而Transnetv2准确率够,但不能进行实时流的识别,所有个人进行了模型搭建,以实现对实时流的镜头切换检测。
软件
1. 万兴喵影(PC端)
这个软件提供的场景检测效果,准确率还是很高的,使用也挺方便,而且处理时软件可以进行GPU加速。
二、个人算法
GitHub链接:待上传
视频效果:见B站
注意看视频的左上角,当视频切换时,会出现‘Scene switching’的字样,速度太快,注意看🤣
效果:
本算法使用 分类模型 思想进行实现,直接分类虽然简单,但是最终效果很不错。
1. 数据集
ClipShots dataset 数据集
本算法只使用了ClipShots 这一个数据集进行训练。
2. 算法方案
最终方案:
将当前帧同上3帧图片同当前帧图片再channel维度进行拼接([3, 224, 224] + [3, 224, 224] + [3, 224, 224] + [3, 224, 224] = [12, 224, 224]),然后使用resnet50模型进行分类,最后发现效果还是很不错的,准确率同Transnetv2相比差不了多少,而我们基本能实现实时检测。
实现过程中的不同测试方案:
1. 分类模型backbone:resnet18、resnet50、resnet101、CSPdarknet53
2. 图片大小:(112, 112)、(224, 224)
3. 前后帧的数量:2帧、4帧、6帧
4. 灰度图(3通道图片转为单通道图片,再合并)
5. 孪生神经网络
根据以上方案总共做了不同的几种交叉测试,结论如下:
1. backbone部分,resnet18模型效果比较差,resnet50、resnet101、CSPdarknet53这三个模型的效果差不多,基本上分不出高低来。
2. 图片大小,(112,112)大小的图片准确率下降比较多,(224, 224)大小的准确率比较高
3. 前后帧数量,要是想要达到实时,最好的就是2帧(上一帧 + 当前帧)图片输入到模型中,但是通过测试发现,只传入2帧画面,检测效果会比较差,而传入6帧画面,准确率也并没有提高很高,所以4帧相对来说是最合适的。
4. 灰度图, 做这个测试主要是发现在综艺节目中,灯光会瞬间变化(蓝光 — 红光),容易造成误检,原本想通过灰度图,降低这种情况的误检,但是效果并不理想,并不能减少此情况的误检(同3通道的数据相比,是否降低准去率,没有准确测试,目测效果差不多)
5. 孪生神经网络, 之所以构建孪生网络,是因为想的是,进行镜头切换检测的本质是进行两张图片的相似度对比,当两张图片的相似度比较高的时候,代表是同一镜头,而相似度比较低的时候代表镜头进行了切换,但通过实际测试发现,效果并不理想😂,所以就换成了直接分类(不过我觉得大概率是自己搭建的模型有问题)。
通过以上的测试,最终确定 resnet50/CSPdarknet53 + (224, 224) + 4帧 + 3通道的方案。
总结:
1. 我们最终确定的是4张图片一起进入到模型中,也就是进行跳转的这一帧画面,我们有3次机会去进行检测识别,此方法能够提高准确率,而对实时的影响也很小,最多延迟3帧识别。
2. Transnetv2中是将图片缩放到了 48x27大小,我们只能到224x224大小,应该是因为它是连续100帧,能够提取到的前后帧的信息更多一些,我们只有4帧,信息太少造成的。
3. 当镜头进行过渡切换的时候,有时候会检测不出来,可能是由数据集造成的,ClipShots数据集中提供了一些过渡的数据集,但是因为持续时间太长,无法放入到模型里训练。
数字图像处理笔记关键镜头检测
镜头边界检测技术简述
介绍
作为视频最基本的单元帧(Frame),它的本质其实就是图片,一系列帧通过某种顺序组成在一起就构成了视频。镜头边界是视频相邻两帧出现了某种意义的变化,即镜头边界反映了视频内容的不连续性。这种变化反映了某些关键信息,通过设定不同的检测指标,我们能够得到这些关键信息的变化。因此镜头边界检测技术(Shot Bound Detection)的实质即设定一个检测指标来获取我们需要的关键信息。这种关键信息在不同任务中的体现使不一样的,动作识别中我们需要能检测动作变化的镜头边界,视频索引任务中我们需要能够表现这个视频整体的视频边界,这就有赖于人为选择检测算法。虽然随着深度学习的兴起,人们开始将深度学习应用在镜头边界检测上,但是传统图像处理方法的镜头边界检测技术仍然有着广泛的,本文旨在对一些常见的镜头边界检测技术进行简述。
连续帧相减法
连续帧相减法实现
一帧本质就是一张图片,因此衡量两帧之间变化本质就是衡量两张图片的区别。在KNN算法中衡量两张图片之间相似度就是图片对应像素相减之和,将其累加,值最小的即最接近的两张图片。连续帧相减法中,我们同样使用这个指标来评价两张图片的近似度,一旦区别大到一定地步则认为该两帧是镜头边界。
读入视频连续的三帧
我们可以清除的看到前两帧的图片几乎一样,第三帧则发生了颜色逆转,可以认为这是该视频的关键镜头。事实上,作为静止系mad,这里也确实是一个小高潮。
图像来自于bilibili,可以点击这里查看你就是我的真物
我们使用连续帧相减法来计算彼此之间的差别,画出他们的差距图
def diffimage(src_1,src_2):
#将numpy的基础类型转化为int型否则uint8会发生溢出
src_1 = src_1.astype(np.int)
src_2 = src_2.astype(np.int)
diff = abs(src_1 - src_2)
return diff.astype(np.uint8)
计算第二张图片与第一张图片差值,第二张图片与第三张图片差值,并使用matplotlib画出来
但是奇怪的是肉眼看不出来的图一和图二(实际上图一相比图二图上的内容有轻微的缺少,同时相比图二,图一有轻微的放大),之间的差别也是相当大。
#使用np.sum取得到的diff之和
图一与图二之间的像素点对应差距值之和 7777617
图二与三之间的像素点对应差距值之和 131587585
这就是连续帧相减法的一个缺陷对于运动目标的过于敏感,图一与图二之间是有轻微的缩放的,而图二与图三更多的只是颜色上的翻转,这极大影响了连续帧相减法检测的准确性,如何减少这些运动对帧相减法的影响?
使用均值滤波处理后使用连续帧相减法
使相对小的平移被忽略的一个直观的方法就是每个像素点取附近的均值,使用均值滤波器能够忽略一些无用的细节。使用通用3*3的卷积核在进行连续帧相减法查看效果。
blur_image1 = cv2.blur(image1,ksize=(3,3))
blur_image2 = cv2.blur(image2,ksize=(3,3))
blur_image3 = cv2.blur(image3,ksize=(3,3))
#省略画子图代码
cross1 = diffimage(blur_image1,blur_image2)
cross2 = diffimage(blur_image3,blur_image2)
图一与图二之间的像素点对应差距值之和 6894882
图二与三之间的像素点对应差距值之和 130940724
从上面的结果与一开始的对比,均值滤波确实减弱了缩放对于两帧差距的影响,但是减弱效果并不理想,因此我们可以得出连续帧相减法的不足,对于运动物体,缩放,平移过于敏感
使用连续帧相减法检测监控视频
相比上例,对监控视频使用连续帧相减法效果显著,考虑到监控器通常监控的区域的变化几乎不变,人的运动能够被轻易的检测出来,而通常检测监控视频中人的出现是通常的需求,我们使用连续帧相减法进行检测。
#核心代码即存储上一帧图像与现在图像进行帧相减法
ret, lastframe = cap.read()
while(cap.isOpened()):
ret, frame = cap.read()
if not ret:
break
if np.sum(diffimage(lastframe,frame))/frame.size > 10:
#设定的阈值
cv2.imwrite(str(uuid.uuid1())+".jpg",frame)
lastframe = frame
cv2.imshow(‘frame‘,frame)
if cv2.waitKey(1) & 0xFF == ord(‘q‘):
break
使用连续帧相减法得到关键帧的其中一张如下(具体代码可以参见配套代码)
注:视频为录制了自己经过摄像头的片段
直方图相减法
黑白图像计算直方图差值
正如上面两张图片颜色的明显变化可能是分辨关键帧的因素一样,我们能否直接从颜色通道上来找寻关键帧呢,首先我们画出三张图片的灰度分布图(为了处理方便,将图片转化为灰度图)
我们计算出各灰度分布数量并将其用直方图表示出来
def cal_s(single_chaneel_image):
height,width = single_chaneel_image.shape
color = np.array([0 for i in range(256)])
for i in range(height):
for j in range(width):
color[single_chaneel_image[i][j]]+=1
return color
我们试着画出第一张图灰度分布图,绘图代码很简答
plt.plot([i for i in range(256)],cal_s(gray_image))
我们可以清除的看到第一张照片的灰度分布,将三张图的通道都画出来进行对比
计算直方图差之和
print("1,2 image color distribution diviation",np.sum(diffimage(cal_s(gray_image1),cal_s(gray_image2))))
print("2 3 iamge color distribution diviation",np.sum(diffimage(cal_s(gray_image1),cal_s(gray_image3))))
#第一张图片与第二张图片直方图差值为 15406
#第三张图片与第二张图片直方图差值为 26378
三通道图像计算直方图差值
单纯的黑白图像可能丢失很大一部分细节,比如第三张图相比第一张,第二张色调发生了明显的反转,但转化为黑边图像则不如彩图时那么明显.
三通道差值计算将三通道分离然后分别计算在merge在一起,代码如下
def cal_s_rgb(image):
image = image.astype(np.int)
color = cv2.split(image)
color = list(map(cal_s,color))
return np.array(color).astype(np.uint8)
我们还是使用图像将图片显示出来
print("image2 image1 color distribution diviation",np.sum(diffimage(cal_s_rgb(image1),cal_s_rgb(image2))))
print("image2 image3 color distribution diviation",np.sum(diffimage(cal_s_rgb(image3),cal_s_rgb(image2))))
#图像1,2直方图差值和为 54100
#图像2,3直方图差值和为 73832
通过对比三张图rgb通道的分布直方图我们发现第三张图的b通道分布的相比1,2图很均匀,这也是将rgb通道分别相减求和与1,2图片的差距主要来源,但是由于r,g通道分布的相近,我们发现彩图的三图差距并不如黑白图几乎相差一倍那么明显。
感知哈希法
感知哈希法在计算图片相似度,音乐相似度等方面都极为常用。该算法对每张图片使用hash算法生成一个“指纹”字符串,通过比较不同图片的指纹来实现图片相似度的计算。在镜头边界检测中,一旦相似度低于一定阈值,则判断为镜头边界。选取不同hash算法对与算法的成效有较大影响。
感知哈希法的实现
图片缩放与简化色彩
感知哈希法在一开始将图片进行缩放,缩放的大小由使用者指定,有如下好处
1.相当于取了一定区域的特征,减少敏感性。
2.减少生成指纹大小。
3.减少计算量
同上一步一样简化色彩也起了抽象特征,减少计算量,存储量的作用。
def convertImage(image):
image = cv2.resize(image,(32,32),interpolation=cv2.INTER_CUBIC)
image = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
return image
计算DCT
DCT变换是将图像的信号转换到频域的一种方法,由于实现较为复杂,此处直接调用。
dct_1 = cv2.dct(cv2.dct(dct_matrix))
缩小DCT
取得到的DCT左上角8*8的矩阵作为特征,并求得其均值,凡大于均值则为1,小于则为0
dct_1 = dct_1[:8,:8]
avg = np.mean(dct_1)
reimg_list = [‘0‘ if i > avg else ‘1‘ for i in dct_1.flatten()]
计算指纹
将求得的转化为16进制的数字即其指纹
#fig = hex(int("".join(reimg_list),2))
fig = ""
for i in range(0,64,4):
num = hex(int("".join(img_list[i:i+4]),2))
fig += num[2:]
计算汉明距离
def hammingDist(s1, s2):
assert len(s1) == len(s2)
return sum([ch1 != ch2 for ch1, ch2 in zip(s1, s2)])
hammingDist(fig1,fig2)
总结
镜头边界检测技术本质是根据不同的指标检测两帧之间的区别,根据检测指标,区别越大则表示我们需要的信息变化越大。在实际使用中应根据不同的选择不同的边界检测技术。
以上是关于视频场景切换检测(镜头边界检测镜头分割)的主要内容,如果未能解决你的问题,请参考以下文章