Sunday, 20 October 2013

openCV and color quantization--01 : kmeans

   color quantization is a powerful weapon for image segmentation.


graph_00
    At first, I separate the image by thresholding graph_00, but the results are far from satisfy.

Otsu



void separate_by_otsu(cv::Mat const &src)
{
    cv::Mat result = src.clone();

    cv::threshold(result, result, 0, 255,      
                  cv::THRESH_BINARY + cv::THRESH_OTSU);
}

graph_01(process by otsu)


Adaptive Threshold


void separate_adaptive_threshold(cv::Mat const &src)
{
    cv::Mat result = src.clone();

    cv::adaptiveThreshold(result, result, 255,
       CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 7, 7);    

    cv::adaptiveThreshold(result, result, 255,
            CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 7, 7);
}

graph_02(process by adaptive gaussian)

graph_03(process by adaptive mean)


Kmeans

   As you can see, the results(graph_01~graph_03) can't cut out the second card.Luckily, the colors of the cards and the background are different, a fairly good example for kmeans.

  To adopt the cv::kmeans, we need to transfer the image into a samples, each data set of the samples should consist a pixel groups(ex : bgr, rgb, hsv and so on).To generate the image after color segmentation, we have to map the centers generated by the cv::kmeans to the image.



#include <iostream>

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

int main()
{    
    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;
        }
    }

    cv::Mat binary;    
    cv::Canny(new_image, binary, 30, 90);

    cv::imshow("original", src);
    cv::imshow("binary", binary);
    cv::imshow( "clustered image", new_image );

    cv::waitKey();

    return 0;
}


   In step 1, we rearrange src to sample as following

src :
(b00,g00,r00) (b01,g01,r01)  (b02,g02,r02).......
(b10,g10,r10) (b11,g11,r11)  (b12,g12,r12).......
............

to

sample :
(b00,g00,r00)
(b01,g01,r01)
(b02,g02,r02)
...........
(b10,g10,r10)
(b11,g11,r11)
(b12,g12,r12)
 ................


   The results of the labels are associated with the samples generated by cv::kmeans.The order of reading the labels should be the same as you generated the samples.

graph_04(process by kmeans)

graph_05(apply canny on graph_04)

  Now we could cut the cards from graph_04 without much troubles.To simplify the procedures of kmeans segmentation, I encapsulate it by class.The codes can download from github.

2 comments:

  1. Color quantization is a technique used to reduce the number of distinct colors in an image while preserving its overall visual appearance. In the context of image segmentation, it simplifies the image by grouping similar colors together, making it easier to identify and separate regions. By reducing color complexity, segmentation algorithms can more effectively cluster pixels into meaningful groups. Common methods for color quantization include K-Means clustering, median cut, and octree quantization, where pixels are assigned to a limited set of representative colors.

    ReplyDelete
  2. This approach is widely used as a preprocessing step in computer vision tasks, especially when dealing with high-resolution color images. By applying quantization before Image Segmentation Projects , noise is reduced and computational efficiency is improved. Techniques from Machine Learning Projects for Final Year, such as clustering algorithms, play a key role in implementing color quantization. It is particularly useful in applications like object detection, medical image analysis, and image compression, where simplifying color information helps in achieving more accurate and faster segmentation results.

    ReplyDelete