背景减除

一旦背景模型建立,将背景模型和当前的图像进行比较,然后减去这些已知的背景信息,则剩下的目标物大致就是所求的前景目标了

缺点 —— 该方法基于一个不长成立的假设:所有像素点是独立的

场景建模

新的前景(物体移动的新位置) —— 旧的前景 (物体离开后留下的“空洞”)—— 背景

cvInitLineIterator()  和  CV_NEXT_LINE_POINT() 对任意直线上的像素进行采样

// 从视频的一行中读出所有像素的RGB值,收集这些数值并将其分成三个文件

#include <cv.h>
#include <highgui.h> int main(int argc,char** argv)
{
CvCapture* capture=cvCreateFileCapture("");
int max_buffer;
IplImage *rowImage;
int r[],g[],b[];
CvLineIterator iterator; FILE *fptrb=fopen("blines.csv","w"); // store the data here
FILE *fptrg=fopen("glines.csv","w");
FILE *fptrr=fopen("rlines.csv","w"); CvPoint pt1,pt2; for (;;)
{
if(!cvGrabFrame(capture))
break;
rowImage=cvRetrieveFrame(capture);
max_buffer=cvInitLineIterator(rowImage,pt1,pt2,&iterator,,); for (int j=;j<max_buffer;j++)
{
fprintf(fptrb,"%d",iterator.ptr[]);
fprintf(fptrg,"%d",iterator.ptr[]);
fprintf(fptrr,"%d",iterator.ptr[]); iterator.ptr[]=; // mark this sample in red CV_NEXT_LINE_POINT(iterator); fprintf(fptrb,"\n");
fprintf(fptrg,"\n");
fprintf(fptrr,"\n"); }
} cvReleaseCapture(capture);
fclose(fptrb);
fclose(fptrg);
fclose(fptrr); return ;
}

帧差 —— 用一帧减去另一帧,然后将足够大的差别标为前景,这种方法往往能捕捉运动目标的边缘

cvAbsDiff  cvThreshold (忽略很小的差异——比如小于15,标识其余的作为较大的差别)

可以用cvErode() 函数或者用连通域去噪

对于彩色图像,我们用相同的代码对每个颜色通道分别处理,之后在调用cvOr() 函数将所有的通道拼接在一起


平均背景法

—— 计算每个像素的平均值和标准差作为他的背景模型

平均背景法使用四个OpenCV函数 :

cvAcc 累计图像

cvAbsDiff 计算一定时间内的每帧图像之差

cvInRange 将图像分割成前景区和背景区域 (背景模型在已经学习的情况下)

cvOr 将不同的彩色通道图像中合成一个掩码图像

// 背景法 --- 只能用于背景场景中不包含运动的部分

// 为需要的不同临时图像和统计属性图像创建指针
IplImage *IavgF,IdiffF,*IprevF,*IhiF,*IlowF; IplImage *Iscratch,*Iscratch2; IplImage *Igray1,*Igray2,*Igray3;
IplImage *Ilow1,*Ilow2,*Ilow3;
IplImage *Ihi1,*Ihi2,*Ihi3; IplImage *Imaskt; float Icount; // couts number of images learned for averaging later // 创建一个函数给需要的所有临时图像分配内存 void AllocateImages(IplImage* I)
{
CvSize sz=cvGetSize(I); IavgF=cvCreateImage(sz,IPL_DEPTH_32F,);
IdiffF=cvCreateImage(sz,IPL_DEPTH_32F,);
IprevF=cvCreateImage(sz,IPL_DEPTH_32F,);
IhiF=cvCreateImage(sz,IPL_DEPTH_32F,);
IlowF=cvCreateImage(sz,IPL_DEPTH_32F,);
Ilow1=cvCreateImage(sz,IPL_DEPTH_32F,);
Ilow2=cvCreateImage(sz,IPL_DEPTH_32F,);
Ilow3=cvCreateImage(sz,IPL_DEPTH_32F,);
Ihi1=cvCreateImage(sz,IPL_DEPTH_32F,);
Ihi2=cvCreateImage(sz,IPL_DEPTH_32F,);
Ihi3=cvCreateImage(sz,IPL_DEPTH_32F,); cvZero(IavgF);
cvZero(IdiffF);
cvZero(IprevF);
cvZero(IhiF);
cvZero(IlowF);
Icount = 0.00001; // Protect against divide by zero Iscratch =cvCreateImage(sz,IPL_DEPTH_32F,);
Iscratch2 =cvCreateImage(sz,IPL_DEPTH_32F,);
Igray1 =cvCreateImage(sz,IPL_DEPTH_32F,);
Igray2 =cvCreateImage(sz,IPL_DEPTH_32F,);
Igray3 =cvCreateImage(sz,IPL_DEPTH_32F,);
Imaskt =cvCreateImage(sz,IPL_DEPTH_32F,); cvZero(Iscratch);
cvZero(Iscratch2); } // 学习积累背景图像和每一帧图像差值的绝对值
void accumulateBackground(IplImage* I)
{
static int first=;
cvCvtScale(I,Iscratch,,);
if (!first)
{
cvAcc(Iscratch,IavgF);
cvAbsDiff(Iscratch,IprevF,Iscratch2);
cvAcc(Iscratch,IdiffF);
Icount+=1.0;
}
first=;
cvCopy(Iscratch,IprevF);
} void setHighThreshold(float scale)
{
cvConvertScale(IdiffF,Iscratch,scale);
cvAdd(Iscratch,IavgF,IhiF);
cvSplit(IhiF,Ihi1,Ihi2,Ihi3,);
} void setLowThreshold(float scale)
{
cvConvertScale(IdiffF,Iscratch,scale);
cvSub(IavgF,Iscratch,IlowF);
cvSplit(IlowF,Ilow1,Ilow2,Ilow3,);
} // 计算每一个像素的均值和方差观测 (平均绝对差分)
void createModelsfromStats()
{
cvConvertScale(IavgF,IavgF,(double)(1.0/Icount));
cvConvertScale(IdiffF,IdiffF,(double)(1.0/Icount)); // make sure diff is always something
cvAddS(IdiffF,cvScalar(1.0,1.0,1.0),IdiffF);
setHighThreshold(7.0);
setLowThreshold(6.0);
// 对每一帧图像的绝对差大于平均值7倍的像素都认为是前景 } // 有了背景模型,同时给出了高低阈值,就可以用它将图像分割成前景(不能被背景模型解释的图像部分)和背景(在背景模型中,任何高低阈值之间的图像部分) void backgroundDiff(IplImage* I,IplImage* Imask)
{
cvCvtScale(I,Iscratch,,); // To float
cvSplit(Iscratch,Igray1,Igray2,Igray3); // channel 1
cvInRange(Igray1,Ilow1,Ihi1,Imask); // 是否在高低阈值之间 // channel 2
cvInRange(Igray2,Ilow2,Ihi2,Imask); // channel 3
cvInRange(Igray3,Ilow3,Ihi3,Imask); cvOr(Imask,Imaskt,Imask); // finally , invert the result
cvSubRS(Imask,,Imask);
} void DeallocateImages()
{
cvReleaseImage(&IavgF);
cvReleaseImage(&IdiffF);
cvReleaseImage(&IprevF);
cvReleaseImage(&IhiF);
cvReleaseImage(&IlowF);
cvReleaseImage(&Ilow1);
cvReleaseImage(&Ilow2);
cvReleaseImage(&Ilow3);
cvReleaseImage(&Ihi1);
cvReleaseImage(&Ihi2);
cvReleaseImage(&Ihi3);
cvReleaseImage(&Iscratch);
cvReleaseImage(&Iscratch2);
cvReleaseImage(&Igray1);
cvReleaseImage(&Igray2);
cvReleaseImage(&Igray3);
cvReleaseImage(&Imaskt); }

累计均值,方差和协方差

均值漂移

cvRunningAvg  —— 更新时,源图像占一定权重  —— 也称为,跟踪器(前一帧图像褪色的影响,参数a本质上上是设置所需要的时间)

计算方差 —— cvSquareAcc  —— 单个像素的方差正好是平方的均值减去均值的平方

计算协方差 —— cvMultiplyAcc


高级背景模型

复杂的运动目标 —— 得到美国像素或一组像素的时间序列模型 ,这种模型能够很好的处理时间起伏,缺点是需要消耗大量的内存

codebook (编码本) —— 将一个像素现在的观测值和先前的观测值作比较。如果两个值很接近,它被建模为那种颜色下的扰动,如果两个值不接近,它可以产生与该像素相关的一组色彩。

从经验角度看绝大部分背景中的变化倾向于沿着亮度轴,而不是颜色轴

在背景学习模型的codebook方法中,在每一个三颜色轴上,每一个box用两个阈值(最大和最小)定义。如果新的背景模型落到学习的阈值(learnHigh 和 learnLow 之间,这些box的边界将膨胀 (最大阈值变大,最小阈值变小)。如果新的背景样本在box和学习阈值外,将开始生成一个新的box,在背景差分模型中,也能容纳maxMod和minMod阈值。使用这些阈值。可以说,如果一个像素和box边界最大值和最小值非常接近,我们就认为它在box里面。再次调整阈值,允许模型适应特殊情形)

codebook box 容纳呈现多维不连续分布的像素,所以能更好的模拟像素的不连续分布

使用codebook 背景模型

1,使用 函数 update_codebook 在几秒钟或几分钟时间内训练一个基本的背景模型

2,使用 clear_stale_entries 清除stale索引

3,调整阈值 minMod 和 maxMod ui已知前景达到最好的分割

4,保持一个更高级别的场景模型

5,通过 background_diff 使用训练好的模型将前景从背景中分割出来

6,定期更新学习的背景像素

7,在一个频率较慢的情况下,使用函数 clear_stale_entries 定期清理 stale 的codebook 索引

部分代码:

#include <cv.h>
#include <highgui.h> #define CHANNELS 3
typedef struct ce
{
uchar learnHigh[CHANNELS];
uchar learnLow[CHANNELS];
uchar max[CHANNELS]; // High side of box boundary
uchar min[CHANNELS];
int t_last_update; // allow us to kill stale entries
int stale; // max negative run
}code_element; typedef struct code_book{
code_element **cb;
int numEntries;
int t; // count every access
}codeBook; // 如果一个像素值的美国通道都不在 min - learnLow 和 max + learnHigh 之间,就会生成一个新的码元。距离上次更新和陈旧的时间(t_last_update)用于删除过程中学习的很少使用的码本条目 // 背景学习
int update_codebook(uchar* p,codeBook& c,unsigned* cbBounds,int numChannels)
{
int n;
unsigned int high[],low[];
for (n=;n<numChannels;n++)
{
high[n]=*(p+n)+*(cbBounds+n);
if(high[n]>)
high[n]=;
low[n]=*(p+n)-*(cbBounds+n);
if(low[n]<)
low[n]=;
} // see if this fits an existing codeword
int matchChannel; for (int i=;i<c.numEntries;i++)
{
matchChannel=;
for (n=;n<numChannels;n++)
{
if((c.cb[i]->learnLow<=*(p+n))&&(*(p+n)<=c.cb[i]->learnHigh[n]))
matchChannel++; if (matchChannel==numChannels) // if an entry war found
{
c.cb[i]->t_last_update=c.t;
// adjust this codeword for the first channel for (n=;n<numChannels;n++)
{
if (c.cb[i]->max[n]<*(p+n))
{
c.cb[i]->max[n]=*(p+n);
}
else if (c.cb[i]->min[n]>*(p+n))
{
c.cb[i]->min[n]=*(p+n);
}
}
break;
}
}
} // overhead to track potential stale entries for (int s=;s<c.numEntries;s++)
{
int negRun=c.t-c.cb[s]->t_last_update;
if (c.cb[s]->stale<negRun)
{
c.cb[s]->stale=negRun;
}
} // enter a new codeword if needed } // 学习有移动前景目标的背景 // 背景差分,寻找前景目标

用于前景清除的连通部分

包含噪声输入掩模图像,然后利用形态学“开”操作将小的噪声缩小至0,接着用“闭”操作重建由于开操作丢失的边缘部分

没有任何理由相信噪声有很大的空间相关性,这些信号又大量的非常小的区域来描述

一个功能强大的在背景中减去噪声的技术

OpenCV —— 图像局部与部分分割(一)的更多相关文章

  1. OpenCV —— 图像局部与分割(二)

    分水岭算法 将图像中的边缘转化成“山脉”,将均匀区域转化为“山谷” 分水岭算法首先计算灰度图像的梯度,这对山谷或没有纹理的盆地(亮度值低的点)的形成有效,也对山头或图像中没有主导线段的山脉(山脊对应的 ...

  2. OpenCV图像处理中“投影技术”的使用

           本文区分"问题引出"."概念抽象"."算法实现"三个部分由表及里具体讲解OpenCV图像处理中"投影技术" ...

  3. OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放

    这篇已经写得很好,真心给作者点个赞.题目都是直接转过来的,直接去看吧. Reference Link : http://blog.csdn.net/poem_qianmo/article/detail ...

  4. 学习 opencv---(12)OpenCV 图像金字塔:高斯金字塔,拉普拉斯金字塔与图片尺寸缩放

    在这篇文章里,我们一起学习下 图像金字塔 的一些基本概念,如何使用OpenCV函数pyrUp和pyrDown 对图像进行向上和向下采样,以及了解专门用于缩放图像尺寸的resize函数的用法.此博文一共 ...

  5. 关于OpenCV图像操作的默认参数问题

    本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/51559490 在使用OpenCV以及其 ...

  6. opencv——图像直方图与反向投影

    引言 在图像处理中,对于直方图这个概念,肯定不会陌生.但是其原理真的可以信手拈来吗? 本文篇幅有点长,在此列个目录,大家可以跳着看: 分析图像直方图的概念,以及opencv函数calcHist()对于 ...

  7. opencv基于HSV的肤色分割

    //函数功能:在HSV颜色空间对图像进行肤色模型分割 //输入:src-待处理的图像,imgout-输出图像 //返回值:返回一个iplimgae指针,指向处理后的结果 IplImage* SkinS ...

  8. 【OpenCV新手教程之十三】OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/26157633 作者:毛星云(浅墨) ...

  9. Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图

    Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图 分类: OpenCV图像处理2013-02-21 21:35 6459人阅读 评论(8) 收藏 举报   原文链接  ht ...

随机推荐

  1. [NOIP1999]进制位(搜索)

    P1013 进制位 题目描述 著名科学家卢斯为了检查学生对进位制的理解,他给出了如下的一张加法表,表中的字母代表数字. 例如: + L K V E L L K V E K K V E KL V V E ...

  2. HDU 4862 Jump 费用流

    又是一个看了题解以后还坑了一天的题…… 结果最后发现是抄代码的时候少写了一个负号. 题意: 有一个n*m的网格,其中每个格子上都有0~9的数字.现在你可以玩K次游戏. 一次游戏是这样定义的: 你可以选 ...

  3. 【uva 1025】A Spy in the Metro

    [题目链接]:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_probl ...

  4. ArcGIS api for javascript——使用图层定义显示地图

    描述 本例展示如何使用图层定义来限制显示在地图上的图层信息.为了了解本例做了什么,看看用于这个地图的ESRI_Census_USA服务的服务目录页是有帮助的.检查地图中的图层列表.现在注意这行代码限制 ...

  5. Windows系统时间同步出错解决办法(w32tm /register按回车,可能是为了解决时间COM注册的问题)

    有时候我们设置本地时间与Internet时间同步时,经常连接服务器time.windows.com超时,导致时间同步失败,解决办法如下: 利用快捷键"Win+R"调出运行框,输入: ...

  6. 八款常用的 Python GUI 开发框架推荐

    作为Python开发者,你迟早都会用到图形用户界面来开发应用.本文将推荐一些 Python GUI 框架,希望对你有所帮助,如果你有其他更好的选择,欢迎在评论区留言. Python 的 UI 开发工具 ...

  7. HDU 5889 Barricade (Dijkstra+Dinic)

    思路: 首先 先Dijkstra一遍 找出来最短路 不是最短路上的边都不要 然后呢 套个Dinic模板就好了-- 求个最小割 输出 大功告成~~ //By SiriusRen #include < ...

  8. Android 使用Gallery组件实现图片播放预览

    Gallery(画廊)扩展了LayoutParams,以此提供可以容纳当前的转换信息和先前的位置转换信息的场所. Activity package com.app.test01; import com ...

  9. 联想杨天 S4130-12 win10改win7 bios参数设置

    一.进入bios 开机后按 F1 二.改bion参数 1.移动到 save& Exit  ,修改 OS optimized defaults   为“Disbled” 再 “F9” 保存 2. ...

  10. Flex3中addEventListener()方法使用详解

    Flex控件对象.RemoteObject等都有一个共同的方法addEventListener. 方法详细信息: 来源于:flash.events.EventDispatcher类 addEventL ...