OpenCV实现平均背景法

 更新时间:2020年03月21日 07:12:35   作者:thystar  
这篇文章主要为大家详细介绍了OpenCV实现平均背景法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

平均背景法的基本思想是计算每个像素的平均值和标准差作为它的背景模型。

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

  • cvAcc(),累积图像;
  • cvAbsDiff() ,计算一定时间内的每帧图像只差;
  • cvInRange(), 将图像分割成前景区域和背景区域;
  • cvOr(), 将不同的彩色通道图像中合成为一个掩膜图像

代码:

/*
平均背景法
*/
 
#include "highgui.h"
#include "cv.h"
#include<stdlib.h>
#include<stdio.h>
 
//为不同的临时指针图像和统计属性创建指针
 
//Float, 3-channel images
IplImage* IavgF, * IdiffF, * IprevF, * IhiF, *IlowF;
 
IplImage* Iscratch, *Iscratch2;
 
//Float 1-channel images
 
IplImage* Igray1, * Igray2, * Igray3;
IplImage* Ilow1, * Ilow2, * Ilow3;
IplImage* Ihi1, *Ihi2, * Ihi3;
 
//Byte, 1-channel image
IplImage* Imask;
IplImage* Imaskt;
 
//Counts number of images learned for averaging later.
float Icount;
 
// 创建一个函数来给需要的所有临时图像分配内存
//为了方便,我们传递一幅图像(来自视频)作为大小参考来分配临时图像
 
void AllocateImages(IplImage* I)
{
 CvSize sz = cvGetSize(I);
 IavgF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
 IdiffF = cvCreateImage(sz, IPL_DEPTH_32F,3);
 IprevF = cvCreateImage(sz, IPL_DEPTH_32F,3);
 IhiF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
 IlowF = cvCreateImage(sz, IPL_DEPTH_32F,3);
 
 Ilow1 = cvCreateImage(sz, IPL_DEPTH_32F,1);
 Ilow2 = cvCreateImage(sz, IPL_DEPTH_32F,1);
 Ilow3 = cvCreateImage(sz, IPL_DEPTH_32F,1);
 Ihi1 = cvCreateImage(sz, IPL_DEPTH_32F,1);
 Ihi2 = cvCreateImage(sz, IPL_DEPTH_32F,1);
 Ihi3 = cvCreateImage(sz, IPL_DEPTH_32F,1);
 cvZero(IavgF);
 cvZero(IdiffF);
 cvZero(IprevF);
 cvZero(IhiF);
 cvZero(IlowF);
 Icount = 0.00001;
 
 Iscratch = cvCreateImage(sz, IPL_DEPTH_32F,3);
 Iscratch2 = cvCreateImage(sz, IPL_DEPTH_32F,3);
 
 Igray1 = cvCreateImage(sz, IPL_DEPTH_32F,1);
 Igray2 = cvCreateImage(sz, IPL_DEPTH_32F,1);
 Igray3 = cvCreateImage(sz, IPL_DEPTH_32F,1);
 
 Imask = cvCreateImage(sz, IPL_DEPTH_8U, 1);
 Imaskt = cvCreateImage(sz, IPL_DEPTH_8U,1);
 
 cvZero(Iscratch);
 cvZero(Iscratch2);
}
 
//学习累积背景图像和每一帧图像差值的绝对值
// Learn the background statistics for one more frame
// I is a color sample of the background, 3-channel, 8u
void accumulateBackground(IplImage *I)
{
 static int first = 1;
 cvCvtScale(I, Iscratch, 1, 0);
 if(!first)
 {
 cvAcc(Iscratch,IavgF);
 cvAbsDiff(Iscratch, IprevF, Iscratch2);
 cvAcc(Iscratch2,IdiffF);
 Icount += 1.0;
 }
 first = 0;
 cvCopy(Iscratch, IprevF);
}
 
//setHighThreshold和setLowThreshold都是基于每一帧图像平均绝对差设置阈值的有效函数
void setHighThreshold(float scale)
{
 cvConvertScale(IdiffF, Iscratch, scale);
 cvAdd(Iscratch, IavgF, IhiF);
 cvSplit(IhiF, Ihi1, Ihi2, Ihi3, 0);
}
void setLowThreshold(float scale)
{
 cvConvertScale(IdiffF, Iscratch, scale);
 cvSub(IavgF, Iscratch, IlowF);
 cvSplit(IlowF, Ilow1, Ilow2, Ilow3, 0);
}
 
//当积累了足够多的帧图像之后,就将其转化为一个背景的统计模型
//计算每一个像素的均值和方差观测
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);
}
 
