Kmeans clustering outputs black and white only there is no color in the final image

 bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), data.getData());
                ny = new Mat();
                Utils.bitmapToMat(bitmap, ny);

                Mat bgrImage = new Mat();
                Imgproc.cvtColor(ny, bgrImage, Imgproc.COLOR_RGB2BGR);
                bgrImage.convertTo(bgrImage, CvType.CV_32F, 1.0 / 255.0);

                Mat reshapedImage = bgrImage.reshape(3,bgrImage.rows()*bgrImage.cols() );

                Mat labels = new Mat();
                Mat centers = new Mat();
                ArrayList<Integer> labelsList = new ArrayList<>();

                int K = 32; // Number of clusters (colors)
                TermCriteria criteria = new TermCriteria(TermCriteria.EPS + TermCriteria.MAX_ITER, 400, 2.0);

                Core.kmeans(reshapedImage, K, labels, criteria, 1, Core.KMEANS_PP_CENTERS,centers);

                for (int i = 0; i < labels.rows(); i++) {
                    for (int j = 0; j < labels.cols(); j++) {
                        labelsList.add((int) labels.get(i, j)[0]);
                int n = labels.cols() * labels.rows();

                for (int i = 0; i < n; ++i) {
                    double[] color = centers.get(labelsList.get(i), 0);
                    labels.put(i, 0, color);

                labels.convertTo(labels, CvType.CV_8U);

                Core.normalize(labels, labels, 0, 255, Core.NORM_MINMAX, CvType.CV_8UC3);


                labels = labels.reshape(3,bgrImage.rows());

                Mat blured = new Mat();
                int kernelsz = 5;
                Imgproc.medianBlur(labels, blured, kernelsz);

                Bitmap resultBitmap = Bitmap.createBitmap(blured.cols(), blured.rows(), Bitmap.Config.ARGB_8888);
                Utils.matToBitmap(blured, resultBitmap);


debug your code. look at intermediate values. work on a very small image, so you can see all the values.

what do you think that will do? give you color where there was none?

Mat reshapedImage = bgrImage.reshape(3,bgrImage.rows()*bgrImage.cols() );

kmeans works on colums, not channels, you need to supply a [w*h,3] single channel matrix, so:

input = image.reshape(1,w*h)

the output will be a [w*h,1] (1d !) labels array, and a [K,3] (single channel !) centers array

from that you can reconstruct the kmeans image by:

  1. make a new (pseudo 1d) image from the labels / centers:
    Mat rec(w*h, 3, CV_32); // same as input
    for (int i=0; i<w*h; i++) {
        int j = labels[i]
        rec.row(i) = centers.row(j); // copy, each row is a 'pixel'
  1. reshape to orig size / type:
    rec = rec.reshape(3, h);
    rec.convertTo(rec, CV_8U, 255);

in general, when in doubt, profile/measure/check. stop guessing !

1 Like

that actually worked thank you . I am quite new to opencv thats why ı didnt know what ı was doing and ı was lost.Thank you so much