EM算法學習筆記_2(opencv自帶EM sample學習)


  實驗說明:

  在上一講EM算法學習筆記_1(EM算法的簡單理解) 中已經用通俗的語言簡單的介紹了下EM算法,在這一節中就采用opencv自帶的一個EM sample來學習下opencvEM 算法類的使用,順便也體驗下EM 算法的實際應用。

  環境:Ubuntu12.04+Qt4.8.2+QtCreator2.5+opencv2.4.2

  在這里需要使用2個與EM算法有關的類,即CvEMCvEMParams,這2個類在opencv2.4.2已經放入legacy文件夾中了,說明不久就會被淘汰掉,因為在未來的opencv版本中,將采用Algorithm這個公共類來統一接口。不過CvEMCvEMParams的使用與其類似,且可以熟悉EM算法的使用流程。

  需要注意的是這2個類雖然是與EM算法有關,可是只能解決GMM問題,比較局限。也許這是將其放在legacy中的原因吧。

 

  實驗流程:

  首先產生需要聚類的樣本數據,我這里采用的是9個混合的二維高斯分布,所以需要被聚類成9類,這些GMM排成3*3的格式,每一格25個點,共225個訓練樣本。在軟件中顯示出樣本點的分布。

  用類EMCvEMParams初始化emem_params對象。

  設置EM參數類em_params的各個參數,這里的均值、權值、方差的初始化采用的是kmeans聚類得到的,em_params的參數中需要特別指定的是所聚類類別N(這里等於9.

  用這255個數據進行訓練EM模型,采用的是CvEM類方法train()函數。

  把窗口大小500*500內的每個點用訓練出來的EM模型進行預測,將預測結果用不同的顏色在軟件中畫出來。

  把訓練過程中樣本的類別標簽(程序中保存在label中)在圖像中顯示出來。

 

  實驗結果:

  軟件界面圖:

  

 

  按下Gnenrate Data按鈕后顯示如下:

  

 

  按下EM Cluster按鈕后顯示如下:

  

 


  實驗代碼

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
//#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/ml/ml.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/legacy/legacy.hpp>

using namespace cv;
using namespace std;
//using std::vector;

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    vector<Scalar> colors;
    
private slots:

    void on_closeButton_clicked();

    void on_generateButton_clicked();

    void on_clusterButton_clicked();

private:
    Ui::MainWindow *ui;

    int nsamples;
    int N, N1;
    Mat img, img1;
    Mat samples, sample_predict;
    Mat labels;
    CvEM em;
    CvEMParams em_params;
};

#endif // MAINWINDOW_H

 

mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QImage>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    N = 9;
    N1 = (int)sqrt(double(N));
    nsamples = 225;
    img = Mat( Size(500, 500), CV_8UC3 );

    colors.resize(N);
    colors.at(0) = Scalar(0, 255, 255);
    colors.at(1) = Scalar(255, 0, 255);
    colors.at(2) = Scalar(255, 255, 0);
    colors.at(3) = Scalar(255, 0, 0);
    colors.at(4) = Scalar(0, 255, 0);
    colors.at(5) = Scalar(0, 0, 255);
    colors.at(6) = Scalar(255, 100, 100);
    colors.at(7) = Scalar(100, 255, 100);
    colors.at(8) = Scalar(100, 100, 255);

}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_closeButton_clicked()
{
    close();
}

void MainWindow::on_generateButton_clicked()
{
    samples = Mat( nsamples, 2, CV_32FC1);//用來存儲產生的二維隨機點
    samples = samples.reshape( 2, 0 );//轉換成2通道的矩陣,reshape函數只適應而2維圖像

    //初始化樣本
    for( int i = 0; i < N; i++ )
        {
            Mat sub_samples = 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 var( 30, 30 );
            randn( sub_samples, mean, var );
        }
    samples = samples.reshape( 1, 0 );

    //顯示樣本數據
    for( int j = 0; j < nsamples; j++ )
    {
        Point gene_sample;
        gene_sample.x = cvRound(samples.at<float>(j, 0));
        gene_sample.y = cvRound(samples.at<float>(j, 1));
        circle( img, gene_sample, 1, Scalar(0, 255, 250), 1, 8 );
    }
    cvtColor( img, img, CV_BGR2RGB );

    /*Qt中處理圖像有4個類,分別為QImage,QPixmap,QBitmap,QPicture.其中QPixmap專門負責在屏幕上顯示圖片
    的,QImage專門負責和I/O方面的,QBitmap是從QPixmap中繼承來的,只負責一個通道的圖像處理,QPicture是
    專門用來負責畫圖的*/
    QImage qimg = QImage( img.data, img.cols, img.rows, QImage::Format_RGB888 );
    //setPixmap為QLabel發出的公共信號,fromImage函數為將圖片轉換程QPixmap的格式
    ui->imgLabel->setPixmap( QPixmap::fromImage( qimg ) );
}

void MainWindow::on_clusterButton_clicked()
{
    //給EM算法參賽賦值,均值,方差和權值采用kmeans初步聚類得到
    em_params.means = NULL;
    em_params.covs = NULL;
    em_params.weights = NULL;
    em_params.nclusters = N;
    em_params.start_step = CvEM::START_AUTO_STEP;
    em_params.cov_mat_type = CvEM::COV_MAT_SPHERICAL;
    //達到最大迭代次數或者迭代誤差小到一定值,應該有系統默認的值
    em_params.term_crit.type = CV_TERMCRIT_ITER | CV_TERMCRIT_EPS;

    cvtColor( img, img, CV_RGB2BGR );

    //EM算法訓練過程
    em.train( samples, Mat(), em_params, &labels );

    //畫出背景圖
    sample_predict = Mat( 1, 2, CV_32FC1 );
    for( int i = 0; i < img.rows; i++ )
        for( int j = 0; j < img.cols; j++ )
            {
                sample_predict.at<float>(0) = (float)i;
                sample_predict.at<float>(1) = (float)j;
                int value = cvRound(em.predict( sample_predict ));//返回的value為預測類標簽
                circle( img, Point(i, j), 1, 0.1*colors.at(value), 1, 8 );
            }

    //畫出樣本點的聚類情況
    for( int n = 0; n < nsamples; n++ )
        circle( img, Point(cvRound(samples.at<float>(n, 0)), cvRound(samples.at<float>(n, 1))),
                1, colors.at( labels.at<int>(n)), 1, 8 );//因為此時labels保存的是類標簽(1~N),為整型

    //顯示圖像
    cvtColor( img, img, CV_BGR2RGB );
    QImage qimg = QImage( img.data, img.cols, img.rows, QImage::Format_RGB888 );
    ui->imgLabel->setPixmap( QPixmap::fromImage(qimg) );


}

 

main.cpp:

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    
    return a.exec();
}

 

  實驗總結:

  要學會數據點產生的類似方法,特別是reshape函數的使用方法。

  要學會用STL的vector,這個容器要比數組方便很多。

  要多學點C++的編程思想。

 

   附錄:工程code下載地址

 

 

 

 



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM