【问题标题】:Input matrix to opencv kmeans clusteringopencv kmeans 聚类的输入矩阵
【发布时间】:2012-05-01 17:24:19
【问题描述】:

这个问题是opencv特有的: opencv 文档中给出的 kmeans 示例有一个 2 通道矩阵 - 特征向量的每个维度都有一个通道。但是,其他一些示例似乎说它应该是一个单通道矩阵,其特征沿列具有每个样本的一行。哪个是对的?

如果我有一个 5 维特征向量,我使用的输入矩阵应该是什么: 这个:

cv::Mat inputSamples(numSamples, 1, CV32FC(numFeatures))

或者这个:

cv::Mat inputSamples(numSamples, numFeatures, CV_32F)

【问题讨论】:

    标签: opencv cluster-analysis k-means


    【解决方案1】:

    正确答案是cv::Mat inputSamples(numSamples, numFeatures, CV_32F)。 关于kmeanssays的OpenCV文档:

    samples – 输入样本的浮点矩阵,每个样本一行

    所以它不是另一个选项中的 n 维浮点数的浮点向量。哪些例子表明了这种行为?

    这也是我的一个小例子,展示了如何使用 kmeans。它对图像的像素进行聚类并显示结果:

    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    
    using namespace cv;
    
    int main( int argc, char** argv )
    {
      Mat src = imread( argv[1], 1 );
      Mat samples(src.rows * src.cols, 3, CV_32F);
      for( int y = 0; y < src.rows; y++ )
        for( int x = 0; x < src.cols; x++ )
          for( int z = 0; z < 3; z++)
            samples.at<float>(y + x*src.rows, z) = src.at<Vec3b>(y,x)[z];
    
    
      int clusterCount = 15;
      Mat labels;
      int attempts = 5;
      Mat centers;
      kmeans(samples, clusterCount, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 10000, 0.0001), attempts, KMEANS_PP_CENTERS, centers );
    
    
      Mat new_image( src.size(), src.type() );
      for( int y = 0; y < src.rows; y++ )
        for( int x = 0; x < src.cols; x++ )
        { 
          int cluster_idx = labels.at<int>(y + x*src.rows,0);
          new_image.at<Vec3b>(y,x)[0] = centers.at<float>(cluster_idx, 0);
          new_image.at<Vec3b>(y,x)[1] = centers.at<float>(cluster_idx, 1);
          new_image.at<Vec3b>(y,x)[2] = centers.at<float>(cluster_idx, 2);
        }
      imshow( "clustered image", new_image );
      waitKey( 0 );
    }
    

    【讨论】:

    • 我想知道您在 clusterCount 变量声明之前的循环中在做什么,以及在 kmeans 之后的 for 最后您在做什么。您认为可以使用此信息更新答案吗?谢谢!
    • 第一个循环将图像中的数据从 (rows,cols,3) 矩阵重新排序为 (rows*cols,3) 矩阵(每个像素一行)。最后的循环将图像中的每个像素替换为对应的聚类中心进行可视化。
    • 可以用Mat::reshape()代替嵌套的for循环吗?
    • 最终转换时索引错误,应该是 int cluster_idx = bestLabels.at(x + y*img.cols,0);
    • 你为什么要像这样奇怪地重新排序数据?从循环来看,图像的第一行现在将是 0、10、20、30... 行样本,第二行将在 1、11、21、31...跨度>
    【解决方案2】:

    作为手动重塑输入矩阵的替代方法,您可以使用 OpenCV reshape 函数以更少的代码实现类似的结果。这是我使用 K-Means 方法(在 Java 中)减少颜色计数的工作实现:

    private final static int MAX_ITER = 10;
    private final static int CLUSTERS = 16;
    
    public static Mat colorMapKMeans(Mat img, int K, int maxIterations) {
    
        Mat m = img.reshape(1, img.rows() * img.cols());
        m.convertTo(m, CvType.CV_32F);
    
        Mat bestLabels = new Mat(m.rows(), 1, CvType.CV_8U);
        Mat centroids = new Mat(K, 1, CvType.CV_32F);
        Core.kmeans(m, K, bestLabels, 
                    new TermCriteria(TermCriteria.COUNT | TermCriteria.EPS, maxIterations, 1E-5),
                    1, Core.KMEANS_RANDOM_CENTERS, centroids);
        List<Integer> idx = new ArrayList<>(m.rows());
        Converters.Mat_to_vector_int(bestLabels, idx);
    
        Mat imgMapped = new Mat(m.size(), m.type());
        for(int i = 0; i < idx.size(); i++) {
            Mat row = imgMapped.row(i);
            centroids.row(idx.get(i)).copyTo(row);
        }
    
        return imgMapped.reshape(3, img.rows());
    }
    
    public static void main(String[] args) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        Highgui.imwrite("result.png", 
            colorMapKMeans(Highgui.imread(args[0], Highgui.CV_LOAD_IMAGE_COLOR),
                CLUSTERS, MAX_ITER));
    }
    

    OpenCV 将图像读入 2 维 3 通道矩阵。首先调用reshape - img.reshape(1, img.rows() * img.cols()); - 基本上将 3 个通道展开为列。在生成的矩阵中,一行对应于输入图像的一个像素,三列对应于 RGB 分量。

    在 K-Means 算法完成工作并应用颜色映射后,我们再次调用 reshape - imgMapped.reshape(3, img.rows()),但现在将列回滚到通道中,并将行数减少到原始图像行数,因此恢复原始矩阵格式,但仅使用减少的颜色。

    【讨论】:

    • 我认为在采用这种方法之前,您需要注意图像是连续的docs.opencv.org/2.4/modules/core/doc/…
    • 如果你使用克隆即。在 img.clone().reshape(1, img.rows() * img.cols()) 中使用克隆,然后图像将是连续的(并且您的原始图像将保持不变)
    猜你喜欢
    • 2012-06-30
    • 2019-03-31
    • 2017-04-13
    • 2016-02-03
    • 2015-09-28
    • 2011-08-16
    • 2021-05-07
    • 2011-02-25
    相关资源
    最近更新 更多