Как избавиться от ненужных строк с помощью emgu cv - PullRequest
1 голос
/ 21 марта 2020

Я пытаюсь определить контур капли воды, похожей на эллипс, с помощью 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);
                    }                   
            }
        }          
    }

результат пока:

enter image description here

Я думаю, что есть проблема с аппроксимацией. Как избавиться от внутренних линий и закрыть внешний контур?

1 Ответ

1 голос
/ 21 марта 2020

Мне может понадобиться больше информации, чтобы точно определить вашу проблему, но это может быть связано с вашим медианным размытием. Я бы посмотрел, достаточно ли размыто, чтобы EmguCV выглядело достаточно размытым, чтобы вы могли обнаружить границы. Другой метод, который вы можете использовать, - это Дилат. Попробуйте набрать номер вашего обнаружения края Canny и посмотрите, получите ли вы лучшие результаты.

EDIT

Вот код ниже

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

Первый Что вы делаете, это размытие изображения. enter image description here

Затем вы можете изменить изображение. enter image description here

Затем вы расширяете изображение, чтобы сделать конечные выходные контуры более однородными. enter image description here

Тогда вы просто найдете контуры. enter image description here

Я знаю, что окончательные контуры немного больше, чем капли воды, но это лучшее, что я мог придумать. Возможно, вы можете поиграть с некоторыми настройками и приведенным выше кодом, чтобы сделать результат немного чище.

...