I'm trying to convert this snippet of code in Emgu CV using C#. I think I converted most of the thing in what they are supposed to be in EmguCV but the cvKMeans2 keeps shooting me Exception that doesn't make sense.
Here is my code:
Image<Bgr, float> src = new Image<Bgr, float>("c:\\blanc.jpg");
Matrix<Single> samples = new Matrix<Single>(src.Rows * src.Cols, 3);
for (int y = 0; y < src.Rows; y++)
{
for (int x = 0; x < src.Cols; x++)
{
for( int z = 0; z < 3; z++)
{
if(z == 0)
samples[y + x * src.Rows, z] = Convert.ToSingle(src[y, x].Blue);
else if(z == 1)
samples[y + x * src.Rows, z] = Convert.ToSingle(src[y, x].Green);
else if (z == 2)
samples[y + x * src.Rows, z] = Convert.ToSingle(src[y, x].Red);
}
}
}
MCvTermCriteria term = new MCvTermCriteria(10000, 0.0001);
term.type = TERMCRIT.CV_TERMCRIT_ITER | TERMCRIT.CV_TERMCRIT_EPS;
int clusterCount = 3;
Matrix<Int32> labels = new Matrix<Int32>(src.Width, 1);
int attempts = 5;
Matrix<Single> centers = new Matrix<Single>(clusterCount, samples.Cols);
CvInvoke.cvKMeans2(samples, clusterCount, labels, term, attempts, IntPtr.Zero, KMeansInitType.PPCenters, centers, IntPtr.Zero );
Image<Bgr, float> new_image = new Image<Bgr, float>(src.Size);
for (int y = 0; y < src.Rows; y++)
{
for (int x = 0; x < src.Cols; x++)
{
//nTotal++;
int cluster_idx = labels[y + x * src.Rows, 0];
float n1 = centers[cluster_idx, 0];
float n2 = centers[cluster_idx, 1];
float n3 = centers[cluster_idx, 2];
MCvScalar sca = new MCvScalar(n1, n2, n3);
CvInvoke.cvSet2D(new_image, y, x, sca);
}
}
CvInvoke.cvShowImage( "clustered image", new_image );
CvInvoke.cvWaitKey( 0 );
I keep receiving this exception:
Additional information: OpenCV: labels.isContinuous() && labels.type() == CV_32S && (labels.cols == 1 || labels.rows == 1) && labels.cols + labels.rows - 1 == data.rows
It doesn't make sense that the label needs to be of Single type because I need to use it as an index in the loop just after the cvKMeans2. Can anyone help me get this code working? If this code works, there is big chance that we will buy a commercial license of Emgu to use in our software.
Thanks!
EDIT
Based on the answer below, I've adapted my code and got it working like this:
Image<Bgr, float> src = new Image<Bgr, float>(@"C:\\test.png");
Matrix<float> samples = new Matrix<float>(src.Rows * src.Cols, 1, 3);
Matrix<int> finalClusters = new Matrix<int>(src.Rows * src.Cols, 1);
for (int y = 0; y < src.Rows; y++)
{
for (int x = 0; x < src.Cols; x++)
{
samples.Data[y + x * src.Rows, 0] = (float)src[y, x].Blue;
samples.Data[y + x * src.Rows, 1] = (float)src[y, x].Green;
samples.Data[y + x * src.Rows, 2] = (float)src[y, x].Red;
}
}
MCvTermCriteria term = new MCvTermCriteria(10000, 0.0001);
term.type = TERMCRIT.CV_TERMCRIT_ITER | TERMCRIT.CV_TERMCRIT_EPS;
int clusterCount = 3;
int attempts = 5;
Matrix<Single> centers = new Matrix<Single>(clusterCount, samples.Cols, 3);
CvInvoke.cvKMeans2(samples, clusterCount, finalClusters, term, attempts, IntPtr.Zero, KMeansInitType.PPCenters, centers, IntPtr.Zero);
Image<Bgr, Byte> new_image = new Image<Bgr, Byte>(src.Size);
for (int y = 0; y < src.Rows; y++)
{
for (int x = 0; x < src.Cols; x++)
{
int cluster_idx = finalClusters[y + x * src.Rows, 0];
MCvScalar sca1 = CvInvoke.cvGet2D(centers, cluster_idx, 0);
Bgr color = new Bgr(sca1.v0, sca1.v1, sca1.v2);
PointF p = new PointF(x, y);
new_image.Draw(new CircleF(p, 1.0f), color, 1);
}
}
CvInvoke.cvShowImage("clustered image", new_image);
CvInvoke.cvWaitKey(0);