CNT简介

CNT算法是OpenCV Contrib 模块中的背景减除(Background segment)算法之一。相较于OpenCV提供的其他背景减 除算法,该算法具有运行速度快,检测精度高等优点。因此背景减除系列文章第一篇就先讲一下这个算法。因为CNT并没有任何参考论文,故而只能根据OpenCV的源码来进行分析。后面首先介绍OpenCV中该算法如何使用,然后再根据源码对算法进行一个详细的解释。

在OpenCV中使用CNT

  1. 创建一个CNT的实例

    cv::Ptr<cv::bgsegm::BackgroundSubtractor[ALGO_NAME]> bs = cv::bgsegm::createBackgroundSubtractorCNT([params]);
  2. 调用apply()函数进行背景减除

    bs->apply(current_frame, fgmask[, learning_rate]);

    可以看到,在OpenCV中使用CNT是非常简单的。只需简单调用两个函数即可。背景减除得到的结果通过fgmask参数返回,其中前景点背置为255,背景点被置为0

CNT源码解析

OpenCV的CNT算法有两个版本,一个版本会使用历史记录(useHistory = true),另一个版本则只考虑最近N帧的数据。


  1. useHistory 参数为 false
    void operator()(Vec4i &vec, uchar currColor, uchar prevColor, uchar &fgMaskPixelRef)
{
int &stabilityRef = vec[0];
int &bgImgRef = vec[3];
// 'threshold' 为类属性,由程序内部默认设置为 30
if (abs(currColor - prevColor) < threshold)
{
++stabilityRef;
// 'minPixelStability' 为类属性,在生成CNT的实例时由同名参数指定,默认值为 15
if (stabilityRef == minPixelStability)
{ // bg
--stabilityRef;
bgImgRef = prevColor;
}
else
{ // fg
fgMaskPixelRef = 255;
}
}
else
{ // fg
stabilityRef = 0;
fgMaskPixelRef = 255;
}
}

上面这个函数就是 useHistory 参数为 false 时的核心函数。代码很简单,就是通过简单的阈值操作判断Pixel的稳定性(stability)。如果在连续的minPixelStability帧内都保持稳定,则认为该 Pixel 是稳定的,否则该 Pixel 不稳定。在程序中,稳定的点,即为背景点。




2. useHistory 参数为 true

	void operator()(Vec4i &vec, uchar currColor, uchar prevColor, uchar &fgMaskPixelRef)
{
int &stabilityRef = vec[0];
int &historyColorRef = vec[1];
int &histStabilityRef = vec[2];
int &bgImgRef = vec[3];
// 'thresholdHistory' 参数为类属性,由程序内部设置为 30
if (abs(currColor - historyColorRef) < thresholdHistory)
{ // No change compared to history - this is maybe a background
stabilityRef = 0;
incrStability(histStabilityRef);
/*********************************************************
inline void incrStability(int &histStabilityRef)
{
// 'maxPixelStability' 参数在创建CNT实例时由程序员制定。默认为 900
if (histStabilityRef < maxPixelStability)
{
++histStabilityRef;
}
}
********************************************************/ if (histStabilityRef <= minPixelStability)
{
fgMaskPixelRef = 255;
}
else
{
bgImgRef = historyColorRef;
}
}
// 'threshold' 参数同上
else if (abs(currColor - prevColor) < threshold)
{ // No change compared to prev - this is maybe a background
incrStability(stabilityRef);
/*********************************************************
inline void decrStability(int &histStabilityRef)
{
if (histStabilityRef > 0)
{
--histStabilityRef;
}
}
********************************************************/ if (stabilityRef > minPixelStability)
{ // Stable color - this is maybe a background
if (stabilityRef >= histStabilityRef)
{
historyColorRef = currColor;
histStabilityRef = stabilityRef;
bgImgRef = historyColorRef;
}
else
{ // Stable but different from stable history - this is a foreground
decrStability(histStabilityRef);
fgMaskPixelRef = 255;
}
}
else
{ // This is FG.
fgMaskPixelRef = 255;
}
}
else
{ // Color changed - this is defently a foreground
stabilityRef = 0;
decrStability(histStabilityRef);
fgMaskPixelRef = 255;
}
}

上面这个函数就是 useHistory 参数为 true 时的核心函数。代码也很简单。程序在运行过程中会 记录从程序运行到当前时刻为止 ,稳定时间最长的 Pixel 的灰度值 historyColorRef 和它的稳定时间 histStabilityRef。在新的一帧来到时,依然是通过一系列的阈值比较操作来判断 Pixel 的稳定性,从而判断其是否为背景点。




3. 区别

通过源码,我们不难发现, 两者区别在于是 useHistory 参数。 useHistory 参数为 true 时,程序保存历史记录,并将之作为第一判据,反之程序不会保存历史记录,因而只是简单的将 Pixel 最近一段时间的稳定性作为判据。 不使用历史记录的好处在于运动物体经过场景(Scene)时,不仅物体当前时刻的位置会被检测标记为前景点,最近一段时间运动经过的地方也会背标记为前景点,换言之,算法可以获得物体最近一段时间的运动轨迹 。反之, 使用历史记录,可以获得更好的检测效果,检测到的运动区域更准确

运行效果截图

左边为 useHistory = true , 右边为 fasle

总结

