【图像处理】混合高斯模型目标检测_c++

基于混合高斯模型建模,来分割背景与目标。
@转载请注明出处
算法步骤:

  1. 视频图像输入
  2. 初始化混合高斯模型参数:均值,方差,权重,高斯模型个数等,假设模型5个,一般位3~5个。
  3. 计算当前像素与每个模型的均值差的绝对值,称该像素与当前模型匹配,判断为背景。若不存在匹配的模型,则判断该点位前景,并且对模型的重要性进行排序,对较小的模型重新赋值。
  4. 更新每个模型的系数
  5. 权重归一化
  6. 重复3~5。
  7. 输出检测二值图。

代码如下: 包括GMM.cpp, GMM.h 和main.cpp

GMM.h

#pragma once
/*
	GMM.h
	created at 2019/4/19
*/
#ifndef _GMM_H_HH
#define _GMM_H_HH

#include <opencv2/opencv.hpp>


class Gauss_mixture_model
{
	public:
		Gauss_mixture_model();
		~Gauss_mixture_model();
	public:
		void gmm_init(int area, int nums);
		void gmm_update(cv::Mat src, cv::Mat& dst);
		void gmm_quit();
	private:
		void sort_important(float* val, int nums, int* sortpos);
	protected:
		float* u_mean;
		float* w_eight;
		float* v_rianc;
		float* i_mport;
		int* sort_loc;
		int model_nums;
		float biase;		/*用于计算偏差的阈值*/
		float rate;			/*学习率*/
		float pho;
		float thr;
};
#endif

GMM.cpp

#include "GMM.h"

Gauss_mixture_model::Gauss_mixture_model()
{

}

Gauss_mixture_model::~Gauss_mixture_model()
{

}

void Gauss_mixture_model::gmm_init(int area, int nums)
{
	biase = 2.5f;
	model_nums = nums;
	rate = 0.01f;
	thr = 0.7f;
	pho = rate * model_nums;

	int size = area * model_nums;
	u_mean = new float[size];
	w_eight = new float[size];
	v_rianc = new float[size];
	i_mport = new float[model_nums];
	sort_loc = new int[model_nums];

	memset(i_mport, 0.0f, model_nums*sizeof(float));
	memset(sort_loc, 0, model_nums*sizeof(int));
	srand((unsigned)(time(NULL)));

	/*init coeff*/
	for (int r = 0; r < size; ++r)
	{
		u_mean[r] = rand() % 256;
		w_eight[r] = 1.0f / nums;
		v_rianc[r] = 6.0f;
	}
}

void Gauss_mixture_model::gmm_update(cv::Mat src, cv::Mat& dst)
{
	int rows = src.rows, cols = src.cols;
	int size = rows * cols;
	bool match;
	for (int r = 0; r < rows; ++r)
		for (int c = 0; c < cols; ++c)
		{
			match = false;
			unsigned char pixel = src.at<uchar>(r, c);
			float* ptr_u = u_mean + r * cols + c;
			float* ptr_v = v_rianc + r * cols + c;
			float* ptr_w = w_eight + r * cols + c;

			for (int k = 0; k < model_nums; ++k)
			{
				float diff = abs(pixel - (*(ptr_u + k * size)));
				float weigt = *(ptr_w + k * size);
				if (diff <= biase * (*(ptr_v + k * size)))
				{
					match = true;
					*(ptr_w + k * size) = (1 - rate)*weigt + rate;

				}
				else
					*(ptr_w + k * size) = (1 - rate)*weigt;
			}
			if (!match)
			{
				dst.at<uchar>(r, c) = 255;
				for (int k = 0; k < model_nums; ++k)
					i_mport[k] = *(ptr_w + k*size) / *(ptr_v + k*size);
				sort_important(i_mport, model_nums, sort_loc);
				float sum_w = 0.0f;
				
				for (int k = 0; k < model_nums; ++k)
				{
					int loc = sort_loc[k];
					sum_w += *(ptr_w + loc * size);
					if (sum_w > thr)
					{
						for (int lose = k + 1; lose < model_nums; ++lose)
						{
							*(ptr_w + lose*size) = 0.001f;
							*(ptr_u + lose*size) = pixel;
							*(ptr_v + lose*size) = 20.0f;
						}
						break;
					}
				}
			
			}
			else
			{
				dst.at<uchar>(r, c) = 0;
				for (int k = 0; k < model_nums; ++k)
				{
					pho = rate / *(ptr_w + k*size);
					float means = *(ptr_u + k*size);
					*(ptr_u + k*size) = (1 - pho) * means + pho * pixel;
					float var = *(ptr_v + k*size);
					*(ptr_v + k*size) = sqrt((1 - pho)*(var*var) + pho * pow((pixel - *(ptr_u + k*size)), 2));
				}
			}
			/*权重归一化*/
			float norm_sum = 0.0f;
			for (int k = 0; k < model_nums; ++k)
				norm_sum += *(ptr_w + k * size);
			for (int k = 0; k < model_nums; ++k)
				*(ptr_w + k * size) /= norm_sum;
		}
}

static void swap_pos(float* x, float* y)
{
	float temp = *x;
	*x = *y;
	*y = temp;
}

void Gauss_mixture_model::sort_important(float* val, int nums, int* sortpos)
{
	float max = FLT_MIN;
	int pos = 0;
	for (int i = 0; i < nums - 1; ++i)
	{
		float max = val[i];
		for (int j = i + 1; j < nums; ++j)
		{
			if (val[j] >= max)
			{
				max = val[j];
				pos = j;
			}
		}
		sortpos[i] = pos;
		swap_pos(val+i, val+pos);
	}
}


void Gauss_mixture_model::gmm_quit()
{
	printf("[gmm] release memory...\n");
	delete[]u_mean;
	delete[]w_eight;
	delete[]v_rianc;
	delete[]i_mport;
	delete[]sort_loc;
}

main.cpp

#include <iostream>
#include "GMM.h"

const char* path = "vtest.avi";

void t_main()
{
	Gauss_mixture_model detector;
	cv::VideoCapture cap;
	cap.open(path);
	cv::Mat src, gray;
	int initflag = 1;
	while (1)
	{
		cap >> src;
		if (src.empty())
			break;
		if (src.channels() == 3)
			cvtColor(src, gray, CV_BGR2GRAY);
		else
			src.copyTo(gray);
		if (initflag)
		{
			int areas = gray.rows * gray.cols;
			detector.gmm_init(areas, 5);				/*init coeff*/
			initflag = 0;
		}
		cv::Mat dst(src.rows, src.cols, CV_8UC1);
		detector.gmm_update(gray, dst);					/*update coeff*/
		cv::imshow("original.jpg", src);
		cv::imshow("gmm_detect.jpg", dst);
		cv::waitKey(10);
	}
	detector.gmm_quit();						/*release memory*/
	printf("[gmm] end of avi...\n");
}

int main(int argc, char* argv[])
{
	t_main();
	return 0;
}

取视频中的一帧:
在这里插入图片描述
检测结果:
在这里插入图片描述

发布了35 篇原创文章 · 获赞 13 · 访问量 6339

猜你喜欢

转载自blog.csdn.net/qq_35306281/article/details/89411540