1.GMM(高斯混合模型)
1.1GMM概述
1
- GMM與K-means相比較屬于軟分類
- 實作的方法是期望最大化(E-M演算法)
- 停止的條件:達到收斂
- 主要分為兩個步驟:訓練與預言
1.2原理講解
高斯混合模型(Gaussian Mixed Model)指的是多個高斯分布函式的線性組合,理論上GMM可以擬合出任意型別的分布,通常用于解決同一集合下的資料包含多個不同的分布的情況(或者是同一類分布但引數不一樣,或者是不同型別的分布,比如正態分布和伯努利分布),
如圖1,圖中的點在我們看來明顯分成兩個聚類,這兩個聚類中的點分別通過兩個不同的正態分布隨機生成而來,但是如果沒有GMM,那么只能用一個的二維高斯分布來描述圖1中的資料,圖1中的橢圓即為二倍標準差的正態分布橢圓,這顯然不太合理,畢竟肉眼一看就覺得應該把它們分成兩類,





2.GMM影像分割案例
void MyApi::GMMCluster(Mat& src_image)
{
//顏色板
vector<Scalar> colorTab = {
{0,0,255},
{0,255,0},
{255,0,0},
{255,255,0},
{0,255,255},
{255,0,255}
};
//獲取輸入影像的尺寸
int width = src_image.cols;
int height = src_image.rows;
int chnes = src_image.channels();
//把彩色影像中的資料點提取出來放入points里面
//points的型別是CV_64FC1
//為什么這里使用的是CV_64FC1,因為GMM中需要計算概率,協方差等,需要大量的浮點運算
//下面的代碼同時適用于灰度圖和3-d,4-d彩色圖的遍歷
Mat points(width * height, chnes, CV_64FC1, Scalar(10));
for (int row = 0; row < height; row++)
{
uchar* ptr = src_image.ptr<uchar>(row);
for (int col = 0; col < width * chnes; col += chnes)
{
int index = row * width + col / chnes;
double* ptr_points = points.ptr<double>(index);
//ptr_points[0] = static_cast<int>(ptr[col + 0]);//B
//ptr_points[1] = static_cast<int>(ptr[col + 1]);//G
//ptr_points[2] = static_cast<int>(ptr[col + 2]);//R
for (int i = 0; i < chnes; i++)
ptr_points[i] = static_cast<int>(ptr[col + i]);
}
}
//和K-means的一樣,表示圖片資料要分為幾類,高斯模型是由clusters個高斯分布合成的
int clusters = 2;
//協方差矩陣的型別(不太懂)
int covariancematrixtype = EM::Types::COV_MAT_SPHERICAL;
//建立高斯模型的終止條件
//最大迭代次數(全部資料處理的次數),終止要達到的精度要求
TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1);
//高斯模型建立的同時,也會預測每一個像素點屬于哪一個高斯分布,所以label用來記錄分布結果
Mat label;
//初始化引數
Ptr<EM> em_model = EM::create();
em_model->setClustersNumber(clusters);
em_model->setCovarianceMatrixType(covariancematrixtype);
em_model->setTermCriteria(criteria);
//訓練建立模型,并得到結果(label)
//第四個引數是每個像素在每個高斯分布的后驗概率
//第二個引數,每個像素的似然對數值(不太懂)
em_model->trainEM(points, noArray(), label, noArray());
//顯示結果
Mat result = Mat::zeros(src_image.size(), CV_8UC3);
//Mat sample(chnes, 1, CV_64FC1);
for (int row = 0; row < height; row++)
{
uchar* ptr_result = result.ptr<uchar>(row);
uchar* ptr_srcImage = src_image.ptr<uchar>(row);
for (int col = 0; col < width * chnes; col += chnes)
{
//第col/chnes個像素點的像素起點位置為col(col為3的倍數)
//計算位置為(row,col/chnes)的像素點屬于的類別
int index = label.at<int>(row * width + col / chnes, 0);
for (int i = 0; i < chnes; i++)
ptr_result[col + i] = colorTab[index][i];
/*
這里還有一種寫法,是把src_image中的每一個像素放到高斯模型里面預測,這樣也可以得到
每一個像素的分類結果,這里沒有這樣寫是因為我們在建立高斯模型時,用的就是src_image的影像資料,
所以在建立高斯模型的時候就已經計算好了像素的分類結果,保存在label里面,
這里寫一下:
//獲取原圖中某個像素點的像素值
sample.at<double>(0, 0) = ptr_srcImage[col];
sample.at<double>(1, 0) = ptr_srcImage[col + 1];
sample.at<double>(2, 0) = ptr_srcImage[col + 2];
//預測像素值屬于哪一類
//predict2 第一引數必須是(1,dims)或者(dims,1)
//第二個引數回傳Vec2d 第一個值是似然對數值,第二值是最可能的高斯分布類別
int index = cvRound(em_model->predict2(sample, noArray())[1]);
//分割影像,給結果影像上相對應的像素點著上顏色
for (int i = 0; i < chnes; i++)
ptr_result[col + i] = colorTab[index][i];
*/
}
}
imshow("GMM result", result);
imshow("src_image", src_image);
}
利用GMM對影像二分類分割如下:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/298459.html
標籤:其他
上一篇:EISeg分割標注軟體使用
