视频场景切换检测的FPGA实现
本文将继续讲述图像处理算法的FPGA实现,后续可能更新图像旋转(1080P)、画中画、快速DCT等算法。视频场景切换检测常用于视频编解码领域,我选用的算法是双阈值灰度直方图检测法,起初在MATLAB上实现并测出最佳双阈值,然后将其转换为verilog代码,最终在XILINX K7开发板上实现视频场景切换检测的效果。
双阈值灰度直方图算法,顾名思义是采用两个灰度阈值来判断视频场景的切换。其中一个是渐变阈值T1,表明视频场景可能发生改变;另一个是突变阈值T2,表示阈值已经发生改变。当相邻帧灰度直方图差值比大于阈值T2时表明为场景突变帧,而当差值比大于阈值T1而小于阈值T2时则表示为场景渐变帧,差值比小于阈值T1则为连续帧。其中,相邻灰度直方图差值实际指的是一个权重,即当前灰度帧差与平均帧差的比,如公式(1)所示。这个比值越大,说明图像变化越大,就越有可能发生场景切换,反之则相反。
Prop_CurrentFrame=FrameDiff/AveFrameDiff (1)
双阈值灰度算法的MATALAB实现较为简单,更多的是依靠公式进行计算,并对差值进行判别。当然由于读取的是1080P视频,又需要遍历整帧的像素点,所以程序运行的比较慢。而程序实现的思路较为清晰,即:视频从第二帧开始读取,一次选取两帧,并将读取的图像数据转YUV格式,提取其中的Y分量;然后利用imhist()函数求取其对应的灰度直方图,并计算其相邻帧差,同时统计平均帧差;最后根据统计的平均帧差和当前帧差作比较,并根据阈值跳转到渐变帧或者突变帧,记录突变帧位置和突变次数。部分代码如下所示:
for i=2:FrameNum
Frame_0=read(Obj,i-1);%前一帧
Frame_1=read(Obj,i);%当前帧
ImageYuv_0=rgb2ycbcr(Frame_0);
ImageYuv_1=rgb2ycbcr(Frame_1);
Y_0=ImageYuv_0(:,:,1);%Y
Y_1=ImageYuv_1(:,:,1);%Y
GrayHist_0=imhist(Y_0); %获取灰度直方图
GrayHist_1=imhist(Y_1); %获取灰度直方图
FrameDiff=sum(abs(GrayHist_1-GrayHist_0));%当前帧与前一帧灰度直方图帧差
SumFrameDiff=(SumFrameDiff+FrameDiff);
AveFrameDiff=SumFrameDiff/(GapFrameCnt-1);
end
最终经过大量测试,确定双阈值在分别为3和5时检测效果较好,视频场景检测效率大概为90%。
而对于视频场景切换检测算法的FPGA实现,比较关键的内容在于帧差的求取。帧差,顾名思义,两帧的像素之差,而本文使用的两帧的亮度分量(Y)差。对于1080P的图像存储,自然会使用到DDR。而计算帧差最少需要两帧数据,假如使得DDR同时输出相邻的两帧,然后对数据流分别统计求直方图,依次相减,再求和,倒的确是能得到两帧的亮度差。但是该方法DDR控制较为复杂,且最终得到像素差位宽太大,所以不采用。本文选用DDR缓存整帧图像+bram存储图像亮度直方图的方式实现。即选用两组bram乒乓操作,一组对DDR输出一帧图像数据进行抽样,在行方向每4个点抽取一次,在列方向每4列抽取一列,且像素位宽由10bit降为8bit,求取对应的灰度直方图数据,并将其写入bram中;另一组bram在当前帧做完灰度直方图统计时,依次读取上一帧缓存的对应位置灰度直方图数据,并依次做差求和,最终求出灰度直方图帧差以及平均帧差。
其中,灰度直方图的统计也是极其重要的一个环节。由前面的分析可知,为缩小数据量对一帧图像进行采样,数据量由原来的1920*1080变为现在的129600(17bit),可这仍然是一个非常大的数字,尤其在帧差计算时带来的累积求和,所以进一步降低统计数据量, 采用2级双口BRAM实现灰度直方图统计。即第一级bram采用9bit位宽,第二级bram为8bit。特选用像素灰度值寻址,当一个8bit亮度统计值计满512时则第二级bram对应地址数值加一,直到统计完所有采样点。在这之中,选用双口bram的原因在于灰度直方图的统计过程中,
当一个新的像素点传来时,需提前一拍读取该地值统计值,然后累加。部分RTL代码如下所示:
//bram读地址,提前2拍,一拍是先于bram写,一拍是bram读延迟
always @(posedge vid_clk or posedge reset)begin
if(reset)begin
BRAM_addrb_0<='h0;
BRAM_addrb_1<='h0;
end
else if(HistData_rden)begin//外部读取直方图数据
if(pos_HistData_rden)begin
BRAM_addrb_0<= odd_frame ? 'h0 : BRAM_addrb_0;
BRAM_addrb_1<=~odd_frame ? 'h0 : BRAM_addrb_1;
end
else begin
BRAM_addrb_0<= odd_frame ? BRAM_addrb_0+1'b1 : BRAM_addrb_0;//奇数帧读bram0
BRAM_addrb_1<=~odd_frame ? BRAM_addrb_1+1'b1 : BRAM_addrb_1;//偶数帧读bram1
end
end
else begin//写直方图数据前提前2拍读
BRAM_addrb_0<= (Hist_wren && ~odd_frame) ? Hist_addr:BRAM_addrb_0;//偶数帧写bram0
BRAM_addrb_1<= (Hist_wren && odd_frame) ? Hist_addr:BRAM_addrb_1;//奇数帧读bram1
end
end
最终,为更为方便观察视频场景切换的效果,特在检测到视频场景切换时,使得边框变为红色,持续0.5s。最后检测的效果与MATLAB上测试的效果相当,正确检测率在90%左右,基本检测出了视频场景的切换。
我个人认为,双阈值灰度直方图算法有一定局限性。即当视频中的场景较为稳定时,平均帧差很小,突然来一个变动比较大的画面时,当前帧差较大,对应的帧差比就偏大,进而产生误警。当然,这也能解释该算法在一些场景下发生错误检测的现象。
视频场景切换检测的FPGA实现的更多相关文章
- 【Cocos2d-x 3.x】 场景切换生命周期、背景音乐播放和场景切换原理与源码分析
大部分游戏里有很多个场景,场景之间需要切换,有时候切换的时候会进行背景音乐的播放和停止,因此对这块内容进行了总结. 场景切换生命周期 场景切换用到的函数: bool Setting::init() { ...
- 自制Unity小游戏TankHero-2D(5)声音+爆炸+场景切换+武器弹药
自制Unity小游戏TankHero-2D(5)声音+爆炸+场景切换+武器弹药 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm ...
- Unity 中场景切换
Unity游戏开发中,单个Scene解决所有问题似乎不可能,那么多个Scene之间的切换是必然存在.如果仅仅是切换,似乎什么都好说,但是在场景比较大的时候不想让玩家等待加载或者说场景与场景之间想通过一 ...
- Cocos2d-x Lua中多场景切换生命周期
在多个场景切换时候,场景的生命周期会更加复杂.这一节我们介绍一下场景切换生命周期.多个场景切换时候分为几种情况:情况1,使用pushScene函数从实现GameScene场景进入SettingScen ...
- Faster-RCNN用于场景文字检测训练测试过程记录(转)
[训练测试过程记录]Faster-RCNN用于场景文字检测 原创 2017年11月06日 20:09:00 标签: 609 编辑 删除 写在前面:github上面的Text-Detection-wit ...
- texturepacker打包图片,场景切换时背景图有黑边
在使用TexturePacker打包图片之后,背景图在场景切换(有切换动画)时,明显能看到有黑边,在百度之后解决了. 知乎上边有网友贴出了两种解决方法,我抄过来如下: 第一种: 修改 ccConfig ...
- cocos2d-x 帧循环不严谨造成场景切换卡顿
最近在用cocos2d-x做引导界面,2dx版本是2.2.3,场景切换加上了效果,所有资源都已经使用texturepacker打包预加载,但是在实际运行调试中,场景切换相当卡顿. 各种纠结后,无意中将 ...
- JavaScript强化教程 -- cocosjs场景切换
场景切换 在main.js,将StartScene作为我们初始化运行的场景,代码如下: cc.LoaderScene.preload(g_resources, function () { cc.dir ...
- cocos2d-x场景切换动画
void StartScene::beginGame() { CCLog("beginGame"); //CCTransitionScene *trans ...
随机推荐
- Python+Selenium - iframe定位
元素在iframe中.在html当中,内嵌了另一个html (iframe) 分辨元素是否在iframe当中 在代码当中,从当前的html切换到iframe当中的html,然后在元素定位 切换方式:d ...
- Jmeter- 笔记3 - Jmeter录制功能 / 抓包
http代理服务器录制脚本: 1.新建线程组 2.添加 http代理服务器 元件 3.http代理服务器修改: 1)端口:8899,任意给个无占用的 2)目标控制器:改成刚刚新建的线程组.不改就录制会 ...
- PyTorch 自动微分
PyTorch 自动微分 autograd 包是 PyTorch 中所有神经网络的核心.首先简要地介绍,然后将会去训练的第一个神经网络.该 autograd 软件包为 Tensors 上的所有操作提供 ...
- STS或eclipse中导入新项目出现红色感叹号红色叉叉的问题
maven项目 原因: jar包缺失 没有正确配置Maven仓库 解决: Window->Preferences->Maven->Installations->Add 添加你的 ...
- java后端知识点梳理——多线程与高并发
进程与线程 进程是一个"执行中的程序",是系统进行资源分配和调度的一个独立单位 线程是进程的一个实体,一个进程中一般拥有多个线程. 线程和进程的区别 进程是操作系统分配资源的最小单 ...
- 狂神说redis笔记(四)
十二.Redis主从复制 概念 主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器.前者称为主节点(Master/Leader),后者称为从节点(Slave/Follower), ...
- Pipeline模式与Factory+Provider模式的应用
前言 我正在写FastGithub这个小麻雀项目,里面主要涉及了Pipeline模式和Factory+Provider模式,这两种设计模式,让这个项目在"ip扫描"和"i ...
- 4.3CNN卷积神经网络最详细最容易理解--tensorflow源码MLP对比
自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取: https://www.cnblogs.com/bclshuai/p/11380657.html 1.1 CNN卷积神经网络 ...
- NOIP模拟测试28「阴阳·虎·山洞」
写这几个题解我觉得我就像在按照官方题解抄一样 阴阳 题解 将题目中给的阴阳看作黑色和白色 首先我们观察到最后生成图中某种颜色必须是竖着单调递增或竖着单调递减 类似这样 否则不满足这个条件 但合法染色方 ...
- 最多能创建多少个 TCP 连接?
我是一个 Linux 服务器上的进程,名叫小进. 老是有人说我最多只能创建 65535 个 TCP 连接. 我不信这个邪,今天我要亲自去实践一下. 我走到操作系统老大的跟前,说: "老操,我 ...