opencv——GMM影象分割
阿新 • • 發佈:2019-01-13
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