//有了背景模型,同时给出了高,低阈值,就能用它将图像分割为前景和背景
// Create a binary: 0,255 mask where 255 means foregrond pixel
// I Input image, 3-channel, 8u
//Imask 
void backgroundDiff(IplImage* I)
{
 cvCvtScale(I, Iscratch, 1, 0);
 cvSplit(Iscratch, Igray1, Igray2, Igray3, 0);
 
 //Channel 1
 cvInRange(Igray1, Ilow1, Ihi1, Imask);
 
 //Channel 2
 cvInRange(Igray2, Ilow2, Ihi2, Imaskt);
 cvOr(Imask, Imaskt, Imask);
 
 //Channel 3
 cvInRange(Igray3, Ilow3, Ihi3, Imaskt);
 cvOr(Imask, Imaskt, Imask);
 
 //Finally, invert the result
 cvSubRS(Imask, cvScalar(255), Imask);
}
 
//完成背景建模后, 释放内存
void DeallocateImage()
{
 cvReleaseImage(&IavgF);
 cvReleaseImage(&IdiffF);
 cvReleaseImage(&IprevF);
 cvReleaseImage(&IhiF);
 cvReleaseImage(&IlowF);
 cvReleaseImage(&Ilow1);
 cvReleaseImage(&Ilow2);
 cvReleaseImage(&Ilow3);
 cvReleaseImage(&Iscratch);
 cvReleaseImage(&Iscratch2);
 cvReleaseImage(&Igray1);
 cvReleaseImage(&Igray2);
 cvReleaseImage(&Igray3);
 cvReleaseImage(&Imaskt);
}
 
//主函数
int main()
{
 CvCapture* capture = cvCreateFileCapture("tree.avi");
 if(!capture)
 {
 return -1;
 }
 cvNamedWindow("win1");
 cvNamedWindow("win2");
 
 IplImage* rawImage = cvQueryFrame(capture);
 cvShowImage("win1", rawImage);
 
 AllocateImages(rawImage);
 int i = 0;
 while(1)
 {
 if(i <= 30)
 {
  accumulateBackground(rawImage);
  if(i == 30)
  {
  createModelsfromStats();
  }
 }
 else
 {
  backgroundDiff(rawImage);
 }
 cvShowImage("win2", Imask);
 
 if(cvWaitKey(33) == 27)
 {
  break;
 }
 if(!(rawImage = cvQueryFrame(capture)))
 {
  break;
 }
 cvShowImage("win1", rawImage);
 if(i == 56 || i == 63)
  cvWaitKey();
 i = i+1;
 }
 DeallocateImage();
 return 0;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • C++中volatile限定符的实现示例

    C++中volatile限定符的实现示例

    volatile关键字在C和C++中用于确保编译器不优化特定变量的访问,主要用于多线程和硬件交互场景,本文就来介绍C++中volatile限定符的实现示例,感兴趣的可以了解一下
    2024-11-11
  • C语言深入分析递归函数的实现

    C语言深入分析递归函数的实现

    递归(recursive)函数是“自己调用自己”的函数,无论是采用直接或间接调用方式。间接递归意味着函数调用另一个函数(然后可能又调用第三个函数等),最后又调用第一个函数。因为函数不可以一直不停地调用自己,所以递归函数一定具备结束条件
    2022-04-04
  • C语言文件操作之fread函数详解

    C语言文件操作之fread函数详解

    fread()函数用来从指定文件中读取块数据,下面这篇文章主要给大家介绍了关于C语言文件操作之fread函数的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • C++11 thread多线程编程创建方式

    C++11 thread多线程编程创建方式

    这篇文章主要介绍了C++11 thread多线程编程的相关知识,包括线程的创建方式结束方式及互斥锁的实例代码详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-12-12
  • C语言实现图的最短路径Floyd算法

    C语言实现图的最短路径Floyd算法

    这篇文章主要为大家详细介绍了C语言实现图的最短路径Floyd算法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • C++使用OpenCV实现证件照蓝底换成白底功能(或其他颜色如红色)详解

    C++使用OpenCV实现证件照蓝底换成白底功能(或其他颜色如红色)详解

    这篇文章主要介绍了C++使用OpenCV实现证件照蓝底换成白底功能(或其他颜色如红色),结合实例形式详细分析了OpenCV颜色转换相关操作原理与实现技巧,需要的朋友可以参考下
    2019-12-12
  • C++抽象数据类型介绍

    C++抽象数据类型介绍

    这篇文章主要介绍了C++抽象数据类型,我们在学数据结构的时候,经常遇到的一个概念就是抽象数据类型(Abstract Data Type),简称ADT。下面我们就对ADT作更多介绍,需要的朋友可以参考一下
    2022-01-01
  • C++中virtual继承的深入理解

    C++中virtual继承的深入理解

    本篇文章是对C++中的virtual继承进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • c++实现高精度加法

    c++实现高精度加法

    高精度运算是指参与运算的数(加数,减数,因子……)范围大大超出了标准数据类型(整型,实型)能表示的范围的运算。例如,求两个200位的数的和。这时,就要用到高精度算法了。
    2017-05-05
  • C语言中逻辑运算符与条件运算符的学习教程

    C语言中逻辑运算符与条件运算符的学习教程

    这篇文章主要介绍了C语言中逻辑运算符与条件运算符的学习教程,条件运算符问号即三目运算符使用起来十分方便,需要的朋友可以参考下
    2016-04-04

最新评论