opencv3机器学习之EM算法示例详解

 更新时间:2022年06月30日 08:46:42   作者:denny402  
这篇文章主要介绍了opencv3机器学习之EM算法的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

不同于其它的机器学习模型,EM算法是一种非监督的学习算法,它的输入数据事先不需要进行标注。相反,该算法从给定的样本集中,能计算出高斯混和参数的最大似然估计。也能得到每个样本对应的标注值,类似于kmeans聚类(输入样本数据,输出样本数据的标注)。实际上,高斯混和模型GMM和kmeans都是EM算法的应用。

在opencv3.0中,EM算法的函数是trainEM,函数原型为:

bool trainEM(InputArray samples, OutputArray logLikelihoods=noArray(),OutputArray labels=noArray(),OutputArray probs=noArray())

四个参数:

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

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

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

probs: 可选项,输出一个矩阵,里面包含每个隐性变量的后验概率

这个函数没有输入参数的初始化值,是因为它会自动执行kmeans算法,将kmeans算法得到的结果作为参数初始化。

这个trainEM函数实际把E步骤和M步骤都包含进去了,我们也可以对两个步骤分开执行,OPENCV3.0中也提供了分别执行的函数:

bool trainE(InputArray samples, InputArray means0,
                        InputArray covs0=noArray(),
                        InputArray weights0=noArray(),
                        OutputArray logLikelihoods=noArray(),
                        OutputArray labels=noArray(),
                        OutputArray probs=noArray())
bool trainM(InputArray samples, InputArray probs0,
                        OutputArray logLikelihoods=noArray(),
                        OutputArray labels=noArray(),
                        OutputArray probs=noArray())

 trainEM函数的功能和kmeans差不多,都是实现自动聚类,输出每个样本对应的标注值。但它比kmeans还多出一个功能,就是它还能起到训练分类器的作用,用于后续新样本的预测。

预测函数原型为:

Vec2d predict2(InputArray sample, OutputArray probs) const

sample: 待测样本

probs : 和上面一样,一个可选的输出值,包含每个隐性变量的后验概率

返回一个Vec2d类型的数,包括两个元素的double向量,第一个元素为样本的似然对数值,第二个元素为最大可能混和分量的索引值。

在本文中,我们用两个实例来学习opencv中的EM算法的应用。

一、opencv3.0中自带的例子

既包括聚类trianEM,也包括预测predict2

代码:

#include "stdafx.h"
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
using namespace cv::ml;
//使用EM算法实现样本的聚类及预测
int main()
{
    const int N = 4;    //分成4类
    const int N1 = (int)sqrt((double)N);
    //定义四种颜色,每一类用一种颜色表示
    const Scalar colors[] =
    {
        Scalar(0, 0, 255), Scalar(0, 255, 0),
        Scalar(0, 255, 255), Scalar(255, 255, 0)
    };
    int i, j;
    int nsamples = 100;   //100个样本点
    Mat samples(nsamples, 2, CV_32FC1);  //样本矩阵,100行2列,即100个坐标点    
    Mat img = Mat::zeros(Size(500, 500), CV_8UC3);  //待测数据,每一个坐标点为一个待测数据
    samples = samples.reshape(2, 0);
    //循环生成四个类别样本数据,共样本100个,每类样本25个
    for (i = 0; i < N; i++)
    {
        Mat samples_part = samples.rowRange(i*nsamples / N, (i + 1)*nsamples / N);
        //设置均值
        Scalar mean(((i%N1) + 1)*img.rows / (N1 + 1),
            ((i / N1) + 1)*img.rows / (N1 + 1));
        //设置标准差
        Scalar sigma(30, 30);
        randn(samples_part, mean, sigma);  //根据均值和标准差,随机生成25个正态分布坐标点作为样本
    }
    samples = samples.reshape(1, 0);
    // 训练分类器
    Mat labels;  //标注,不需要事先知道
    Ptr<EM> em_model = EM::create();
    em_model->setClustersNumber(N);
    em_model->setCovarianceMatrixType(EM::COV_MAT_SPHERICAL);
    em_model->setTermCriteria(TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 300, 0.1));
    em_model->trainEM(samples, noArray(), labels, noArray());
    //对每个坐标点进行分类,并根据类别用不同的颜色画出
    Mat sample(1, 2, CV_32FC1);
    for (i = 0; i < img.rows; i++)
    {
        for (j = 0; j < img.cols; j++)
        {
            sample.at<float>(0) = (float)j;
            sample.at<float>(1) = (float)i;
            //predict2返回的是double值,用cvRound进行四舍五入得到整型
            //此处返回的是两个值Vec2d,取第二个值作为样本标注
            int response = cvRound(em_model->predict2(sample, noArray())[1]);
            Scalar c = colors[response];  //为不同类别设定颜色
            circle(img, Point(j, i), 1, c*0.75, FILLED);
        }
    }
    //画出样本点
    for (i = 0; i < nsamples; i++)
    {
        Point pt(cvRound(samples.at<float>(i, 0)), cvRound(samples.at<float>(i, 1)));
        circle(img, pt, 2, colors[labels.at<int>(i)], FILLED);
    }
    imshow("EM聚类结果", img);
    waitKey(0);
    return 0;
}

