2016-01-21 134 views
0

基本上,我試圖用較少的像素來表示圖像本身。爲什麼Mat.forEach不會自行更改?

的步驟如下:

  1. 說我將輸入大小爲[1000 * 600]的圖像,然後我得到600_000像素(RGB),這可能是[600_000,3]的載體。 K-Means用於獲取其聚類中心。

  2. 圖像中的每個像素將與通過K-Means找到的集羣中最近的鄰居放置在一起。

來源是:

template <typename T> 
void NN(Point3_<T>& pixel, const Mat& points) 
{ 
    vector<T> vt {pixel.x, pixel.x, pixel.z}; 
    double min_dist = LDBL_MAX; 
    int min_index = -1; 
    for (int i = 0; i < points.rows; ++ i) 
    { 
     double dist = norm(vt, points.row(i), NORM_L2); 
     if (dist < min_dist) 
     { 
      min_dist = dist; 
      min_index = i; 
     } 
    } 
    // assert(min_index != -1); 
    pixel.x = points.at<T>(min_index, 0); 
    pixel.y = points.at<T>(min_index, 1); 
    pixel.z = points.at<T>(min_index, 2); 
} 

template <typename T> 
void NN(Mat& img, const Mat& points) 
{ 
    timer::start("assign"); 
    img.forEach<Point3_<T>>([&points](Point3_<T> &pixel, const int position[]) 
     { 
      NN(pixel, points); 
     }); 
    timer::stop<ms>(); 
} 

Mat kmeans(const Mat& original_img, const int K) 
{ 
    Mat img; 
    original_img.reshape(3, original_img.rows * original_img.cols) 
     .convertTo(img, CV_32FC3); 

    timer::start("K-means cluster"); 
    // Require img.type() == CV_32F 
    Mat clusters = BOWKMeansTrainer(K).cluster(img); 
    timer::stop<ms>(); 

    // Type 5 -> Type 0: 32FC1 -> 8UC1 
    // K rows, 3 cols, 8UC1 
    clusters.convertTo(clusters, CV_8UC1); 
    Mat output_img = original_img; 
    NN<uchar>(output_img, clusters); 

    // assert won't fire, why? 
    assert(equal(original_img.begin<uchar>(), original_img.end<uchar>(), 
     output_img.begin<uchar>())); 

    return output_img; 
} 

int main(int argc, char* argv[]) 
{ 
    vector<int> ks {2, 16}; 
    string filename = "1"; 
    string pathname = string("./img/") + filename + ".jpg"; 

    Mat img = imread(pathname); 
    for (const int& K: ks) 
    { 
     imshow(int_to_string(K), kmeans(img, K)); 
     // write_img(filename, "kmeans", K, kmeans(img, K)); 
    } 

    std::cout << "Press enter to continue..."; 
    cin.get(); 
} 

的問題是:

  1. 斷言()在k均值()將不會觸發。也就是說,墊子對象original_imgoutput_img相同。這怎麼會發生?

  2. main()中的兩個imwrite()將顯示兩個相同的2值圖像。也就是說,K = 2的K均值起作用,而下面的K = 16 不是。請注意,如果我們每次執行輸出一個圖像,一切都很好。

手推車輸出低於:

The buggy output

原始圖像和K均值與K = 16可在下面看到:

The original image

K-Means with K=16

回答

1

感謝上帝!我找到了原因。

在kmeans()中,下面的代碼將調用Mat的複製構造函數,這會使O(1)將original_img的頭部分配給output_img's。

Mat output_img = original_img; 

這就是assert不會觸發的原因。

相關問題