在Emgu CV中划分blob

时间:2012-12-10 19:57:05

标签: c# image-processing blob emgucv

我正在使用Emgu CV 2.4.2并希望执行以下算法:

  1. 获取blob
  2. 设置投资回报率以加快计算
  3. 从blob获取局部最小值的像素位置
  4. 划分blob
  5. 将分界矩形绘制为分割的blob
  6. 我已经完成了步骤1-2并使用BGStatModel提取了blob。这是我得到的结果:

    Blob Picture

    我希望在垂直投影中获得局部最小值的像素位置。得到它之后,我想分割blob并像这样绘制矩形:

    vertical projection Picture

    我试图通过检查blob区域中的每个像素来获取局部最小值的像素位置,但它使我的应用程序运行非常慢。这是我的代码:

    Point minPix = new Point(0,0);
    
    //copy the foreground frame
    Image<Gray, Byte> foreFrame_copy = foreFrame.Copy();
    
    //find the contour
    Contour<Point> contours = foreFrame.FindContours(
        CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
        RETR_TYPE.CV_RETR_EXTERNAL);
    
    //looping every contour
    while (contours != null)
    {
        double PPixel = contours.Area;
        if (PPixel >= 1400)
        {
            //get the contour width
            WR = contours.BoundingRectangle.Width;
            //divide the contour using estimated pixel position
            Num = Convert.ToInt32(WR / 40);
    
        if (Num > 1)
        {
            //save the estimated pixel position for ROI in arraylist
            ArrayList XList = new ArrayList();
            for (int i = 1; i <= Num; i++)
            {
                int x = i * WR / Num;
                XList.Add(x);
            }
    
            //get the estimated pixel position 
            foreach (int pos in Xlist)
            {
                //roiWidth= 10px
                int roiWidth = (pos-5) + (pos+5);
                //roiHeight= 20px
                int roiHeight = 20;
    
                int pixValue = 0;
                //STEP 2: set the ROI to speed up computation
                foreFrame_copy.ROI = new Rectangle(contours.BoundingRectangle.X, contours.BoundingRectangle.Y, roiWidth, roiHeight);
                for (int i = (pos-5); i < roiWidth; i++)
                {
                    for (int j = (pos-5); j < (pos+5); j++)
                    {
                        pixValue = foreFrame_copy.Data[i, j, 0];
                        //find the white pixel
                        if (pixValue == 255) {
                            //find the position of minimum pixel
                            if (j < j-1) {
                            minPix.X = i;
                            minPix.Y = j;
                            }
                        }
    
                    }
                }
            }
    
        }
        //draw the red rectangle
        estimatedFrame.Draw(contours.BoundingRectangle, new Bgr(Color.Red), 1);
        contours = contours.HNext;
    }
    else
    {
        contours = contours.HNext;
    }
    }
    //show frame in framebox
    blobBox.Image = foreFrame_copy;
    estimatedBox.Image = estimatedFrame;
    

    请帮助我如何使用Emgu CV以最快的方式执行步骤2-5。如果有人详细说明这三个步骤和一些代码,我将非常感激。

    提前致谢, 大卫

1 个答案:

答案 0 :(得分:0)

好的,现在问题变得更清楚了。就个人而言,我同意mmgp用户的意见,因为缺乏一般性,你作为参考的论文并不是那么好。它已经针对一个非常特殊的场景进行了编码,并对受控环境做出了一些强有力的假设。

我为您提供了一种计算垂直和水平投影以及绝对最大值点作为良好起点的方法

   private void ComputeProjections(Image<Bgr, byte> inputImage)
    {                        
        Image<Gray, Byte> inputGrayImage = inputImage.Convert<Gray, Byte>();
        Matrix<float> imgMatHorizontal = new Matrix<float>(inputGrayImage.Height, 1, 1);
        Matrix<float> imgMatVertical = new Matrix<float>(1, inputGrayImage.Width, 1);

        inputGrayImage.Reduce<float>(imgMatHorizontal, REDUCE_DIMENSION.SINGLE_COL, REDUCE_TYPE.CV_REDUCE_AVG);
        inputGrayImage.Reduce<float>(imgMatVertical, REDUCE_DIMENSION.SINGLE_ROW, REDUCE_TYPE.CV_REDUCE_AVG);
        double minH, maxH, minV, maxV;
        Point minLocH, maxLocH, minLocV, maxLocV;
        imgMatHorizontal.MinMax(out minH, out maxH, out minLocH, out maxLocH);
        imgMatVertical.MinMax(out minV, out maxV, out minLocV, out maxLocV);

        Image<Gray, Byte> maskProvaH = new Image<Gray, byte>(new Size((int)(maxH - minH + 1), imgMatHorizontal.Rows));
        Image<Gray, Byte> maskProvaV = new Image<Gray, byte>(new Size(imgMatVertical.Cols, (int)(maxV - minV + 1)));

        for (int i = 0; i < imgMatHorizontal.Rows; i++)
            maskProvaH.Draw(new CircleF(new PointF((float)(imgMatHorizontal[i, 0] - minH), i), 1f), new Gray(255), 1);

        for (int i = 0; i < imgMatVertical.Cols; i++)
            maskProvaV.Draw(new CircleF(new PointF(i, (float)(imgMatVertical[0, i] - minV)), 1f), new Gray(255), 1);

        inputImage.Draw(new CircleF(new PointF(minLocV.X, minLocH.Y), 2), new Bgr(Color.Green), 1);
        //imageBoxProjected.Image = inputGrayImage;
        imageBoxHorizProj.Image = maskProvaH;
        //imageBoxVerticProj.Image = maskProvaV;

    }

如果您有兴趣找到参考文件中的局部最大值,您可以开始实现一个简单的局部最大值搜索,例如(水平投影的代码):

List<Point> localMaxima = new List<Point>();
        imgMatHorizontal.MinMax(out minH, out maxH, out minLocH, out maxLocH);

        Image<Gray, Byte> maskProvaH = new Image<Gray, byte>(new Size((int)(maxH - minH + 1), imgMatHorizontal.Rows));
        for (int i = 0; i < imgMatHorizontal.Rows; i++)
            maskProvaH.Draw(new CircleF(new PointF((float)(imgMatHorizontal[i, 0] - minH), i), 1f), new Gray(255), 1);

        //// Absolute Horizontal Projection Maxima Drawing
        //inputGrayImage.Draw(new Cross2DF(new PointF(maxLocH.X, maxLocH.Y), 2, 2), new Gray(255), 2);

        // Local maximas search
        for (int i = imgMatHorizontal.Rows - 2; i > 1; i--)
        {
            float prev = imgMatHorizontal[i + 1, 0];
            float curr = imgMatHorizontal[i, 0];
            float next = imgMatHorizontal[i - 1, 0];
            if (curr >= prev && curr >= next)
                localMaxima.Add(new Point((int)curr, i));
        }

此代码来自我的一个youtube演示:

Facial Features Demo using projections

其余步骤非常简单,您可以根据需要进行调整,或遵循文章中建议的一些交叉比率阈值。