Ask Your Question

Color classification

asked 2016-03-07 20:50:44 -0500

cv_new gravatar image

updated 2016-03-08 03:19:35 -0500

I am goint to find out hsv values of four main colors in a image like this, so that I could get those values.(minH1, minS1, ..., maxS4, maxV4). What would be the best way to make a color clustering?

image description

Scalar lowerA = new Scalar( minH1,minS1,minV1);
Scalar upperA = new Scalar(maxH1,maxS1,maxV1);

Scalar lowerB = new Scalar( minH2,minS2,minV2);
Scalar upperB = new Scalar(maxH2,maxS2,maxV2);

Scalar lowerC = new Scalar( minH3,minS3,minV3);
Scalar upperC = new Scalar(maxH3,maxS3,maxV3);

Scalar lowerD = new Scalar( minH4,minS4,minV4);
Scalar upperD = new Scalar(maxH4,maxS4,maxV4);

The k-mean clustering are not doing quite well in the HSV domain. How could I solve it?

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.TermCriteria;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
//import org.opencv.highgui.Highgui;

public class TestingOpenCV {
    public static void main (String[] args) {
        Mat img = Imgcodecs.imread("C:\\imagetesting\\defimgGray.jpg");    // 入力画像の取得
        int k = 5;
        Mat hsv = new Mat();
        Mat cropped_hsv = new Mat();
        Imgproc.cvtColor(img, hsv, Imgproc.COLOR_RGB2HSV); 
        List<Mat> channels = new ArrayList<Mat>();
        cropped_hsv = channels.get(0);
        List<Mat> temp = new ArrayList<Mat>();
        temp = cluster(hsv, k);
        Mat clusters1 = temp.get(0);
        Mat clusters2 = temp.get(1);
        Mat clusters3 = temp.get(2);
        Mat clusters4 = temp.get(3);
        Mat clusters5 = temp.get(4);

        Imgcodecs.imwrite("C:\\imagetesting\\clusters1.jpg",clusters1);             // 画像をJPG形式で保存
        Imgcodecs.imwrite("C:\\imagetesting\\clusters2.jpg",clusters2);             // 画像をJPG形式で保存
        Imgcodecs.imwrite("C:\\imagetesting\\clusters3.jpg",clusters3);             // 画像をJPG形式で保存
        Imgcodecs.imwrite("C:\\imagetesting\\clusters4.jpg",clusters4);             // 画像をJPG形式で保存
        Imgcodecs.imwrite("C:\\imagetesting\\clusters5.jpg",clusters5);             // 画像をJPG形式で保存

    public static List<Mat> cluster(Mat cutout, int k) {
        Mat samples = cutout.reshape(1, cutout.cols() * cutout.rows());
        Mat samples32f = new Mat();
        samples.convertTo(samples32f, CvType.CV_32F, 1.0 / 255.0);
        Mat labels = new Mat();
        TermCriteria criteria = new TermCriteria(TermCriteria.COUNT, 100, 1);
        Mat centers = new Mat();
        Core.kmeans(samples32f, k, labels, criteria, 1, Core.KMEANS_PP_CENTERS, centers);
        return showClusters(cutout, labels, centers);

    private static List<Mat> showClusters (Mat cutout, Mat labels, Mat centers) {
        centers.convertTo(centers, CvType.CV_8UC1, 255.0);
        List<Mat> clusters = new ArrayList<Mat>();

        for(int i = 0; i < centers.rows(); i++) {           
            //clusters.add(Mat.zeros(cutout.size(), cutout.type()));
            Mat light = new Mat(cutout.size(),cutout.type(), new Scalar(255,255,255));

        int rows = 0;
        for(int y = 0; y < cutout.rows(); y++) {
            for(int x = 0; x < cutout.cols(); x++) {

                int label = (int)labels.get(rows, 0)[0];
                int r = (int)centers.get(label, 2)[0];
                int g = (int)centers.get(label, 1)[0];
                int b = (int)centers.get(label, 0)[0];

                Mat tempMat = new Mat(); 
                tempMat = clusters.get(label);
                tempMat.put(y, x, b, g, r);
        return clusters;
edit retag flag offensive close merge delete

2 answers

Sort by » oldest newest most voted

answered 2016-03-08 02:19:52 -0500

berak gravatar image

currently, all your 5 cluster images reference the same set of pixels, so you get 5 times the same image.

solution: make a new (seperate) Mat for each cluster.

for(int i = 0; i < centers.rows(); i++) {
    Mat light = new Mat(cutout.size(),cutout.type(), new Scalar(255,255,255));
edit flag offensive delete link more


Thanks for your help. They are different now. But when I convert the image to HSV domain for further clustering, the resulting clustered image are quite dirty, how can I split the character better? I am going to do the masking afterwards.

cv_new gravatar imagecv_new ( 2016-03-08 02:57:36 -0500 )edit

answered 2016-03-07 21:11:57 -0500

Tetragramm gravatar image

This is a job for K-means clustering. And in fact, this is the subject of one of the tutorials on the subject. Take a look.

edit flag offensive delete link more


I have changed my method to K-means clustering, but I got all the same images at the end.

cv_new gravatar imagecv_new ( 2016-03-07 23:43:22 -0500 )edit
Login/Signup to Answer

Question Tools



Asked: 2016-03-07 20:50:44 -0500

Seen: 943 times

Last updated: Mar 08 '16