OpenCV实现平均背景法
作者:thystar 发布时间:2023-06-28 18:25:41
标签: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;
}
来源:https://blog.csdn.net/thystar/article/details/41279305


猜你喜欢
- 简单的IM聊天程序由于项目需要做一个基于XMPP协议的Android通讯软件。故开始研究XMPP。XMPP协议采用的是客户端-服务器架构,所
- 如果我们的程序是在单线程下运行,或者是不必考虑到线程同步问题,我们应该优先使用StringBuilder类;如果要保证线程安全,自然是Str
- 研发背景公司安全部目前针对内部系统的网络访问日志的安全审计,大部分都是T+1时效,每日当天,启动Python编写的定时任务,完成昨日的日志审
- spring和mybatis整合整合思路需要spring通过单例方式管理SqlSessionFactory。spring和mybatis整合
- 1、说明isInterrupted()可以判断当前线程是否被中断,仅仅是对interrupt()标识的一个判断,并不会影响标识发生任何改变(
- 前几天刚好有需求要把emoji对应的Unicode编码转换成文字,比如1f601对应的这个笑脸😁,但没有找到C#的把1f601转换成文字的方
- 本文实例分析了C#队列Queue用法。分享给大家供大家参考。具体分析如下:队列(Queue)在程序设计中扮演着重要的角色,因为它可以模拟队列
- 目录1 Exchanger 介绍2 Exchanger 实例exchange等待超时3 实现原理1 Exchanger 介绍前面分别介绍了C
- 一、前言随着 JDK 1.8 Streams API 的发布,使得 HashMap 拥有了更多的遍历的方式,但应该选择那种遍历方式?反而成了
- 聊一聊kotlin协程“低级”apiKotlin协程已经出来很久了,相信大家都有不同程度的用上了,由
- 本文实例为大家分享了Opencv实现画笔功能的具体代码,供大家参考,具体内容如下#include<iostream>#inclu
- 前言本篇文章将教你作为一个.NET程序员如何快入门Spring Boot。你不需要用Eclipse,也不需要用IDEA。已经习惯了VS,其他
- 在这里,记录我在项目中使用log4net记录本地日志的步骤。在不会之前感觉很难,很神秘,一旦会了之后其实没那么难。其实所有的事情都是一样的,
- 在upload.jsp页面中将多个文件域对象命名为相同的名字,这样在action中就可以将多个文件域解析成一个数组,数组的大小就是文件域的个
- 本文实例讲述了C#将制定目录文件名转换成大写的方法。分享给大家供大家参考。具体如下:using System;using System.IO
- 一. 可变字符串1. 简介在Java中,我们除了可以通过String类创建和处理字符串之外,还可以使用StringBuffer和String
- 使用Spring Boot 与Dubbo集成,这里我之前尝试了使用注解的方式,简单的使用注解注册服务其实是没有问题的,但是当你涉及到使用注解
- 骑士周游问题在8x8的国际棋盘上,按照马走日的规则,验证是否能够走遍棋盘。解题思路1、创建棋盘 chessBoard,是一个二维数组。2、将
- 作为工厂方法模式的孪生兄弟,相信大家对工厂方法模式和抽象工厂模式傻傻分不清楚吧。那么,就让我来拯救大家吧!抽象工厂模式定义:所谓抽象工厂模式
- 本文实例为大家分享了C#基于Socket的TCP通信实现聊天室的具体代码,供大家参考,具体内容如下一、Socket(套接字)通信概念套接字(