Ask Your Question
2

How can you use K-Means clustering to posterize an image using c++?

asked 2014-02-05 19:17:51 -0600

humungousDust2 gravatar image

updated 2016-01-22 07:01:17 -0600

Hi all,

I'm trying to posterize an image, i.e. reduce the number of colours in an image, but I'm not having much luck.

I've found the following Python code from OpenCV's documentation, which uses K-Means:

import numpy as np
import cv2

img = cv2.imread('home.jpg')
Z = img.reshape((-1,3))

# convert to np.float32
Z = np.float32(Z)

# define criteria, number of clusters(K) and apply kmeans()
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 8
ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)

# Now convert back into uint8, and make original image
center = np.uint8(center)
res = center[label.flatten()]
res2 = res.reshape((img.shape))

cv2.imshow('res2',res2)
cv2.waitKey(0)
cv2.destroyAllWindows()

My problem is that I only know C/C++. Would someone please help me out by converting this to the C++ equivalent?

Thanks in advance.

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
3

answered 2014-02-06 02:11:12 -0600

Viatorus gravatar image

You are looking for clustering. Have look here: http://stackoverflow.com/a/10242156/1611317

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

using namespace cv;

int main( int argc, char** argv )
{
  Mat src = imread( argv[1], 1 );
  Mat samples(src.rows * src.cols, 3, CV_32F);
  for( int y = 0; y < src.rows; y++ )
    for( int x = 0; x < src.cols; x++ )
      for( int z = 0; z < 3; z++)
        samples.at<float>(y + x*src.rows, z) = src.at<Vec3b>(y,x)[z];


  int clusterCount = 15;
  Mat labels;
  int attempts = 5;
  Mat centers;
  kmeans(samples, clusterCount, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 10000, 0.0001), attempts, KMEANS_PP_CENTERS, centers );


  Mat new_image( src.size(), src.type() );
  for( int y = 0; y < src.rows; y++ )
    for( int x = 0; x < src.cols; x++ )
    { 
      int cluster_idx = labels.at<int>(y + x*src.rows,0);
      new_image.at<Vec3b>(y,x)[0] = centers.at<float>(cluster_idx, 0);
      new_image.at<Vec3b>(y,x)[1] = centers.at<float>(cluster_idx, 1);
      new_image.at<Vec3b>(y,x)[2] = centers.at<float>(cluster_idx, 2);
    }
  imshow( "clustered image", new_image );
  waitKey( 0 );
}
edit flag offensive delete link more

Comments

Perfect, thank you very much. This was exactly what I was looking for.

humungousDust2 gravatar imagehumungousDust2 ( 2014-02-09 20:05:30 -0600 )edit

Thank you for this, you saved my day !1

Hemang gravatar imageHemang ( 2017-01-26 18:21:52 -0600 )edit

Question Tools

Stats

Asked: 2014-02-05 19:17:51 -0600

Seen: 14,622 times

Last updated: Feb 06 '14