2012-04-20 34 views
5

Câu hỏi này dành riêng cho opencv: Ví dụ về km được đưa ra trong tài liệu opencv có ma trận 2 kênh - một kênh cho mỗi thứ nguyên của vectơ đặc trưng. Tuy nhiên, một số ví dụ khác dường như nói rằng nó phải là một ma trận một kênh với các tính năng dọc theo các cột với một hàng cho mỗi mẫu. Điều nào trong số này là đúng?Ma trận đầu vào cho các cụm công nghiệp opencv phân cụm

nếu tôi có một vector 5 tính năng chiều, những gì nên là ma trận đầu vào mà tôi sử dụng: này một:

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

hay này:

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

Trả lời

28

Câu trả lời đúng là cv::Mat inputSamples(numSamples, numFeatures, CV_32F) . Các OpenCV Tài liệu về kmeanssays:

mẫu - ma trận Floating-point của mẫu đầu vào, một hàng cho mỗi mẫu

Vì vậy, nó không phải là một vector Floating-point phao n-Dimensional như trong tùy chọn khác. Ví dụ nào đã đề xuất một hành vi như vậy?

Đây cũng là một ví dụ nhỏ của tôi cho biết cách sử dụng km km. Nó cụm các điểm ảnh của một hình ảnh và hiển thị kết quả:

#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); 
} 
+0

Tôi muốn biết những gì bạn đang làm trong vòng lặp trước khi khai báo biến clusterCount và cũng là những gì bạn đang làm ở cuối cho sau khi kmeans. Bạn có nghĩ rằng có thể cập nhật câu trả lời với thông tin này không? Cảm ơn! –

+0

Vòng lặp đầu tiên sắp xếp lại dữ liệu từ hình ảnh từ ma trận (hàng, cols, 3) sang ma trận (hàng * cols, 3) (một hàng trên mỗi pixel). Vòng lặp ở cuối thay thế từng pixel trong hình ảnh bằng trung tâm cụm tương ứng để hiển thị. – sietschie

+0

Có thể sử dụng 'Mat :: reshape()' thay vì lồng nhau cho vòng lặp? – Jayesh

1

Như thay thế cho định hình lại ma trận đầu vào bằng tay, bạn có thể sử dụng OpenCV reshape chức năng để đạt được kết quả tương tự với mã ít hơn. Đây là triển khai làm việc của tôi về việc giảm số lượng màu với phương pháp K-Means (trong 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 đọc hình ảnh thành ma trận 2 chiều, 3 kênh. Cuộc gọi đầu tiên đến reshape - img.reshape(1, img.rows() * img.cols()); - về cơ bản sẽ hủy 3 kênh thành các cột. Trong kết quả ma trận một hàng tương ứng với một điểm ảnh của hình ảnh đầu vào, và 3 cột tương ứng với các thành phần RGB.

Sau khi thuật toán K-Means kết thúc công việc và ánh xạ màu đã được áp dụng, chúng tôi gọi reshape lần nữa - imgMapped.reshape(3, img.rows()), nhưng bây giờ quay trở lại kênh và giảm số hàng thành số hàng ảnh gốc, định dạng ma trận ban đầu, nhưng chỉ với màu sắc giảm.

+0

I nghĩ rằng bạn cần phải quan tâm rằng hình ảnh liên tục trước tiên trước khi thực hiện phương pháp này http://docs.opencv.org/2.4/modules/core/doc/basic_structures.html#mat-iscontinuous – ejectamenta

+0

nếu bạn sử dụng bản sao tức là. sử dụng bản sao như trong img.clone(). reshape (1, img.rows() * img.cols()) sau đó ảnh sẽ liên tục (và ảnh gốc của bạn sẽ không thay đổi) – ejectamenta

Các vấn đề liên quan