2016-09-21 66 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; 

}