Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

The first question I would like to ask you is why do you still using outdated, deprecated, old-style c api?If there is no specific reason, then please use the c++ interface, which has a better support for the moment. The codes written by c++ api are much more easier to read and maintain, prefer c++ api should save you and your colleagues a lot of headaches.

About your problem, you need to map the original data to a group of data(samples), remap the labels and centers generated by kmeans algorithm back to the image.

cv::Mat src = cv::imread(Folder + "perspective05.jpg");
if(src.empty()){
    std::cerr<"can't read the image"<std::endl;
    return -1;
}

//step 1 : map the src to the samples
cv::Mat samples(src.total(), 3, CV_32F);
auto samples_ptr = samples.ptr<float>(0);
for( int row = 0; row != src.rows; ++row){
    auto src_begin = src.ptr<uchar>(row);
    auto src_end = src_begin + src.cols * src.channels();
    //auto samples_ptr = samples.ptr<float>(row * src.cols);
    while(src_begin != src_end){
        samples_ptr[0] = src_begin[0];
        samples_ptr[1] = src_begin[1];
        samples_ptr[2] = src_begin[2];
        samples_ptr += 3; src_begin +=3;
    }        
}

//step 2 : apply kmeans to find labels and centers
int clusterCount = 3;
cv::Mat labels;
int attempts = 5;
cv::Mat centers;
cv::kmeans(samples, clusterCount, labels,
           cv::TermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 
                            10, 0.01),
           attempts, cv::KMEANS_PP_CENTERS, centers);

//step 3 : map the centers to the output
cv::Mat new_image(src.size(), src.type());
for( int row = 0; row != src.rows; ++row){
    auto new_image_begin = new_image.ptr<uchar>(row);
    auto new_image_end = new_image_begin + new_image.cols * 3;
    auto labels_ptr = labels.ptr<int>(row * src.cols);

    while(new_image_begin != new_image_end){
        int const cluster_idx = *labels_ptr;
        auto centers_ptr = centers.ptr<float>(cluster_idx);
        new_image_begin[0] = centers_ptr[0];
        new_image_begin[1] = centers_ptr[1];
        new_image_begin[2] = centers_ptr[2];
        new_image_begin += 3; ++labels_ptr;
    }
}

This blog show you the whole process, explain the reasons and encapsulate those annoying details under the hood.

The first question I would like to ask you is why do you still using outdated, deprecated, old-style c api?If there is no specific reason, then please use the c++ interface, which has a better support for the moment. The codes written by c++ api are much more easier to read and maintain, prefer c++ api should save you and your colleagues a lot of headaches.

About your problem, you need to map the original data to a group of data(samples), remap the labels and centers generated by kmeans algorithm back to the image.

cv::Mat src = cv::imread(Folder + "perspective05.jpg");
if(src.empty()){
    std::cerr<"can't read the image"<std::endl;
    return -1;
}

//step 1 : map the src to the samples
cv::Mat samples(src.total(), 3, CV_32F);
auto samples_ptr float *samples_ptr = samples.ptr<float>(0);
for( int row = 0; row != src.rows; ++row){
    auto src_begin uchar *src_begin = src.ptr<uchar>(row);
    auto src_end uchar *src_end = src_begin + src.cols * src.channels();
    //auto samples_ptr = samples.ptr<float>(row * src.cols);
src.channels();        
    while(src_begin != src_end){
        samples_ptr[0] = src_begin[0];
        samples_ptr[1] = src_begin[1];
        samples_ptr[2] = src_begin[2];
        samples_ptr += 3; src_begin +=3;
    }        
}

//step 2 : apply kmeans to find labels and centers
int clusterCount = 3;
cv::Mat labels;
int attempts = 5;
cv::Mat centers;
cv::kmeans(samples, clusterCount, labels,
           cv::TermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 
                            10, 0.01),
           attempts, cv::KMEANS_PP_CENTERS, centers);

//step 3 : map the centers to the output
cv::Mat new_image(src.size(), src.type());
for( int row = 0; row != src.rows; ++row){
    auto new_image_begin uchar *new_image_begin = new_image.ptr<uchar>(row);
    auto new_image_end uchar *new_image_end = new_image_begin + new_image.cols * 3;
    auto labels_ptr int *labels_ptr = labels.ptr<int>(row * src.cols);

    while(new_image_begin != new_image_end){
        int const cluster_idx = *labels_ptr;
        auto centers_ptr float *centers_ptr = centers.ptr<float>(cluster_idx);
        new_image_begin[0] = centers_ptr[0];
        new_image_begin[1] = centers_ptr[1];
        new_image_begin[2] = centers_ptr[2];
        new_image_begin += 3; ++labels_ptr;
    }
}

This blog show you the whole process, explain the reasons and encapsulate those annoying details under the hood.