2016-09-21 60 views
2

在深入探讨我的问题之前,我希望您知道我已阅读此论坛上的其他帖子,但没有人关注我的问题。 特别是,帖子here回答了“如何做到这一点?”的问题。与k-means,虽然我已经知道我必须使用它,我想知道为什么我的实现不起作用。OpenCV:无法使用k-means获得图像分割

我想使用k-means算法根据输入图像的颜色将输入图像的像素分成多个簇。然后,在完成这样的任务之后,我希望每个像素都具有它被分配给的集群中心的颜色。 为参考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; 
} 

总之,在计算快结束时,我只是得到一个黑色的图像。 你知道为什么吗? 奇怪的是,如果我在算法结束时初始化结果矩阵作为

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

它将显示完全输入图像,没有任何分段。

特别是,我有两个疑惑:

1)是正确的躺在矩阵的每一行像素的RGB值调整我做的方式?有没有办法做到这一点没有循环?

2)k-means函数完成工作后,中心的内容究竟是什么?它是一个3列矩阵,它是否包含集群中心的RGB值?

感谢您的支持。下面

+0

可能有重复的[是否有公式确定给定BGR值的整体颜色? (OpenCV和C++)](http://stackoverflow.com/questions/34734379/is-there-a-formula-to-determine-overall-color-given-bgr-values-opencv-and-c) – Miki

+0

感谢回答。您提供的帖子解决了我的问题,给了我一个工作代码片段。无论如何,如果可能的话,我想知道我的错在哪里,因为我几乎肯定会在下次发生同样的错误。我能否对这两个疑问做出回答?感谢支持和抱歉,如果我问太多:) 我希望你不会把这个帖子当作经典的重复案例:) – ubisum

+0

1)是的,正确的,但他们应该是浮动值。你可以在我的文章中看到如何做到没有循环。 2)是的,集群中心的BGR值以浮点数表示,需要转换为uchar。我现在不能更深入地看这个,但我的帖子应该清楚 – Miki

回答

0

-The张贴的OpenCV程序的图像

在分配用户优选的颜色的特定像素值 - ScanImageAndReduceC()在OpenCV的预定义的方法来通过图像的所有像素扫描

- I.atuchar>(10, 10) = 255;用于访问图像

这里的特定像素值的代码:

垫& ScanImageAndReduceC(太& I) {

//仅接受字符类型的矩阵 CV_Assert(I。深度()== 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; 

}

主要------- -------计划

调用上面的方法在我们的主程序

diff = ScanImageAndReduceC(diff); 

namedWindow("Difference", WINDOW_AUTOSIZE);// Create a window for display. 
imshow("Difference", diff);     // Show our image inside it. 

waitKey(0);           // Wait for a keystroke in the window 
return 0; 

}