从CNT的源码可以看到,每当新的一帧输入时,只需要遍历一遍图像,进行一些简单的加减操作即可完成对像素点的分类。因此CNT算法相较于后面会讲到的GMM系列和LSBP背景减除算法,在运行速度和内存占用上具有得天独厚的优势。另外,算法的检测精度也很高。在对算法速度要求较高时,可以首先考虑使用该算法。

Background Segment CNT的更多相关文章

  1. anime.js 简单入门教程

    anime.js是一个强大的用来制作动画的javascript库,虽然功能没有GASP(greensock)强大,但胜在它足够轻便,gzip压缩完只有9kb左右,麻雀虽小,却五脏俱全. 下面就来看看如 ...

  2. 3dContactPointAnnotationTool开发日志(三三)

      添加背景图片后发现Runtime Transform Gizmo无法选中物体了:   于是改了一下EditorObjectSelection.cs中的WereAnyUIElementsHovere ...

  3. bzoj 3524 可持久化线段树

    我们可以先离散化,然后建立权值的可持久化线段树,记录每个数出现的次数,对于区间询问直接判断左右儿子的cnt是不是大于(r-k+1)/2,然后递归到最后一层要是还是大于就有,否则不存在. 反思:挺简单一 ...

  4. 几个div并列显示效果消除之间的间隔

    今天在做一个静态页面时,头部的广告条是很大一张图片,考虑到网页访问时的加载速度,因此需要把一幅图拆成几个尺寸较小的图片来作为背景图,但是采用div来布局时,出现了div不能显示在一行的情况,所以开始想 ...

  5. 【BZOJ-3165】Segment 李超线段树(标记永久化)

    3165: [Heoi2013]Segment Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 368  Solved: 148[Submit][Sta ...

  6. Greenplum failed segment的恢复方法

    [前记] Segment检测及故障切换机制GP Master首先会检测Primary状态,如果Primary不可连通,那么将会检测Mirror状态,Primary/Mirror状态总共有4种:1. P ...

  7. HDURevenge of Segment Tree(第二长的递增子序列)

    HDURevenge of Segment Tree(第二长的递增子序列) 题目链接 题目大意:这题是求第二长的递增子序列. 解题思路:用n^2的算法来求LIS,可是这里还要记录一下最长的那个序列是否 ...

  8. android TranslateAnimation 顶部segment分段移动动画

    这里实现的功能是从主页布局的fragment点击跳转到一个acitivity,然后顶部是一个切换的segment顶部是一个listview,点击segment分段让listview加载不同的内容.我这 ...

  9. codeforces 242E - XOR on Segment (线段树 按位数建树)

    E. XOR on Segment time limit per test 4 seconds memory limit per test 256 megabytes input standard i ...

随机推荐

  1. 栅格那点儿事(四B)---多波段栅格数据的显示

    多波段栅格数据的显示 我上面说了这么多,可能有的人会觉得平时也根本用不上.自然,说起影像数据,大家接触到对多的就是最最常见的航片或卫片.对于这种栅格数据呢,大多数的场景下,都只需实现一个效果,就是最接 ...

  2. LotusScript_批量更改数据库标识符(id)

    OA开发中经常要搭建测试环境,测试环境的数据库与原数据库不能有ID冲突现象,以防混淆.以下是一个批量修改数据库标识符的方法,其中,取得这些需要更改的数据库,需要导出源服务器上的数据库路径和名称,方法详 ...

  3. 轻松完成excel读写操作- 基于POI的框架BingExcel的使用(1)

    Bingexcel User Guide 使用maven进行项目开发目前项目的maven仓库是在github上,浏览地址为 https://github.com/bingyulei007/mvn-re ...

  4. Use Exception.ToString() instead of Exception.Message.

    Exception.Message contains only the message (doh) associated with the exception. Example: Object ref ...

  5. android错误整理

    1.Caused by: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientat ...

  6. php的yii框架开发总结1

    最近用php的yii框架写了一个小的demo,虽然不复杂,但是也学习了很多东西,现在总结一下. 项目需求:为几个教研室写一个日报系统,每个人每天写日报,并且系统有自动实现发邮件功能. 额外要求:1.人 ...

  7. sudoers文件解析

    分类: LINUX 今天在用户组中新加了一个普 通用户,开始这个用户没有sudo权限,于是通过sudo visudo修改了sudo的配置文件,赋予了普通用户的root权限.后来想着能不能将/etc/s ...

  8. VOS落地网关前缀优先级

    问题描述: 假如:A客户业务方向:酒水B客户业务方向:增值酒水业务网关前缀:9150增值业务网关前缀:660 公司原来落地全跑酒水量9150前缀,但B客户加入后公司又不想添加新的落地网关,计划在原来网 ...

  9. SQL:数据库批量插入数据

    测试中有些功能要求有足够的数据进行测试,当输入字段较多时通过页面添加很慢.业务只关联单个数据库表可以通过数据库批量插入数据 批量插入数据示例: declare @i int--声明变量 --变量初始化 ...

  10. DFS+BFS(POJ3083)

    题目链接:http://poj.org/problem?id=3083 解题报告:这个题目,搜最短路,没有什么问题.优先走左边,走右边,有很多说法,思路大概都相同,都是记录当前朝向,根据数学公式(i+ ...