【问题标题】:Exception using cvKMeans2 in EmguCV在 EmguCV 中使用 cvKMeans2 的异常
【发布时间】:2013-02-03 08:28:18
【问题描述】:

我正在尝试使用 C# 在 Emgu CV 中转换 this snippet of code。我认为我将大部分内容转换为 EmguCV 中应有的内容,但 cvKMeans2 不断向我射击没有意义的异常。

这是我的代码:

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 );

我不断收到此异常:

附加信息:OpenCV:labels.isContinuous() && labels.type() == CV_32S && (labels.cols == 1 || labels.rows == 1) && labels.cols + labels.rows - 1 == data.rows

标签必须是 Single 类型没有意义,因为我需要在 cvKMeans2 之后将它用作循环中的索引。谁能帮我让这段代码工作?如果此代码有效,我们很有可能会购买 Emgu 的商业许可证以在我们的软件中使用。

谢谢!

编辑

根据下面的答案,我已经修改了我的代码并让它像这样工作:

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);

【问题讨论】:

    标签: c# .net opencv emgucv k-means


    【解决方案1】:

    我查看了example you refers to,并编写了一些适用于输入 rgb 图像的 vanilla 代码,在 rgb 空间中执行 kmeans。您可以调整一些参数以使其适应您的需求。

    以这个输入图像为例:

    EMGUCV 代码

    Bgr[] clusterColors = new Bgr[] {
            new Bgr(0,0,255),
            new Bgr(0, 255, 0),
            new Bgr(255, 100, 100),
            new Bgr(255,0,255),
            new Bgr(133,0,99),
            new Bgr(130,12,49),
            new Bgr(0, 255, 255)};
    
            Image<Bgr, float> src = new Image<Bgr, float>("fotobp.jpg");            
            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(100, 0.5);
            term.type = TERMCRIT.CV_TERMCRIT_ITER | TERMCRIT.CV_TERMCRIT_EPS;
    
            int clusterCount = 4;            
            int attempts = 5;
            Matrix<Single> centers = new Matrix<Single>(clusterCount, src.Rows * src.Cols);            
            CvInvoke.cvKMeans2(samples, clusterCount, finalClusters, term, attempts, IntPtr.Zero, KMeansInitType.PPCenters, IntPtr.Zero, 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++)
                {
                    PointF p = new PointF(x, y);
                    new_image.Draw(new CircleF(p, 1.0f), clusterColors[finalClusters[y + x * src.Rows, 0]], 1);
                }
            }
    
            CvInvoke.cvShowImage("clustered image", new_image);
            CvInvoke.cvWaitKey(0);
    

    结果(CLUSTER_NUM = 4)

    【讨论】:

    • 我会看看是否可以根据我的需要调整它。你知道为什么它需要一个“初始”颜色数组来工作吗? Kmeans 应该是一个无监督的算法,不是吗?
    • 我使用您的示例修改了我的代码并使其正常工作!非常感谢!有关完整答案,请参阅更新后的问题。
    猜你喜欢
    • 2013-04-16
    • 2012-07-07
    • 1970-01-01
    • 2017-12-01
    • 1970-01-01
    • 2016-07-14
    • 1970-01-01
    • 2021-03-08
    • 2019-05-05
    相关资源
    最近更新 更多