结果:

二、trainEM实现自动聚类进行图片目标检测

只用trainEM实现自动聚类功能,进行图片中的目标检测

代码:

#include "stdafx.h"
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
using namespace cv::ml;
int main()
{
    const int MAX_CLUSTERS = 5;
    Vec3b colorTab[] =
    {
        Vec3b(0, 0, 255),
        Vec3b(0, 255, 0),
        Vec3b(255, 100, 100),
        Vec3b(255, 0, 255),
        Vec3b(0, 255, 255)
    };
    Mat data, labels;
    Mat pic = imread("d:/woman.png");
    for (int i = 0; i < pic.rows; i++)
    for (int j = 0; j < pic.cols; j++)
    {
        Vec3b point = pic.at<Vec3b>(i, j);
        Mat tmp = (Mat_<float>(1, 3) << point[0], point[1], point[2]);
        data.push_back(tmp);
    }
    int N =3;  //聚成3类
    Ptr<EM> em_model = EM::create();
    em_model->setClustersNumber(N);
    em_model->setCovarianceMatrixType(EM::COV_MAT_SPHERICAL);
    em_model->setTermCriteria(TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 300, 0.1));
    em_model->trainEM(data, noArray(), labels, noArray());
    int n = 0;
    //显示聚类结果,不同的类别用不同的颜色显示
    for (int i = 0; i < pic.rows; i++)
    for (int j = 0; j < pic.cols; j++)
    {
        int clusterIdx = labels.at<int>(n);
        pic.at<Vec3b>(i, j) = colorTab[clusterIdx];
        n++;
    }
    imshow("pic", pic);
    waitKey(0);
    return 0;
}

测试图片

测试结果:

以上就是opencv3机器学习之EM算法的详细内容,更多关于opencv3 EM算法的资料请关注脚本之家其它相关文章!

相关文章

  • C语言求解无向图顶点之间的所有最短路径

    C语言求解无向图顶点之间的所有最短路径

    这篇文章主要为大家详细介绍了C语言求解无向图顶点之间的所有最短路径,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • 用C语言实现链式栈介绍

    用C语言实现链式栈介绍

    大家好,本篇文章主要讲的是用C语言实现链式栈介绍,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12
  • C++中继承(inheritance)详解及其作用介绍

    C++中继承(inheritance)详解及其作用介绍

    这篇文章主要介绍了C++中继承(inheritance)详解及其作用介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • C语言动态数组的使用实现代码

    C语言动态数组的使用实现代码

    这篇文章主要介绍了C语言动态数组的使用实现代码的相关资料,需要的朋友可以参考下
    2017-01-01
  • 浅谈C++日志系统log4cxx的使用小结详解

    浅谈C++日志系统log4cxx的使用小结详解

    本篇文章是对C++日志系统log4cxx的使用进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C语言实现纸牌游戏(小猫钓鱼)

    C语言实现纸牌游戏(小猫钓鱼)

    这篇文章主要为大家详细介绍了C语言实现纸牌游戏,小猫钓鱼游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-10-10
  • C语言项目全正整数后再计算的三种参考解答方法

    C语言项目全正整数后再计算的三种参考解答方法

    今天小编就为大家分享一篇关于C语言项目全正整数后再计算的三种参考解答方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • C++深入细致探究二叉搜索树

    C++深入细致探究二叉搜索树

    二叉搜索树是以一棵二叉树来组织的。每个节点是一个对象,包含的属性有left,right,p和key,其中,left指向该节点的左孩子,right指向该节点的右孩子,p指向该节点的父节点,key是它的值
    2022-05-05
  • 完美解决QT QGraphicsView提升到QChartView报错的问题

    完美解决QT QGraphicsView提升到QChartView报错的问题

    使用QT提供的QChartView来绘制图表,提升QGraphicsView控件继承QChartView后,然后将QGraphicsView提升到我们自己写的类,怎么才能确保提升后编译不报错呢,下面小编给大家带来了QT QGraphicsView 提升到QChartView报错解决方案,感兴趣的朋友一起看看吧
    2023-05-05
  • C++扑克牌的洗牌发牌游戏设计

    C++扑克牌的洗牌发牌游戏设计

    这篇文章主要为大家详细介绍了C++扑克牌的洗牌发牌游戏设计,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08

最新评论