背景提取——码书法(codebook),一些总结和改进

简介

  码书法,是对每个像素建立一个记录背景范围的码书,一个码书上包含多个表示背景范围的盒子,类似于颜色空间YUV(背景颜色变化多发生在亮度轴V上)上漂浮着的气团。如果新像素和先前建立的盒子足够近,则扩展盒子。否则,新建新的盒子。为了能在存在移动的前景时进行背景学习,需要更低频率地(为了更好地学习背景和避免清理掉背景盒子)清理码书中的被判定为前景的盒子。最后进行背景差分,不在码书中全部盒子范围内的为前景,否则,为背景。
  由于不可避免的存在各种干扰,需要使用形态学操作和连通分量法进行处理,最后用多边形逼近或者凸包逼近绘出处理后的前景结果。

结构

  • 码书类继承自std::vector,加上记录当前帧数的成员变量t。
  • 码数单元(盒子),包括盒子上下边界(max,min)、学习阈上下边界(learnHigh,learnLow)、最后一次被击中帧数(t_last_update)、盒子创建时帧数(t_create)(自己加的成员变量,改进stale计算方式)、用于判断长时间未被击中(stale)。

codeBookh.h

#pragma once
#include <iostream>
#include <opencv.hpp>
using namespace std;

//#define TRANSPOSE

#define CHANNELS 3
#define DP_EPSILON_DENOMINATOR 100.0
#define CVCLOSE_KSIZE 5 //闭操作核大小
#define CVOPEN_ITR 1//腐蚀膨胀次数

string videoname = "test2.mp4";
unsigned int bound[3] = {
    10,10,10 };//像素边框,用于调整学习阈
int minMod[3] = {
    5,5,5 };//误差范围,用于检测前景
int maxMod[3] = {
    5,5,5 };

int fpr = 300;//每轮学习帧数
int fpsScale = 2;//每隔几帧取一帧计算

int rsb = 8;//图像缩小倍数
bool p1h0 = true;
int deleNum = 0;//调用清理盒子次数

float minAreaScale = 0.005;//最小面积比例

/*
码书单元(盒子)
*/
class CodeElement {
   
public:
	uchar learnHigh[CHANNELS];//学习阈值上限
	uchar learnLow[CHANNELS];//学习阈值下限
	uchar max[CHANNELS];//盒子上边界
	uchar min[CHANNELS];//盒子下边界
	int t_last_update;//最后一次被命中的时间戳
	int stale;//反映历史最长没命中此盒子的时间段,time(此时)-t_last_update>stale便更新,越大表示此盒子越不是背景(干扰或移动前景)
	int t_create;//创建时间戳
	CodeElement() {
   
		for (int i = 0; i < CHANNELS; i++)
			learnHigh[i] = learnLow[i] = max[i] = min[i] = 0;
		t_last_update = t_create = 0;
	}

	CodeElement& operator=(const CodeElement& ce) {
   
		for (int i = 0; i < CHANNELS; i++) {
   
			learnHigh[i] = ce.learnHigh[i];
			learnLow[i] = ce.learnLow[i];
			max[i] = ce.max[i];
			min[i] = ce.min[i];
		}
		t_last_update = ce.t_last_update;
		t_create = ce.t_create;
		stale = ce.stale;
		return *this;
	}

	CodeElement(const CodeElement& ce) {
    *this = ce; }
};

/*
码书,每个像素上对应一个码书
*/
class CodeBook :public std::vector<CodeElement> {
   //vector太低效,可用MAX_CODE来限制最大码书大小,静态分配数组CodeElement[MAX_CODES]
public:
	int t;//累加的点的个数
	CodeBook() {
    t = 0; }
	CodeBook(int n) :std::vector<CodeElement>(n) {
    t = 0; }//构建有n个码书单元的码书,更新出直接用book[i]
};

int updateCodebook(const cv::Vec3b& p, CodeBook& c, unsigned* cbBounds, int numChannels);
int clearStaleEntries(CodeBook& c);
uchar backgroundDiff(const cv::Vec3b& p, CodeBook& c, int numChannels, int* minMod, int* maxMod);
void findConnectedComponents(cv::Mat& mask, std::vector<cv::Rect>& bbs, std::vector<cv::Point>& centers, float minArea, bool poly1_hull0 = 1);

背景学习

  由于在背景学习时,stale只是t-t_last_update并不能很好的表示此盒子在一轮视频流中未被击中的情况。这样会导致在盒子清理时,视频流偏后面出现的移动前景不能被清理掉。所以,此处修改为t - t_last_update + t_create。
  每个像素自带一个自定义大小的边框,用于在创建新盒子时设置学习阈,或者是在扩展旧盒子时调整学习阈。

#include "pch.h"
#include 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值