OPENCV GMM算法理解与实现

 

1,介绍

      GMM(​​Gaussian mixture model)  高斯混合模型,高斯概率密度函数(二维时也称为:正态分布曲线)精确的量化事物,就是:某一区域的点数数量分布情况。如下图所示:

opencv  使用GMM对数据进行分类聚合,把靠近的数据,变成一个集合

1,代码如下

(1)前期准备,产生随机的点集

       1):    Mat(row,col,type) 定义一个sampleCount行 ,2列的数据

	int sampleCount = rng.uniform(5, 100);
	Mat points(sampleCount, 2, CV_32FC1,Scalar(10,1));

        2):给这个point集合填充随机数据集,点集的范围要在图片的范围里面,

	for (int k = 0; k < numCluster; k++) {
		Point center;
		center.x = rng.uniform(0, img.cols);
		center.y = rng.uniform(0, img.rows);
		Mat pointChunk = points.rowRange(k*sampleCount / numCluster,
			k == numCluster - 1 ? sampleCount : (k + 1)*sampleCount / numCluster);
		rng.fill(pointChunk, RNG::NORMAL, Scalar(center.x, center.y), Scalar(img.cols*0.05, img.rows*0.05));
		
	}

      3):打乱数据

randShuffle(points, 1, &rng);

这样我们就产生了一个随机的数据集合

2,接着开始使用GMM算法

先对函数进行解释

/* samples: 输入的样本,一个单通道的矩阵。从这个样本中,进行高斯混和模型估计。

logLikelihoods: 可选项,输出一个矩阵,里面包含每个样本的似然对数值。

labels: 可选项,输出每个样本对应的标注。

probs: 可选项,输出一个矩阵,里面包含每个隐性变量的后验概率
*/ 
bool trainEM(InputArray samples, OutputArray logLikelihoods=noArray(),OutputArray labels=noArray(),OutputArray probs=noArray())

2),使用GMM:EM算法技术

Ptr<EM> em_model = EM::create();
	em_model->setClustersNumber(numCluster);
	em_model->setCovarianceMatrixType(EM::COV_MAT_SPHERICAL);
	em_model->setTermCriteria(TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 100, 0.1));
	em_model->trainEM(points, noArray(), labels, noArray());

EM算法:期望最大(Expectation Maximization, 简称EM)算法,称为机器学习十大算法之一。

它是一种从不完全数据或有数据丢失的数据集(存在隐含变量)中求解概率模型参数的最大似然估计方法。

就比如:

某位同学与一位猎人一起外出打猎,一只野兔从前方窜过。只听一声枪响,野兔应声到下,如果要你推测,这一发命中的子弹是谁打的?你就会想,只发一枪便打中,由于猎人命中的概率一般大于这位同学命中的概率,看来这一枪是猎人射中的。

假设有一群兔子和一群猎人呢?其实GMM:EM探讨的就是这样一个问题而已,

一群兔子就判断兔子离哪个猎人比较近,一阵枪响之后一地的兔子,通过已知道的条件(猎人的个数,兔子位置)判断哪些兔子的哪个猎人打的。

那么我们就会想:传入的需要哪些条件呢?

1,传入的数据集(几只兔子),

2,传出的数据集(谁杀死了哪几家兔子)

3,要分成几个数据集(几个猎人)

对于的程序如下:

//创建一个算法空间

Ptr<EM> em_model = EM::create();

//设置有要分成的数据集合

em_model->setClustersNumber(numCluster);

//设置算法类型

    em_model->setCovarianceMatrixType(EM::COV_MAT_SPHERICAL);

//设置退出循环的条件

    em_model->setTermCriteria(TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 100, 0.1));

ermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 100, 0.1);

TermCriteria::EPS       表示: 迭代到阈值终止

TermCriteria::COUNT 表示: 最大迭代次数终止 

100:最大迭代次数

0.1:  结果的精确性

typedef struct CvTermCriteria
 {
  int    type;  /* CV_TERMCRIT_ITER 和CV_TERMCRIT_EPS二值之一,或者二者的组合 */
  int    max_iter; /* 最大迭代次数 */
  double epsilon; /* 结果的精确性 */
 }

//放入数据进行计算

em_model->trainEM(points, noArray(), Result, noArray());

   points:输入的数据集合(兔子)

   Result:结果,输出的集合

最后画点显示数据

for (int i = 0; i < sampleCount; i++) {
		Point p(cvRound(points.at<float>(i, 0)), points.at<float>(i, 1));
		circle(img, p, 3, colorTab[labels.at<int>(i)], -1);
	}

	imshow("GMM-EM Demo", img);

显示结果

还可以通过模型预测如果(兔子出现在某一点)被哪个猎手。代码入下

遍历所有的点

