天天看点

使用OpenCV的kmeans实现图像分割

作者:音视频开发老舅

1、概述

  案例:使用kmeans算法实现图像分割

kmeans算法参数介绍:
 kmeans( InputArray data, int K, InputOutputArray bestLabels,
                            TermCriteria criteria, int attempts,
                            int flags, OutputArray centers = noArray() )
 
data:输入数据,此输入数据必须是CV_32F类型的
k:要分成几个类别
bestLabels:分类的标签(分成k类,那么就有k种类型的标签)
criteria:表示kmeans分割的停止条件
attempts:判断某个样本属于某个类别的最少聚类次数。例如:3代表此列别如果聚类了3此就说明它属于这个类别
flags:中心初始化方法
    有三个值可选:
        1.KMEANS_RANDOM_CENTERS 表示随机初始化簇心
        2.KMEANS_PP_CENTERS 表示用kmeans++算法来初始化簇心
        3.KMEANS_USE_INITIAL_LABELS 表示第一次聚类时用用户给定的值初始化聚类,后面几次的聚类,则自动确定簇心。
centers:表示最终分割后每个聚类的中心点位置           

  使用kmeans实现图像像素分割的步骤:

    1.载入输入图像

    2.得到图像的宽、高、通道数

    3.创建一个CV_32F的的Mat用于存放样本数据(由于kmeans方法的输入数据必须是CV_32F类型的,而直接载入的图像数据是CV_8U类型的所以要经过一层转换)

    4.将输入图像的RGB数据转换为 CV_32F的数据

    5.使用kmeans算法开始给样本数量分类

    6.显示图像分割后的结果

2、代码样例

//输入图像
    Mat src = imread(filePath);
    if(src.empty()){
        qDebug()<<"图片为空";
        return;
    }
    imshow("src",src);
    //定义随机颜色
    Scalar colorTab[] = {
        Scalar(0,0,255),
        Scalar(0,255,0),
        Scalar(255,0,0),
        Scalar(0,255,255),
        Scalar(255,0,255)
    };
    //获取原图属性,宽高及维度
    int width = src.cols;
    int height = src.rows;
    int dims = src.channels();//通道数


    //初始化采样数量
    int sampleCount= width*height;
    int clusterCount = 4;//四分类
    Mat points(sampleCount,dims,CV_32F,Scalar(10));
    Mat labels;
    Mat centers(clusterCount,1,points.type());
    //将RGB图片数据转换为样本数据,因为kmeans要求输入的样本数据为CV_32F类型的
    int index = 0;
    for(int row = 0;row<height;row++){
        for(int col = 0;col<width;col++){
            index = row*width+col;
            Vec3b bgr = src.at<Vec3b>(row,col);
            points.at<float>(index,0) = static_cast<int>(bgr[0]);
            points.at<float>(index,1) = static_cast<int>(bgr[1]);
            points.at<float>(index,2) = static_cast<int>(bgr[2]);
        }
    }

    //使用KMeans分类
    TermCriteria criteria = TermCriteria(TermCriteria::EPS+TermCriteria::COUNT,10,0.1);
    kmeans(points,clusterCount,labels,criteria,3,KMEANS_PP_CENTERS,centers);

    //显示图像分割后的结果
    Mat result = Mat::zeros(src.size(),src.type());
    for(int row=0;row<height;row++){
        for(int col=0;col<width;col++){
            index  = row*width+col;
            int label = labels.at<int>(index,0);
            result.at<Vec3b>(row,col)[0] = colorTab[label][0];
            result.at<Vec3b>(row,col)[1] = colorTab[label][1];
            result.at<Vec3b>(row,col)[2] = colorTab[label][2];
        }
    }
    imshow("result",result);
QT开发交流君羊:714620761           

3、示例图片

使用OpenCV的kmeans实现图像分割

继续阅读