• opencvKmeans图像分割根据颜色


    K-means算法分割

    K-means是一种经典的无监督聚类算法---不需要人工干预。
    算法原理:

    (1)随机选择两个中心点;

     (2)计算每个点到这两个中心点的距离,最近的分成一类(连接起来);

     (3)重新计算中心点(平均值计算),计算新的中心点到旧的中心点的差值如果小于输入的值,就说明中心的位置发生了变化,,那么到(2)步重新计算中心点到每个点的距离,开始下一次循环;

     (4)执行多个迭代之后,满足收敛时,得到最终的分类

    应用:分类

    【根据颜色分类】

    #include<opencv2/opencv.hpp>
    #include<iostream>
    
    
    int main(int argc, char** argv) {
    
        cv::Mat img(500, 500, CV_8UC3);
        cv::RNG rng(12345);
        cv::Scalar colorTab[] = {
            cv::Scalar(0, 0, 255),
            cv::Scalar(0, 255, 0),
            cv::Scalar(255, 0, 0),
            cv::Scalar(0, 255, 255),
            cv::Scalar(255, 0, 255)
        };
        int numCluster = rng.uniform(2, 5);
        printf("种类数量 : %d\n", numCluster); 
        //4
        int sampleCount = rng.uniform(2, 1000);//随机样本
        printf("样本数量 : %d\n", sampleCount);
        //591
        cv::Mat points(sampleCount, 1, CV_32FC2);
        cv::Mat labels;
        cv::Mat centers;
    
        for (int k = 0; k < numCluster; k++) {
            cv::Point center;
            center.x = rng.uniform(0, img.cols);//随机坐标
            center.y = rng.uniform(0, img.rows);
            cv::Mat pointChunk = points.rowRange(k * sampleCount / numCluster, k == numCluster - 1 ? sampleCount : (k + 1) * sampleCount / numCluster);
            //每一类占1/numCluster 行
            //rng.fill(pointChunk, cv::RNG::NORMAL, cv::Scalar(center.x, center.y), cv::Scalar(img.cols * 0.05, img.rows * 0.05));//用随机数填充矩阵
            rng.fill(pointChunk, cv::RNG::UNIFORM, 0, 255);//用随机数填充矩阵
            
        }
    
        randShuffle(points, 1, &rng);//算法打乱元素排列顺序
        kmeans(points, numCluster, labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 10, 0.1), 3, cv::KMEANS_PP_CENTERS, centers);
        /*【根据参数1的坐标进行分类】
        参数1:为cv::Mat类型,每行代表一个样本,即特征,即mat.cols=特征长度,mat.rows=样本数,数据类型仅支持float
        参数2:K  指定聚类时划分为几类
        参数3:为cv::Mat类型,是一个长度为(样本数,1)的矩阵,即mat.cols=1,mat.rows=样本数;为K-Means算法的结果输出,指定每一个样本聚类到哪一个label中【指定每一个样本聚类到哪一类中】
        参数4:TermCriteria类,算法进行迭代时终止的条件,可以指定最大迭代次数,也可以指定预期的精度,也可以这两种同时指定;
                参数1:int type 
                        type=TermCriteria::MAX_ITER/TermCriteria::COUNT  迭代到最大或迭代次数终止
                        type= TermCriteria::EPS   迭代到阈值终止
                        type= TermCriteria::MAX_ITER+ TermCriteria::EPS 上述两者都作为迭代终止条件
                参数2:int maxCount  迭代的最大次数
                参数3:double epsilon   阈值(中心位移值)
        参数5:指定K-Means算法执行的次数,每次算法执行的结果是不一样的,选择最好的那次结果输出
        参数6:初始化均值点的方法,目前支持三种:KMEANS_RANDOM_CENTERS、KMEANS_PP_CENTERS、KMEANS_USE_INITIAL_LABELS 
        参数7:为cv::Mat类型,输出最终的均值点,mat.cols=特征长度,mat.rols=K 【每个类的中心点】
    
        */
    
    
        // 用不同颜色显示分类
        //初始化图片颜色。
        img = cv::Scalar::all(255);
        for (int i = 0; i < sampleCount; i++) {
            int index = labels.at<int>(i);
            //获取ponint点
            cv::Point p = points.at<cv::Point2f>(i);
            //填充
            circle(img, p, 2, colorTab[index], -1, 8);
        }
    
        // 每个聚类的中心来绘制圆
        for (int i = 0; i < centers.rows; i++) {
            int x = centers.at<float>(i, 0);
            int y = centers.at<float>(i, 1);
            printf("c.x= %d, c.y=%d", x, y);
            circle(img, cv::Point(x, y), 40, colorTab[i], 1, cv::LINE_AA);
        }
    
        imshow("KMeans-Data-Demo", img);
    
    
    
            
        cv::waitKey(0);
        return 0;
    }

    实例 

    2.png

    #include<opencv2/opencv.hpp>
    #include<iostream>
    
    int main(int argc, char** argv) {
    
        
        cv::Scalar colorTab[] = {
            cv::Scalar(0, 0, 255),
            cv::Scalar(0, 255, 0),
            cv::Scalar(255, 0, 0),
            cv::Scalar(0, 255, 255),
            
            };
        
        cv::Mat src = cv::imread("D:/bb/tu1/2.png");
        if (!src.data)
        {
            printf("图像读取失败...\n");
            return -1;
        }
        cv::imshow("src", src);
    
        int width = src.cols;
        int height = src.rows;
        int dims = src.channels();
    
        int sampleCount = width * height;  //总像素
        int clusterCount = 4;  //分类数量
        cv::Mat points(sampleCount, dims,CV_32F,cv::Scalar(10));
        //一个像素为一行
        cv::Mat labels;
        cv::Mat centers(clusterCount,1, points.type());
        //保存中心坐标
    
        //把RGB数据转换成样本数据
        int index = 0;//像素序号
        for (int row = 0; row < height;row++) {
            for (int col = 0; col < width;col++) {
                index = row * width + col;
                cv::Vec3b bgr = src.at<cv::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]);
    
            }
    
        }
    
          
        cv::TermCriteria criteria = cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS,10,0.1);
        //kmeans的终止的条件
        
        kmeans(points, clusterCount, labels, criteria, 3, cv::KMEANS_PP_CENTERS, centers);//运行kmeans 
    
        //显示图像分割结果
        cv::Mat result = cv::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<cv::Vec3b>(row, col)[0] = colorTab[label][0];
                result.at<cv::Vec3b>(row, col)[1] = colorTab[label][1];
                result.at<cv::Vec3b>(row, col)[2] = colorTab[label][2];
                
            }
        }
    
        cv::imshow("result", result);
    
    
    
    
    
        cv::waitKey(0);
        return 0;
    }

  • 相关阅读:
    树链剖分( 洛谷P3384 )
    ZJOI 2015 诸神眷顾的幻想乡
    BZOJ 1002 [FJOI2007]轮状病毒
    洛谷 P1485 火枪打怪
    Luogu2860 [USACO06JAN]冗余路径Redundant Paths
    CF962F Simple Cycles Edges
    Luogu3605 [USACO17JAN]Promotion Counting晋升者计数
    Luogu2295 MICE
    CF341D Iahub and Xors
    CF617E XOR and Favorite Number
  • 原文地址:https://www.cnblogs.com/liming19680104/p/15737586.html
Copyright © 2020-2023  润新知