首先
首先我想进行介绍的是关于显著性检测的有关内容。
关于显著性检测,其本身是一种视觉注意机制:当我们观察某一个场景的时候,时常会选择性地忽略不感兴趣的区域、聚焦于感兴趣的区域。对于这种感兴趣的区域的提取算法,我们将其称为视觉显著性检测(Visual Saliency Detection,VSD)如下图所示:在人眼的观察过程中,会对天上的白云以及草地上的牛群最先产生反应,而自动忽略了背景区域,则白云以及牛群所在区域就是我们常说的显著性区域。
我们可以使用一些显著性检测算法,来得到下图的结果。
其中,像素值接近0的黑色区域为不显著区域,像素值接近255的白色区域为显著区域。
显著性检测算法在计算机视觉中有着很多的应用。
此处,我们需要使用到OpenCV-Contrib库中的saliency模块,OpenCV-Contrib在Python下的安装非常容易:
pip install opencv-contrib-python
使用上述命令进行安装即可。
使用说明
在saliency模块下,其主要提供了4种显著性检测算法。
(1).StaticSaliencySpectralResidual
原理:其本质是从统计学的角度进行的处理:模拟眼球的视觉捕捉过程,人们的视觉对变化部分更加敏感,视觉系统的一个基本原则就是抑制对频繁出现的特征的响应,同时对非常规的特征保持敏感。对图像的log频谱进行求均值后可以发现:大量图像的log频谱的平均值与频率成正比关系,如果再对log频谱进行一次log对数变换,其曲线会趋于直线,其中不能直线化的那一部分就是一幅图像的显著性区域,也就是普残差SR(Spectral Residual)。然后将谱残差进行空间变换,得到显著性图,该显著性图显示了感兴趣目标的位置。
提出时间:2007。
(2).StaticSaliencyFineGrained
原理:该方法基于空间尺度差异center-surround differences计算显著性。利用积分图像integral images来实时生成高分辨率显著性图。
提出时间:2010。
(3).ObjectnessBING
原理:基于二值化梯度特征(BING features)进行物体检测。
提出时间:2014。
(4).BinWangApr2014
原理:使用运动背景减除法实现显著性区域的检测。
提出时间:2014。
代码实现
接下来,我需要使用到vtest.avi作为我们的实验数据,需要进行下载的,可以点击此处进行下载,提取码为:1234。
整体代码部分如下所示。
import cv2
import random
def main():
# 显著性检测算法
# 可选:SPECTRAL_RESIDUAL,FINE_GRAINED,BING,BinWangApr2014
saliency_algorithm = "FINE_GRAINED"
# 检测视频或者图像
# video_name = "vtest.avi"
video_name = "1.jpeg"
# 起始帧
start_frame = 0
# 模型路径
training_path = "ObjectnessTrainedModel"
# 如果算法名和视频名为空,停止检测
if saliency_algorithm is None or video_name is None:
print("Please set saliency_algorithm and video_name")
return
# 打开对应的画面
cap = cv2.VideoCapture(video_name)
# 设置视频起始帧
cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
# 读图
_, frame = cap.read()
if frame is None:
print("Please set saliency_algorithm and video_name")
return
# 拷贝当前帧的一个副本
image = frame.copy()
# 根据输入的方法确定检测类型
if saliency_algorithm.find("SPECTRAL_RESIDUAL") == 0:
# 检测结果,白色区域表示显著区域
saliencyAlgorithm = cv2.saliency.StaticSaliencySpectralResidual_create()
# 计算显著性
start = cv2.getTickCount()
success, saliencyMap = saliencyAlgorithm.computeSaliency(image)
duration = (cv2.getTickCount() - start) / cv2.getTickFrequency()
print("computeBinaryMap cost time is: {} ms".format(duration * 1000))
if success:
# 二值化图像
start = cv2.getTickCount()
_, binaryMap = saliencyAlgorithm.computeBinaryMap(saliencyMap)
duration = (cv2.getTickCount() - start) / cv2.getTickFrequency()
print("computeBinaryMap cost time is: {} ms".format(duration * 1000))
cv2.imshow("Saliency Map", saliencyMap)
cv2.imshow("Original Image", image)
cv2.imshow("Binary Map", binaryMap)
# 转换格式并保存图片
saliencyMap = (saliencyMap * 255)
cv2.imwrite("Results/FINE_GRAINED_saliencyMap.jpg", saliencyMap)
cv2.imwrite("Results/FINE_GRAINED_binaryMap.jpg", binaryMap)
cv2.waitKey(0)
# FINE_GRAINED
elif saliency_algorithm.find("FINE_GRAINED") == 0:
saliencyAlgorithm = cv2.saliency.StaticSaliencyFineGrained_create()
# 计算显著性
start = cv2.getTickCount()
success, saliencyMap = saliencyAlgorithm.computeSaliency(image)
duration = (cv2.getTickCount() - start) / cv2.getTickFrequency()
print("computeBinaryMap cost time is: {} ms".format(duration * 1000))
if success:
# 二值化图像
start = cv2.getTickCount()
_, binaryMap = saliencyAlgorithm.computeBinaryMap(saliencyMap)
duration = (cv2.getTickCount() - start) / cv2.getTickFrequency()
print("computeBinaryMap cost time is: {} ms".format(duration * 1000))
cv2.imshow("Saliency Map", saliencyMap)
cv2.imshow("Original Image", image)
cv2.imshow("Binary Map", binaryMap)
# 转换格式后保存图片
saliencyMap = (saliencyMap * 255)
cv2.imwrite("Results/FINE_GRAINED_saliencyMap.jpg", saliencyMap)
cv2.imwrite("Results/FINE_GRAINED_binaryMap.jpg", binaryMap)
cv2.waitKey(0)
elif saliency_algorithm.find("BING") == 0:
# 判断模型是否存在
if training_path is None:
print("Path of trained files missing! ")
return
else:
saliencyAlgorithm = cv2.saliency.ObjectnessBING_create()
# 提取模型文件参数
saliencyAlgorithm.setTrainingPath(training_path)
# 将算法检测结果保存在Results文件夹内
saliencyAlgorithm.setBBResDir("Results")
# 计算显著性
start = cv2.getTickCount()
success, saliencyMap = saliencyAlgorithm.computeSaliency(image)
duration = (cv2.getTickCount() - start) / cv2.getTickFrequency()
print("computeBinaryMap cost time is: {} ms".format(duration * 1000))
if success:
# saliencyMap获取检测到的目标个数
ndet = saliencyMap.shape[0]
print("Objectness done ", ndet)
# 结果根据objectness进行排序,且只需要最大的那一个即可
# 目标按可能性从大到小排列,maxd为显示前5个目标,step设置颜色,jitter设置矩形框微调
maxd = 5
step = 255 / maxd
jitter = 9
draw = image.copy()
for i in range(0, min(maxd, ndet)):
# 获得矩形框坐标点
bb = saliencyMap[i][0]
# 设定颜色
col = ((i * step) % 255), 50, 255 - ((i * step) % 255)
# 矩形框微调
off = random.randint(-jitter,
jitter), random.randint(-jitter, jitter)
# 画矩形
cv2.rectangle(draw, (bb[0] + off[0], bb[1] + off[1]),
(bb[2] + off[0], bb[3] + off[1]), col, 2)
# mini temperature scale
# 颜色标注
cv2.rectangle(draw, (20, 20 + i * 10, 10, 10), col, -1)
# 保存图片
cv2.imwrite("Results/BING_draw.jpg", draw)
cv2.imshow("BING", draw)
cv2.waitKey(0)
# 需要传入图像建模
elif saliency_algorithm.find("BinWangApr2014") == 0:
saliencyAlgorithm = cv2.saliency.MotionSaliencyBinWangApr2014_create()
# 设置数据结构大小
saliencyAlgorithm.setImagesize(image.shape[1], image.shape[0])
# 初始化
saliencyAlgorithm.init()
paused = False
while True:
if not paused:
_, frame = cap.read()
if frame is None:
break
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 计算显著性
start = cv2.getTickCount()
success, saliencyMap = saliencyAlgorithm.computeSaliency(frame)
duration = (cv2.getTickCount() - start) / \
cv2.getTickFrequency()
print("computeBinaryMap cost time is: {} ms".format(duration * 1000))
cv2.imshow("image", frame)
# 显示
cv2.imshow("saliencyMap", saliencyMap * 255)
if cv2.waitKey(2)==ord('q'):
break
elif cv2.waitKey(2)==ord('p'):
paused = not paused
cv2.destroyAllWindows()
return
if __name__ == '__main__':
main()
这里以FINE_GRAINED来进行展示,其原图(视频第一帧)如下所示。
之后对其运行代码后,可以得到基于StaticSaliencyFineGrained算法的运行结果,如下所示。
除此以外,其提供了检测图片的二值化,使用的是computeBinaryMap函数来进行的实现,即先聚类然后阈值分割,其结果如下所示。
若要进行算法方法的修改,只需要修改上述代码中的第八行代码即可。例如,我把第八行的代码修改为:
saliency_algorithm = "BinWangApr2014"
其就能够不再仅仅是对第一帧进行处理,而是对整个视频进行处理了,其运行结果如下所示。
总结
就速度而言的话StaticSaliencySpectralResidual效果是这集中里面最快的,但与此同时,其效果很差。
StaticSaliencyFineGrained效果和速度都还可以,但是StaticSaliencyFineGrained获得的结果是一个高维图像,为此需要我们进行二值转换。模块自带的computeBinaryMap函数进行二值化效果很不错,就是比较耗时。
otionSaliencyBinWangApr2014中加入了运动检测,效果和速度都很好,但是建模时间比较长(因为他需要一些先验数据,所以运行的时候的前几秒钟会是白屏),这种当运动检测算法较好。
如果是较为复杂的场景,最好不要使用显著性检测算法,效果不佳。
评论(0)
您还未登录,请登录后发表或查看评论