Search code examples
c#image-processingblobemgucv

Dividing the blob in Emgu CV


I am using Emgu CV 2.4.2 and want to perform the following algorithm:

  1. Get the blob
  2. Set the ROI to speed up computation
  3. Get the pixel position of local minima from the blob
  4. Dividing the blob
  5. Draw the bounding rectangle into divided blob

I have done step 1-2 and extracted the blob by using BGStatModel. This is the result I've got :

Blob Picture

I want to get the pixel position of the local minima in vertical projection. After getting it, I want to divide the blob and draw the rectangle like this :

vertical projection Picture

I have tried to get get the pixel position of local minima by checking every pixel in the blob area but it makes my application runs very slow. Here's my code :

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;

Please help me how can I do step 2-5 in fastest way using Emgu CV. I would be highly appreciate if someone elaborate these three steps and some code also.

Thanks in advance, David


Solution

  • Ok so the question becomes more clear right now. Personally I agree with mmgp user in that the paper you are taking as a reference is not so good due to lack of generality. It has been coded for a very particular scenario and with some strong assumption on the controlled environment.

    I provide you with a method that compute vertical and horizontal projection and absolute maxima points as a good starting point

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

    If you are interested in finding local maxima as in the referenced paper you could start implementing a simple local maxima search such as ( code for horizontal projection) :

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

    This code comes from one of my youtube demos:

    Facial Features Demo using projections

    The rest of the steps are quite trivial and you can adjust it to your needs or follow some cross ratio thresholds as suggested in the paper.