本文由本人原创,仅作为自己的学习记录
最近研究物联网安全,需求之一就是要实现摄像头遮挡的检测,调研了很久,很多都是基于视频帧分析的,这样不仅处理繁琐,而且对不同编码格式的视频处理也不尽相同,结合最近在学习图像处理的东东,脑洞一开,能不能通过监听网络上的视频流,从而还原出视频,再进一步提取关键帧图像,通过对比遮挡前后图像的相似度,进而判断摄像头是否被遮挡呢?下面是我的实现步骤。
有人说摄像头都有遮挡报警设置,为什么还要做这个?这个….我也不知道,客户就是上帝,上帝让你做,就得做。言归正传。
由于网络设备时串行部署在网络中,作为网络转发设备,对硬件资源的占用一定要慎重,所以,通过直接向摄像头获取视频数据这种方式被放弃,能不能通过tcpdump监听网络流量,进而把RTP的视频流保存为视频文件呢?网上还真有真有的工具,videosnarf就是其中之一,具体实现大家可以自行百度,这里不做详细介绍,上代码:
def __init__(self, pcap_time, percent):
self.pcap_time = pcap_time
self.percent = int(percent)
self.pcap_filename = ‘/tmp/udp_rtp.pcap’
self.vodiodir = ‘/tmp/vodio/’
初始化目录
if not os.path.exists(self.vodiodir):
os.mkdir(self.vodiodir)
self.picturedir = ‘/tmp/picture/’
if not os.path.exists(self.picturedir):
os.mkdir(self.picturedir)
self.picture_predir = ‘/tmp/picture_pre/’
if not os.path.exists(self.picture_predir):
os.mkdir(self.picture_predir)
抓取数据包
def get_pcap(self):
print ‘begin packet capture’
在这里,抓包只为了获取视频数据,进而获取图像,所以,抓包时间尽可能的短一些,避免占用系统资源
command = ‘timeout -t ‘ + self.pcap_time + ‘ /usr/sbin/tcpdump -i any udp -w ‘ + self.pcap_filename
print command
os.system(command)
将数据包转换成视频文件
def trans_pcap_to_h264file(self):
print ‘begin trans pcap to h264’
command = ‘ ./videosnarf -i ‘ + self.pcap_filename + ‘ -o ‘ + self.vodiodir
print command
os.system(command)
下一步是如何从视频文件中提取图片,继续找工具,强大的ffmpeg实现了这个功能,能够根据需要对视频进行截图,代码如下:
def get_picture_from_vodio(self):
print ‘begin get picture from vodio’
vodio_list = os.listdir(self.vodiodir)
for i in vodio_list:
command = ‘./ffmpeg -i ‘ + self.vodiodir + i + ‘ -r 1 -f image2 ‘ + self.picturedir + i.split(‘_’)[0] + ‘_%4d.jpeg’
print command
os.system(command)
到这里基本上完成了图像的提取工作,下一步就是要针对前后两次的图像就行对比,然后就可以根据设定的相似度进行摄像头遮挡的检测,同样的,也可以实现对对移动物体的检测哦,如何实现大家自行补脑吧。
python对图像的处理有很多开源的库,这里使用了pil库,首先提取图片的框架图,大家对比下面两幅图片:
第一幅是正常图片,第二幅是提取的框架图,很简单,通过计算第二幅图的黑白点个数,即可得到图的灰度值,比较前后两次抓取图片的灰度值,即可得到图片的相似度,是不是so easy!!
def getGray(image_file):
tmpls=[]
for h in range(0, image_file.size[1]):#h
for w in range(0, image_file.size[0]):#w
tmpls.append( image_file.getpixel((w,h)) )
return tmpls
def getAvg(ls):#获取平均灰度值
return sum(ls)/len(ls)
def getMH(a,b):#比较字符有几个字符相同
dist = 0;
for i in range(0,len(a)):
if a[i]==b[i]:
dist=dist+1
return dist
def getImgHash(fne):
image_file = Image.open(fne) # 打开
image_file=image_file.resize((12, 12))#重置图片大小我12px X 12px
image_file=image_file.convert(“L”)#转256灰度图
Grayls=getGray(image_file)#灰度集合
avg=getAvg(Grayls)#灰度平均值
bitls=”#接收获取0或1
#除去变宽1px遍历像素
for h in range(1, image_file.size[1]-1):#h
for w in range(1, image_file.size[0]-1):#w
if image_file.getpixel((w,h))>=avg:#像素的值比较平均值 大于记为1 小于记为0
bitls=bitls+’1′
else:
bitls=bitls+’0′
return bitls
程序运行结果如下:
设置抓包时间3秒 相似度低于80%为遮挡
themis:~# python camera_cover_dect.py 3 80
begin packet capture
timeout -t 3 /usr/sbin/tcpdump -i any udp -w /tmp/udp_rtp.pcap
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
2604 packets captured
2621 packets received by filter
12 packets dropped by kernel
begin trans pcap to h264
./videosnarf -i /tmp/udp_rtp.pcap -o /tmp/vodio/
begin get picture from vodio
./ffmpeg -i /tmp/vodio/10.50.10.36_3.264 -r 1 -f image2 /tmp/picture/10.50.10.36_%4d.jpeg
./ffmpeg -i /tmp/vodio/10.30.10.211_2.264 -r 1 -f image2 /tmp/picture/10.30.10.211_%4d.jpeg
begin clean vodio
rm -f /tmp/vodio/*
begin compare picture
192.168.28.189_0001.jpeg
ls /tmp/picture/ | grep 192.168.28.189
192.168.28.189_0001.jpeg Similarity degree:80%
设置抓包时间3秒 相似度低于98%为遮挡
themis:~# python camera_cover_dect.py 3 98
begin packet capture
timeout -t 3 /usr/sbin/tcpdump -i any udp -w /tmp/udp_rtp.pcap
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
2730 packets captured
2758 packets received by filter
28 packets dropped by kernel
begin trans pcap to h264
./videosnarf -i /tmp/udp_rtp.pcap -o /tmp/vodio/
begin get picture from vodio
./ffmpeg -i /tmp/vodio/192.168.88.226_2.264 -r 1 -f image2 /tmp/picture/192.168.88.226_%4d.jpeg
./ffmpeg -i /tmp/vodio/192.168.28.189_1.264 -r 1 -f image2 /tmp/picture/192.168.28.189_%4d.jpeg
begin clean vodio
rm -f /tmp/vodio/*
begin compare picture
192.168.28.189_0001.jpeg
ls /tmp/picture/ | grep 192.168.28.189
192.168.28.189_0001.jpeg Similarity degree:73%
camare 192.168.28.189 is covered!!!
达到预定目标,实现了基于流量监听的摄像头遮挡检测,是不是很简单。
感谢开源工具videosnarf ffmpeg tcpdump,感谢用户提出这么奇葩的要求。相关代码资源可以在一下链接下载,有问题欢迎大家交流。
如需源码,请联系本人 zhang_peng18@163.com