OpenCV學習(23) 使用kmeans算法實現圖像分割


      本章我們用kmeans算法實現一個簡單圖像的分割。如下面的圖像,我們知道圖像分3個簇,背景、白色的任務,紅色的絲帶以及帽子。

image

 

    Mat img = cv::imread("../kmeans.jpg");
    namedWindow("image");
    imshow("image", img);

     首先我們會生成采樣點,采樣點包括原始圖像中的所有像素點,采樣點用32位浮點數表示,接着我們會定義一個標記矩陣labels,用來存放kmeans的結果。該矩陣中存放的是索引的采樣點屬於那一個簇,在本例子中,值應該是0,1或2,因為有3個簇。

    //生成一維采樣點,包括所有圖像像素點,注意采樣點格式為32bit浮點數。
    Mat samples(img.cols*img.rows, 1, CV_32FC3);
    //標記矩陣,32位整形
    Mat labels(img.cols*img.rows, 1, CV_32SC1);

    uchar* p;
    int i, j, k=0;
    for(i=0; i < img.rows; i++)
        {
        p = img.ptr<uchar>(i);
        for(j=0; j< img.cols; j++)
            {
            samples.at<Vec3f>(k,0)[0] = float(p[j*3]);
            samples.at<Vec3f>(k,0)[1] = float(p[j*3+1]);
            samples.at<Vec3f>(k,0)[2] = float(p[j*3+2]);
            k++;
            }
        }

    int clusterCount = 3;
    Mat centers(clusterCount, 1, samples.type());
    kmeans(samples, clusterCount, labels,
        TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0),
        3, KMEANS_PP_CENTERS, centers);

    最后我們把不同的簇用不同灰度來表示,並把結果放在img1中。

    //我們已知有3個聚類,用不同的灰度層表示。
    Mat img1(img.rows, img.cols, CV_8UC1);
    float step=255/(clusterCount - 1);
    k=0;
    for(i=0; i < img1.rows; i++)
        {
        p = img1.ptr<uchar>(i);
        for(j=0; j< img1.cols; j++)
            {
               int tt = labels.at<int>(k, 0);
               k++;
               p[j] = 255 - tt*step;
            }
        }

    namedWindow("image1");
    imshow("image1", img1);

程序運行后的效果:

image

程序代碼:工程FirstOpenCV17


免責聲明!

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



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