简体   繁体   English

OpenCV:无法使用k-means进行图像分割

[英]OpenCV: can't get segmentation of image using k-means

Before going into deep of my question, I want you to know that I've read other posts on this forum, but none regards my problem. 在深入探讨我的问题之前,我希望您知道我已经阅读了该论坛上的其他帖子,但是没有人认为我的问题与众不同。 In particular, the post here answers the question "how to do this?" 特别是, 这里的帖子回答了“如何做到这一点”的问题。 with k-means, while I already know that I have to use it and I'd like to know why my implementation doesn't work. 使用k-means,虽然我已经知道必须使用它,并且我想知道为什么我的实现无法正常工作。

I want to use k-means algorithm to divide pixels of an input image into clusters, according to their color. 我想使用k-means算法将输入图像的像素根据其颜色分为几类。 Then, after completing such task, I want each pixel to have the color of the center of the cluster it's been assigned to. 然后,完成此任务后,我希望每个像素都具有分配给它的群集中心的颜色。 Taking as reference the OpenCV examples and other stuff retrieved on the web, I've designed the following code: 以OpenCV示例和网上检索的其他内容为参考,我设计了以下代码:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>

using namespace std;
using namespace cv;


int main( int argc, char** argv )
{

    Mat src = imread( argv[1], 1 );

    // reshape matrix
    Mat resized(src.rows*src.cols, 3, CV_8U);
    int row_counter = 0;

    for(int i = 0; i<src.rows; i++)
    {
        for(int j = 0; j<src.cols; j++)
        {
            Vec3b channels = src.at<Vec3b>(i,j);
            resized.at<char>(row_counter,0) = channels(0);
            resized.at<char>(row_counter,1) = channels(1);
            resized.at<char>(row_counter,2) = channels(2);

            row_counter++;
        }
    }

    //cout << src << endl;

    // change data type
    resized.convertTo(resized, CV_32F);

    // determine termination criteria and number of clusters
    TermCriteria criteria(TermCriteria::COUNT + TermCriteria::EPS, 10, 1.0);
    int K = 8;

    // apply k-means
    Mat labels, centers;
    double compactness = kmeans(resized, K, labels, criteria, 10, KMEANS_RANDOM_CENTERS, centers);

    // change data type in centers
    centers.convertTo(centers, CV_8U);

    // create output matrix
    Mat result = Mat::zeros(src.rows, src.cols, CV_8UC3);

    row_counter = 0;
    int matrix_row_counter = 0;
    while(row_counter < result.rows)
    {
        for(int z = 0; z<result.cols; z++)
        {
            int index = labels.at<char>(row_counter+z, 0);
            //cout << index << endl;
            Vec3b center_channels(centers.at<char>(index,0),centers.at<char>(index,1), centers.at<char>(index,2));
            result.at<Vec3b>(matrix_row_counter, z) = center_channels;
        }

        row_counter += result.cols;
        matrix_row_counter++;
    }

    cout << "Labels " << labels.rows << " " << labels.cols << endl;
    //cvtColor( src, gray, CV_BGR2GRAY );
    //gray.convertTo(gray, CV_32F);

    imshow("Result", result);
    waitKey(0);


    return 0;
}

Anyway, at the end of computation, I simply get a black image. 无论如何,在计算结束时,我只会得到一张黑色图像。 Do you know why? 你知道为什么吗? Strangely, if I initialize result matrix as 奇怪的是,如果我将结果矩阵初始化为

Mat result(src.size(), src.type())

at the end of algorithm it will display exactly the input image, without any segmentation. 在算法结束时,它将准确显示输入图像,而不会进行任何分割。

In particular, I have two doubts: 特别是,我有两个疑问:

1) is it correct to lay the RGB values of a pixel on each row of matrix resized the way I've done it? 1)将像素的RGB值放置在按照我的方法调整大小的矩阵的每一行上是否正确? is there a way to do it without a loop? 有没有办法做到这一点而没有循环?

2) what's exactly the content of centers , after k-means function finishes working? 2)在k均值函数完成工作之后, 中心的确切内容是什么? it's a 3 columns matrix, does it contains the RGB values of clusters' centers? 它是一个3列的矩阵,它是否包含聚类中心的RGB值?

thanks for support. 感谢你的支持。

-The below posted OpenCV program assigns the user preferred color to a particular pixel value in an image -下面发布的OpenCV程序将用户喜欢的颜色分配给图像中的特定像素值

- ScanImageAndReduceC() is a predefined method in OpenCV to scan through all the pixels of an Image ScanImageAndReduceC()是OpenCV中的预定义方法,可扫描图像的所有像素

- I.atuchar>(10, 10) = 255; I.atuchar>(10, 10) = 255; is used to access a particular pixel value of an image 用于访问图像的特定像素值

Here is the code: 这是代码:

Mat& ScanImageAndReduceC(Mat& I) {

// accept only char type matrices CV_Assert(I.depth() == CV_8U);

// accept only char type matrices CV_Assert(I.depth() == CV_8U);
 int channels = I.channels(); int nRows = I.rows; int nCols = I.cols * channels; if (I.isContinuous()) { nCols *= nRows; nRows = 1; } int i, j; uchar* p; for (i = 0; i < nRows; ++i) { p = I.ptr<uchar>(i); for (j = 0; j < nCols; ++j) { I.at<uchar>(10, 10) = 255; } } return I; 

} }

-------Main Program------- -------主程序-----

Calling the above method in our main program 在我们的主程序中调用上述方法

 diff = ScanImageAndReduceC(diff); 差异= ScanImageAndReduceC(diff);\n\nnamedWindow("Difference", WINDOW_AUTOSIZE);// Create a window for display. namedWindow(“ Difference”,WINDOW_AUTOSIZE); //创建一个显示窗口。\nimshow("Difference", diff); imshow(“ Difference”,diff); // Show our image inside it. //在其中显示我们的图像。\n\nwaitKey(0); waitKey(0); // Wait for a keystroke in the window //等待窗口中的击键\nreturn 0; 返回0;\n

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM