GMM即高斯混合模型,GMM加上貝葉斯就能對圖像進行分割。
在說高斯混合模型之前,得先認識單高斯模型,即高斯分佈(正態分佈),由圖可知,以某個點爲例,它的高斯分佈含義:離該點越近其權重越大影響越大,越遠其權重越小影響越小,中心點的大小要受到周圍點的影響。比如 5 _ 10 _ _ 6,以10爲中心點的高斯分佈,_代表距離,因爲5離10更近,權值更大,設爲0.8,則5變成5*0.8=4。因爲6離10更遠,權值更小,設爲0.4,則6變成6*0.4=2.4。
對於GMM高斯混合模型:圖中是一個直方圖,我用曲線去大概模擬走勢,可以看到爲凹凸曲線,仔細想想,是不是像一個個單高斯分佈組合起來的?GMM高斯混合模型就是一個個單高斯分佈組合的。可以用來擬合直方圖。
圖像處理知識:對於圖像明顯的類別,在其直方圖上可以明顯看出,若直方圖上存在兩個波峯,則圖像分爲兩類。
貝葉斯:貝葉斯就是一個概率估計算法,就是估計一個東西最有可能屬於哪類。
圖像分割:對於上圖,由直方圖可以認爲圖像分爲兩類,即A和B類。現在要判斷每個像素點屬於哪一類。以K像素點爲例,我們能從經驗認爲,它有很大概率屬於A類。 如何對每個像素點都能自動分類呢?用貝葉斯算法,關於貝葉斯算法,可以自查資料,這樣就把圖像每個像素點都找到屬於自己的類別。
以上都是自己對於GMM算法的個人理解。
// GMM——圖像分割.cpp: 定義控制檯應用程序的入口點。
//
#include<opencv2\opencv.hpp>
using namespace cv;
using namespace ml;
int main(int arc, char** argv) {
Mat src = imread("C:/Users/zhang/Desktop/1.png");
imshow("input", src);
int width = src.cols;
int height = src.rows;
int dims = src.channels();
int pointsCount = width * height;//總共數據點的個數
Mat points(pointsCount, dims, CV_64FC1);//輸入數據,與原圖像有着相同通道
Mat labels;//輸出數據,爲各個數據點最終的分類索引
int k = 3;//分別個數
Scalar color[] = { //每個分類的顏色
Scalar(0,0,255),
Scalar(0,255,0),
Scalar(255,0,0)
};
//將圖像轉換爲數據點
int index = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
//把RGB圖像的三個通道的各個像素點值分別賦給points的三個通道
index = i * width + j;
points.at<double>(index, 0) = src.at<Vec3b>(i, j)[0];
points.at<double>(index, 1) = src.at<Vec3b>(i, j)[1];
points.at<double>(index, 2) = src.at<Vec3b>(i, j)[2];
}
}
//GMM分割(基於高斯混合模型的期望最大值)
TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, 0.1);
//10代表最大循環數目,1.0代表閾值
Ptr<EM> em = EM::create();
em->setClustersNumber(k);//分類個數
em->setCovarianceMatrixType(EM::COV_MAT_SPHERICAL);//協方差矩陣類型
em->setTermCriteria(criteria);//停止條件
em->trainEM(points, noArray(), labels, noArray());
//第一個:表示輸入的數據集合,可以一維或者多維數據,類型是Mat類型,
//第二個:可選項,輸出一個矩陣,裏面包含每個樣本的似然對數值,如果不需要則爲noArray()
//第三個:labels表示計算之後各個數據點的最終的分類索引,是一個INT類型的Mat對象,類型和長寬與原圖像一致
//第四個://可選項,輸出一個矩陣,裏面包含每個隱性變量的後驗概率,如果不需要則爲noArray()
//將數據點轉換爲圖像並顯示
Mat result = Mat::zeros(src.size(), CV_8UC3);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
index = i * width + j;
int label = labels.at<int>(index, 0);////每個像素點的標籤
//把每個像素點對應的標籤所對應的顏色賦給新圖像
result.at<Vec3b>(i, j)[0] = color[label][0];
result.at<Vec3b>(i, j)[1] = color[label][1];
result.at<Vec3b>(i, j)[2] = color[label][2];
}
}
imshow("output", result);
waitKey(0);
return 0;
}
結果:分爲3類
GMM進階:如何確定應該分爲幾類?如何進行好壞評估?可以看看下面資料
https://blog.csdn.net/wangxiaopeng0329/article/details/53542606