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

你可能感兴趣的:(opencv)