// classify every image pixels(像素)
	Mat sample(1, 2, CV_32FC1);
	for (int row = 0; row < img.rows; row++) {
		for(int col = 0; col < img.cols; col++) {
			sample.at<float>(0) = (float)col;
			sample.at<float>(1) = (float)row;
			//cvRound():四舍五入;
			// predict2:EM预言 sample:位置
			int response = cvRound(em_model->predict2(sample, noArray())[1]);
			/*typedef struct Scalar
			{
				double val[4];
			}Scalar*/
			Scalar c = colorTab[response];
			circle(img, Point(col, row), 1, c*0.75, -1);
		}
	}

 

执行的结果如下:

所有代码如下:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace cv::ml;
using namespace std;

int main(int argc, char** argv) {
	//产生随机的点集
	Mat img(500, 500, CV_8UC3);
	RNG rng(12345);
	vector<int> vi = {1,2,3,4,5,6};
	randShuffle(vi, 1, &rng);
	for (size_t i = 0; i < vi.size(); i++)
	{
		cout << vi[i] << endl;
	}
	
	Scalar colorTab[] = {
		Scalar(0, 0, 255),
		Scalar(0, 255, 0),
		Scalar(255, 0, 0),
		Scalar(0, 255, 255),
		Scalar(255, 0, 255)
	};

	int numCluster = rng.uniform(2, 10);
	printf("number of clusters : %d\n", numCluster);

	int sampleCount = rng.uniform(5, 100);
	//1,Mat(row,col,type) 定义一个sampleCount行 ,2列的数据
	Mat points(sampleCount, 2, CV_32FC1,Scalar(10,1));
	
	Mat labels;
	Mat centers;
	cout << points << endl;
	// 生成随机数
	for (int k = 0; k < numCluster; k++) {
		Point center;
		center.x = rng.uniform(0, img.cols);
		center.y = rng.uniform(0, img.rows);
		//为矩阵的指定行区间创建一个矩阵头 参数1,从0开始的行间距索引;  参数2,终止索引(把points的第n,到n+1行数据放到这里)
		Mat pointChunk = points.rowRange(k*sampleCount / numCluster,
			k == numCluster - 1 ? sampleCount : (k + 1)*sampleCount / numCluster);

		/*用随机数填充矩阵 ,
		InputOutputArray                    输入输出矩阵,最多支持4通道,超过4通道先用reshape()改变结构

		int distType                             UNIFORM 或 NORMAL,表示均匀分布和高斯分布

		InputArray a                           disType是UNIFORM,a表示为下限

		InputArray b                           disType是UNIFORM,b表示为上限

		bool saturateRange=false     只针对均匀分布有效。当为真的时候,会先把产生随机数的范围变换到数据类型的范围,再产生随机数;
		                             如果为假,会先产生随机数,再进行截断到数据类型的有效区间。请看以下fillM1和fillM2的例子并观察结果 */ 
		rng.fill(pointChunk, RNG::NORMAL, Scalar(center.x, center.y), Scalar(img.cols*0.05, img.rows*0.05));
		
	}

	randShuffle(points, 1, &rng);


	Ptr<EM> em_model = EM::create();
	em_model->setClustersNumber(numCluster);
	em_model->setCovarianceMatrixType(EM::COV_MAT_SPHERICAL);
	em_model->setTermCriteria(TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 100, 0.1));
	em_model->trainEM(points, noArray(), labels, noArray());
	//em_model 模型
	// classify every image pixels(像素)
	Mat sample(1, 2, CV_32FC1);
	for (int row = 0; row < img.rows; row++) {
		for(int col = 0; col < img.cols; col++) {
			sample.at<float>(0) = (float)col;
			sample.at<float>(1) = (float)row;
			//cvRound():四舍五入;
			// predict2:EM预言 sample:位置
			int response = cvRound(em_model->predict2(sample, noArray())[1]);
			/*typedef struct Scalar
			{
				double val[4];
			}Scalar*/
			Scalar c = colorTab[response];
			circle(img, Point(col, row), 1, c*0.75, -1);
		}
	}

	// draw the clusters
	for (int i = 0; i < sampleCount; i++) {
		Point p(cvRound(points.at<float>(i, 0)), points.at<float>(i, 1));
		circle(img, p, 3, colorTab[labels.at<int>(i)], -1);
	}

	imshow("GMM-EM Demo", img);

	waitKey(0);
	return 0;
}

创作不易,如有引用,请附上链接。2020年5月2日19:39:49

参考:http://blog.sina.com.cn/s/blog_a36a563e0102y2ec.html

https://blog.csdn.net/weixin_38206214/article/details/81064625

https://blog.csdn.net/ilyhlf5201314/article/details/8232746

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值