背景建模之单高斯实现
高斯分布與背景建模的關系:圖像中每一個像素點的顏色值作為一個隨機過程X,并假設該點的像素值出現的概率服從高斯分布。令I(x,y,t)表示像素點(x,y,t)在t時刻的像素值,則有:
其中和分別為t時刻該像素高斯分布的期望值和標準差。
算法流程:
1.用第一幀圖像數據初始化背景模型,其中std_init通常設置為20。
2.檢測前景與背景像素。
背景像素檢測公式:
前景像素檢測公式:
3.對、、背景值進行更新,更新公式如下:
4.返回到2直至停止。
算法實現代碼(vc6.0+opencv1.0):
// singleGaussian.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <highgui.h>
#include <cv.h>
#include <math.h>
#include <cxcore.h>
int main(int argc, char* argv[])
{
//新建窗口
? ? cvNamedWindow("origin", CV_WINDOW_AUTOSIZE);
? ? cvNamedWindow("background", CV_WINDOW_AUTOSIZE);
? ? cvNamedWindow("foreground", CV_WINDOW_AUTOSIZE);
? ? double alpha = 0.05; ? ?//背景建模alpha值
? ? double std_init = 20; ? ?//初始標準差
? ? double var_init = std_init * std_init; ? ?//初始方差 ? ?
? ? double lamda = 2.5 * 1.2; ? ?//背景更新參數
? ? //視頻文件
? ? CvCapture *capture = NULL;
? ? //讀取視頻文件
? ? if (argc == 1)
? ? {
? ? ? ? //從攝像頭讀入
? ? ? ? capture = cvCreateCameraCapture(0);
? ? }
? ? else if (argc == 2)
? ? {
? ? ? ? //從文件讀入
? ? ? ? capture = cvCreateFileCapture(argv[1]);
? ? }
? ? else
? ? {
? ? ? ? //讀入錯誤
? ? ? ? printf("input error\n");
? ? ? ? return -1;
? ? }
? ? IplImage *frame = NULL; ? ? ? ?//原始圖像
? ? IplImage *frame_u = NULL; ? ?//期望圖像
? ? IplImage *frame_d = NULL; ? ?//前景圖像
? ? IplImage *frame_var = NULL; ? ?//方差圖像
? ? IplImage *frame_std = NULL; ? ?//標準差
? ? CvScalar pixel = {0}; ? ? ? ?//像素原始值
? ? CvScalar pixel_u = {0}; ? ? ? ?//像素期望
? ? CvScalar pixel_d = {0}; ? ? ? ?//像素前景
? ? CvScalar pixel_var = {0}; ? ?//像素方差
? ? CvScalar pixel_std = {0}; ? ?//像素標準差
? ? //初始化frame_u, frame_var, frame_std
? ? frame = cvQueryFrame(capture);
? ? frame_u = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 3);
? ? frame_d = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 3);
? ? frame_var = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 3);
? ? frame_std = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 3);
? ? for (int y = 0; y < frame->height; ++y)
? ? {
? ? ? ? for (int x = 0; x < frame->width; ++x)
? ? ? ? {
? ? ? ? ? ? pixel = cvGet2D(frame, y, x);
? ? ? ? ? ? pixel_u.val[0] = pixel.val[0];
? ? ? ? ? ? pixel_u.val[1] = pixel.val[1];
? ? ? ? ? ? pixel_u.val[2] = pixel.val[2];
? ? ? ? ? ? pixel_d.val[0] = 0;
? ? ? ? ? ? pixel_d.val[1] = 0;
? ? ? ? ? ? pixel_d.val[2] = 0;
? ? ? ? ? ? pixel_std.val[0] = std_init;
? ? ? ? ? ? pixel_std.val[1] = std_init;
? ? ? ? ? ? pixel_std.val[2] = std_init;
? ? ? ? ? ? pixel_var.val[0] = var_init;
? ? ? ? ? ? pixel_var.val[1] = var_init;
? ? ? ? ? ? pixel_var.val[2] = var_init;
? ? ? ? ? ? cvSet2D(frame_u, y, x, pixel_u);
? ? ? ? ? ? cvSet2D(frame_d, y, x, pixel_d);
? ? ? ? ? ? cvSet2D(frame_var, y, x, pixel_var);
? ? ? ? ? ? cvSet2D(frame_std, y, x, pixel_std);
? ? ? ? }
? ? }
? ? while (cvWaitKey(33) != 27) ? ? ? ?//按ESC鍵退出, 幀率33ms
? ? {
? ? ? ? frame = cvQueryFrame(capture);
? ? ? ? //視頻結束退出
? ? ? ? if (!frame)
? ? ? ? {
? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? //單高斯背景更新
? ? ? ? for (int y = 0; y < frame->height; ++y)
? ? ? ? {
? ? ? ? ? ? for (int x = 0; x < frame->width; ++x)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? pixel = cvGet2D(frame, y, x);
? ? ? ? ? ? ? ? pixel_u = cvGet2D(frame_u, y, x);
? ? ? ? ? ? ? ? pixel_d = cvGet2D(frame_d, y, x);
? ? ? ? ? ? ? ? pixel_std = cvGet2D(frame_std, y, x);
? ? ? ? ? ? ? ? pixel_var = cvGet2D(frame_var, y, x);
? ? ? ? ? ? ? ? //|I-u| < lamda*std 時認為是背景, 進行更新
? ? ? ? ? ? ? ? if (fabs(pixel.val[0] - pixel_u.val[0]) < lamda * pixel_std.val[0] &&
? ? ? ? ? ? ? ? ? ? fabs(pixel.val[1] - pixel_u.val[1]) < lamda * pixel_std.val[1] &&
? ? ? ? ? ? ? ? ? ? fabs(pixel.val[2] - pixel_u.val[2]) < lamda * pixel_std.val[2])
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? //更新期望 u = (1-alpha)*u + alpha*I
? ? ? ? ? ? ? ? ? ? pixel_u.val[0] = (1 - alpha) * pixel_u.val[0] + alpha * pixel.val[0];
? ? ? ? ? ? ? ? ? ? pixel_u.val[1] = (1 - alpha) * pixel_u.val[1] + alpha * pixel.val[1];
? ? ? ? ? ? ? ? ? ? pixel_u.val[2] = (1 - alpha) * pixel_u.val[2] + alpha * pixel.val[2];
? ? ? ? ? ? ? ? ? ? //更新方差 var = (1-alpha)*var + alpha*(I-u)^2
? ? ? ? ? ? ? ? ? ? pixel_var.val[0] = (1 - alpha) * pixel_var.val[0] +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (pixel.val[0] - pixel_u.val[0]) * (pixel.val[0] - pixel_u.val[0]);
? ? ? ? ? ? ? ? ? ? pixel_var.val[1] = (1 - alpha) * pixel_var.val[1] +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (pixel.val[1] - pixel_u.val[1]) * (pixel.val[1] - pixel_u.val[1]);
? ? ? ? ? ? ? ? ? ? pixel_var.val[2] = (1 - alpha) * pixel_var.val[2] +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (pixel.val[2] - pixel_u.val[2]) * (pixel.val[2] - pixel_u.val[2]);
? ? ? ? ? ? ? ? ? ? //更新標準差
? ? ? ? ? ? ? ? ? ? pixel_std.val[0] = sqrt(pixel_var.val[0]);
? ? ? ? ? ? ? ? ? ? pixel_std.val[1] = sqrt(pixel_var.val[1]);
? ? ? ? ? ? ? ? ? ? pixel_std.val[2] = sqrt(pixel_var.val[2]);
? ? ? ? ? ? ? ? ? ? //寫入矩陣
? ? ? ? ? ? ? ? ? ? cvSet2D(frame_u, y, x, pixel_u);
? ? ? ? ? ? ? ? ? ? cvSet2D(frame_var, y, x, pixel_var);
? ? ? ? ? ? ? ? ? ? cvSet2D(frame_std, y, x, pixel_std);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? pixel_d.val[0] = pixel.val[0] - pixel_u.val[0];
? ? ? ? ? ? ? ? ? ??pixel_d.val[1] = pixel.val[1] - pixel_u.val[1];
? ? ? ? ? ? ? ? ? ? pixel_d.val[2] = pixel.val[2] - pixel_u.val[2];
? ? ? ? ? ? ? ? ? ? cvSet2D(frame_d, y, x, pixel_d);
? ? ? ? ? ? ? ?}
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? //顯示結果
? ? ? ? frame_u->origin = 1;
? ? ? ? frame_d->origin = 1;
? ? ? ? cvShowImage("origin", frame);
? ? ? ? cvShowImage("background", frame_u);
? ? ? ? cvShowImage("foreground", frame_d);
? ? }
? ? //釋放內存
? ? cvReleaseCapture(&capture);
? ? cvReleaseImage(&frame);
? ? cvReleaseImage(&frame_u);
? ? cvReleaseImage(&frame_var);
? ? cvReleaseImage(&frame_std);
? ? cvDestroyWindow("origin");
? ? cvDestroyWindow("background");
? ? cvDestroyWindow("foreground");
? ? return 0;
}
完善補充:
對于單高斯模型實現必須進行背景減除與陰影消除的處理,實用的模型還需要很多改進!此文僅供初學者研究。
參考鏈接:
http://underthehood.blog.51cto.com/2531780/484191
總結
以上是生活随笔為你收集整理的背景建模之单高斯实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法优化:rgb向yuv的转化最优算法,
- 下一篇: Bayer Pattern to RGB