如何使用 emgu cv 去除不必要的行

How to get rid of unnecessary lines with emgu cv

我正在尝试使用 Emgu CV 检测椭圆形水滴的轮廓。我写了轮廓检测的代码:

    public List<int> GetDiameters()
    {
        string inputFile = @"path.jpg";

        Image<Bgr, byte> imageInput = new Image<Bgr, byte>(inputFile);

        Image<Gray, byte> grayImage = imageInput.Convert<Gray, byte>();

        Image<Gray, byte> bluredImage = grayImage;
        CvInvoke.MedianBlur(grayImage, bluredImage, 9);

        Image<Gray, byte> edgedImage = bluredImage;
        CvInvoke.Canny(bluredImage, edgedImage, 50, 5);

        Image<Gray, byte> closedImage = edgedImage;           
        Mat kernel = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Ellipse, new System.Drawing.Size { Height = 100, Width = 250}, new System.Drawing.Point(-1, -1)); 
        CvInvoke.MorphologyEx(edgedImage, closedImage, Emgu.CV.CvEnum.MorphOp.Close, kernel, new System.Drawing.Point(-1, -1), 0, Emgu.CV.CvEnum.BorderType.Replicate, new MCvScalar());
       System.Drawing.Point(100, 250), 10000, Emgu.CV.CvEnum.BorderType.Default, new MCvScalar()

        Image<Gray, byte> contoursImage = closedImage;
        Image<Bgr, byte> imageOut = imageInput;
        VectorOfVectorOfPoint rescontours1 = new VectorOfVectorOfPoint();
        using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
        {
            CvInvoke.FindContours(contoursImage, contours, null, Emgu.CV.CvEnum.RetrType.List,
                Emgu.CV.CvEnum.ChainApproxMethod.LinkRuns);
            MCvScalar color = new MCvScalar(0, 0, 255);

            int count = contours.Size;
            for (int i = 0; i < count; i++)
            {
                using (VectorOfPoint contour = contours[i])
                    using (VectorOfPoint approxContour = new VectorOfPoint())
                    {
                        CvInvoke.ApproxPolyDP(contour, approxContour,
                            0.01 * CvInvoke.ArcLength(contour, true), true);

                        var area = CvInvoke.ContourArea(contour);

                    if (area > 0 && approxContour.Size > 10)
                    {
                        rescontours1.Push(approxContour);
                    }

                        CvInvoke.DrawContours(imageOut, rescontours1, -1, color, 2);
                    }                   
            }
        }          
    }

到目前为止的结果:

我认为近似有问题。如何去除内部线条和关闭外部轮廓?

我可能需要更多信息才能准确查明您的问题,但这可能与您的中值模糊有关。我会看看你是否模糊得足以让 EmguCV 的东西模糊到足以让你可以进行边缘检测。您可以使用的另一种方法是扩张。尝试 Dialating 您的 Canny 边缘检测,看看是否能获得更好的结果。

编辑

下面是代码

    public List<int> GetDiameters()
    {
        //List to hold output diameters
        List<int> diametors = new List<int>();

        //File path to where the image is located
        string inputFile = @"C:\Users\jones\Desktop\Image Folder\water.JPG";

        //Read in the image and store it as a mat object
        Mat img = CvInvoke.Imread(inputFile, Emgu.CV.CvEnum.ImreadModes.AnyColor);

        //Mat object that will hold the output of the gaussian blur
        Mat gaussianBlur = new Mat();

        //Blur the image
        CvInvoke.GaussianBlur(img, gaussianBlur, new System.Drawing.Size(21, 21), 20, 20, Emgu.CV.CvEnum.BorderType.Default);

        //Mat object that will hold the output of the canny
        Mat canny = new Mat();

        //Canny the image
        CvInvoke.Canny(gaussianBlur, canny, 40, 40);

        //Mat object that will hold the output of the dilate
        Mat dilate = new Mat();

        //Dilate the canny image
        CvInvoke.Dilate(canny, dilate, null, new System.Drawing.Point(-1, -1), 6, Emgu.CV.CvEnum.BorderType.Default, new MCvScalar(0, 0, 0));

        //Vector that will hold all found contours
        VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();

        //Find the contours and draw them on the image
        CvInvoke.FindContours(dilate, contours, null, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);
        CvInvoke.DrawContours(img, contours, -1, new MCvScalar(255, 0, 0), 5, Emgu.CV.CvEnum.LineType.FourConnected);

        //Variables to hold relevent info on what is the biggest contour
        int biggest = 0;
        int index = 0;

        //Find the biggest contour
        for (int i = 0; i < contours.Size; i++)
        {
            if (contours.Size > biggest)
            {
                biggest = contours.Size;
                index = i;
            }
        }

        //Once all contours have been looped over, add the biggest contour's index to the list
        diametors.Add(index);

        //Return the list
        return diametors;
    }

您要做的第一件事是模糊图像。

然后你就可以看到图像了。

然后将图像放大,使最终输出的轮廓更均匀。

然后你只需要找到轮廓。

我知道最终的轮廓比水滴大一点,但这是我能想到的最好的了。您可能 fiddle 使用上面的一些设置和代码来使结果更清晰一些。