镜头边界检测技术简述

介绍

作为视频最基本的单元帧(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)

总结

镜头边界检测技术本质是根据不同的指标检测两帧之间的区别,根据检测指标,区别越大则表示我们需要的信息变化越大。在实际使用中应根据不同的选择不同的边界检测技术。

附录

使用上述三种方法分别对录制的视频进行了检测,可以参考我使用opencv_python写的代码

python数字图像处理(二)关键镜头检测的更多相关文章

  1. python数字图像处理(17):边缘与轮廓

    在前面的python数字图像处理(10):图像简单滤波 中,我们已经讲解了很多算子用来检测边缘,其中用得最多的canny算子边缘检测. 本篇我们讲解一些其它方法来检测轮廓. 1.查找轮廓(find_c ...

  2. 「转」python数字图像处理(18):高级形态学处理

    python数字图像处理(18):高级形态学处理   形态学处理,除了最基本的膨胀.腐蚀.开/闭运算.黑/白帽处理外,还有一些更高级的运用,如凸包,连通区域标记,删除小块区域等. 1.凸包 凸包是指一 ...

  3. python skimage图像处理(二)

    python skimage图像处理(二) This blog is from: https://www.jianshu.com/p/66e6261f0279  图像简单滤波 对图像进行滤波,可以有两 ...

  4. python数字图像处理(1):环境安装与配置

    一提到数字图像处理编程,可能大多数人就会想到matlab,但matlab也有自身的缺点: 1.不开源,价格贵 2.软件容量大.一般3G以上,高版本甚至达5G以上. 3.只能做研究,不易转化成软件. 因 ...

  5. 初始----python数字图像处理--:环境安装与配置

    一提到数字图像处理编程,可能大多数人就会想到matlab,但matlab也有自身的缺点: 1.不开源,价格贵 2.软件容量大.一般3G以上,高版本甚至达5G以上. 3.只能做研究,不易转化成软件. 因 ...

  6. python数字图像处理(18):高级形态学处理

    形态学处理,除了最基本的膨胀.腐蚀.开/闭运算.黑/白帽处理外,还有一些更高级的运用,如凸包,连通区域标记,删除小块区域等. 1.凸包 凸包是指一个凸多边形,这个凸多边形将图片中所有的白色像素点都包含 ...

  7. python数字图像处理(5):图像的绘制

    实际上前面我们就已经用到了图像的绘制,如: io.imshow(img) 这一行代码的实质是利用matplotlib包对图片进行绘制,绘制成功后,返回一个matplotlib类型的数据.因此,我们也可 ...

  8. python数字图像处理(三)边缘检测常用算子

    在该文将介绍基本的几种应用于边缘检测的滤波器,首先我们读入saber用来做为示例的图像 #读入图像代码,在此之前应当引入必要的opencv matplotlib numpy saber = cv2.i ...

  9. python数字图像处理(9):直方图与均衡化

    在图像处理中,直方图是非常重要,也是非常有用的一个处理要素. 在skimage库中对直方图的处理,是放在exposure这个模块中. 1.计算直方图 函数:skimage.exposure.histo ...

随机推荐

  1. File类 ReadAllBytes() ReadAllLines() ReadAllText()

    用 File 类里的 ReadAllLines方法读取文件string[] contents = File.ReadAllLines(@"F:\Users\zhuotu003\Desktop ...

  2. webpack插件之webpack-dev-server

    webpack插件之webpack-dev-server webpack插件 自动化 webpack-dev-server  现在只需要使用 npm run build指令就可以自动打包,并自动处理好 ...

  3. Type.MakeGenericType 方法 (Type[]) 泛型反射

    替代由当前泛型类型定义的类型参数组成的类型数组的元素,并返回表示结果构造类型的 Type 对象. 命名空间:   System程序集:  mscorlib(mscorlib.dll 中) public ...

  4. 【Python】—— 获取函数内部变量名称

    原文出处: https://blog.csdn.net/maixiaochai/article/details/88693507 关键语句: func_vars = func.__code__.co_ ...

  5. 使用 Dom4j 对XML操作!!!

    转自:http://blog.csdn.net/redarmy_chen/article/details/12969219 dom4j是一个Java的XML API,类似于jdom,用来读写XML文件 ...

  6. Matlab与C++混合编程 2--在C++中使用Matlab固有命令

    直接在Visual Studio中运行Matlab固有命令 #include <iostream> #include"engine.h" // 添加matlab引擎库的 ...

  7. 深入理解java:1.3.2 JVM监控与调优

    学习Java GC机制的目的是为了实用,也就是为了在JVM出现问题时分析原因并解决之. 本篇,来看看[ 如何监控和优化GC机制.] 通过学习,我觉得JVM监控与调优,主要在3个着眼点上: 1,如何配置 ...

  8. [19/09/16-星期一] Python的运算符和条件判断语句

    一.运算符 (1)算术运算符  + 加法运算符(如果是两个字符串之间进行加法运算,则会进行拼串操作) a = 10 + 5  计算 a = 'hello' + ' ' + 'world' 拼串  - ...

  9. JavaWeb返回Json格式数据JQuery Ajax无法解析的问题

    今天在写实验室的傻逼Java Web小项目的时候,有一个需要发布内容的地方,因为想做的让用户感觉优雅一点 所以就是用了Ajax来做,本来很简单的一个小玩意,竟然花了半个多小时的时间,主要是将时间花在了 ...

  10. CAS单点登录系统入门--分布式登录验证

    1.开源单点登录系统CAS入门 1.1 什么是单点登录 单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要 ...