Обнаружение с захвата видео с EmguCV 3.1.0.1 - PullRequest
3 голосов
/ 16 марта 2019

Я пытаюсь реализовать функцию распознавания лиц с захватом видео с использованием библиотеки EmguCV 3.1.0.1 , устанавливаемой пакетами NuGet VS15 на 64-битную ОС Windows 10 ПК в настольном приложении WinForms.

Моя цель - получить обнаружение и отслеживание человеческого лица с видеокамеры и обнаружить улыбку, но для примеров ниже я буду использовать только лицо HaarCascade .xml с CascadeClassifier.

Итак,использование с DirectShowLib библиотекой для videoDevice из comboBox1_SelectedIndexChanged SelectedItem:

using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.UI;
using DirectShowLib;

Путь к HaarCascade xml-s:

    string facePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "dir\\haarcascade_frontalface_default.xml");

Таймер:

    private void timer1_Tick(object sender, EventArgs e)
    {
        detectFace();
    }

Попытка 1:

    private void detectFace()
    {
        CascadeClassifier face = new CascadeClassifier(facePath);
        Image<Bgr, Byte> currentframe = null;
        Image<Gray, byte> grayFrame = null;
        Capture grabber;
        grabber = new Capture(videoDevice);
        currentframe = grabber.QueryFrame().Resize(500, 320, Emgu.CV.CvEnum.INTER.CV_INTER_CUBIC);
        if (currentframe != null)
        {
            grayFrame = currentframe.Convert<Gray, Byte>();
            Rectangle[] faceDetected = face.DetectMultiScale(grayFrame, 1.1, 10, Size.Empty, Size.Empty);
            foreach (Rectangle faceFound in faceDetected)
            {
                currentframe.Draw(faceFound, new Bgr(Color.Red), 2);
            }
            pictureBox1.Image = currentframe.ToBitmap();
        }
    }

строка currentframe = grabber.QueryFrame().Resize(500, 320, Emgu.CV.CvEnum.INTER.CV_INTER_CUBIC); говорит:

Ошибка CS0234 Тип или имя пространства имен «INTER» не существует в пространстве имен «Emgu».CV.CvEnum '(вам не хватает ссылки на сборку?)

Вместо этого я попытался использовать currentframe = grabber.QueryFrame().Resize(500, 320, Emgu.CV.CvEnum.TemplateMatchingType.CcoeffNormed); с grabber.QueryFrame().MatchTemplate или grabber.QueryFrame().Retrieve, но другая ошибка по-прежнему сохраняетсястрока как:

Ошибка CS1061 'Mat' не содержит определения для 'Resize', и не найден метод расширения 'Resize', принимающий первый аргумент типа 'Mat' (вы пропускаетеиспользуя директиву или ссылку на сборку?)

Я не уверен, где я должен загрузить требуемые dll-ы (если это является причиной отсутствия?) и какие dll-ы именно я должен добавить к ссылкам дополнительно.

Попытка 2:

    private Capture _capture;
    private CascadeClassifier _cascadeClassifier;
    private void detectFace()
    {
        _capture = new Capture(videoDevice); 
        _cascadeClassifier = new CascadeClassifier(facePath);
        using (var imageFrame = _capture.QueryFrame().ToImage())
        {
            if (imageFrame != null)
            {
                var grayframe = imageFrame.Convert();
                var faces = _cascadeClassifier.DetectMultiScale(grayframe, 1.1, 10, Size.Empty);
                foreach (var face in faces)
                {
                    imageFrame.Draw(face, new Bgr(Color.Red), 3);
                }
            }
            pictureBox1.Image = imageFrame.ToBitmap();
        }
    }

line using (var imageFrame = _capture.QueryFrame().ToImage()):

Ошибка CS0411 Theаргументы типа для метода 'Mat.ToImage (bool)' не могут быть выведены из использования.Попробуйте явно указать аргументы типа.

line var grayframe = imageFrame.Convert();:

Ошибка CS0411 Аргументы типа для метода 'Image.Convert ()' не могут быть выведены из использования,Попробуйте явно указать аргументы типа.

line imageFrame.Draw(face, new Bgr(Color.Red), 3);:

Ошибка CS1503 Аргумент 2: невозможно преобразовать из Emgu.CV.Structure.Bgr в TColor'

Любое руководство, совет или пример будут полезны

Редактировать Михал Навроцик ответ ниже:

Метод 1:

private void detectFace()
        {
            CascadeClassifier face = new CascadeClassifier(facePath);
            Image<Bgr, Byte> currentframe = null;
            Image<Gray, byte> grayFrame = null;
            Capture grabber;
            grabber = new Capture(videoDevice);  
            var dstMat = new Mat();
            var frame = grabber.QueryFrame();
            CvInvoke.Resize(frame, dstMat, new Size(500, 320), interpolation: Emgu.CV.CvEnum.Inter.Cubic);
            currentframe = dstMat.ToImage<Bgr, byte>();
            if (currentframe != null)
            {
                grayFrame = currentframe.Convert<Gray, Byte>();
                Rectangle[] faceDetected = face.DetectMultiScale(grayFrame, 1.1, 10, Size.Empty, Size.Empty);
                foreach (Rectangle faceFound in faceDetected)
                {
                    currentframe.Draw(faceFound, new Bgr(Color.Red), 2);
                }
                pictureBox1.Image = currentframe.ToBitmap();
            }
        }

Необработанное исключение:

System.AccessViolationException 'произошло в Emgu.CV.World.dll Дополнительная информация: Попытка чтения или записи в защищенную память.Это часто указывает на то, что другая память повреждена

Метод 2:

 private Capture _capture;
    private CascadeClassifier _cascadeClassifier;
    private void detectFace()
    {
            _capture = new Capture(videoDevice);   
            _cascadeClassifier = new CascadeClassifier(facePath);
            using (var imageFrame = _capture.QueryFrame().ToImage<Bgr, byte>())
            {
                if (imageFrame != null)
                {
                    var grayframe = imageFrame.Convert<Gray, byte>();
                    var faces = _cascadeClassifier.DetectMultiScale(grayframe, 1.1, 10, Size.Empty);  
                    foreach (var face in faces)
                    {
                        imageFrame.Draw(face, new Bgr(Color.Red), 3);
                    }
                }
                pictureBox1.Image = imageFrame.ToBitmap();
            }
        }           
    }

исключение:

Emgu.CV.Util.CvException 'произошла в Emgu.CV.World.dll Дополнительная информация: OpenCV: нераспознанный или неподдерживаемый тип массива

1 Ответ

0 голосов
/ 16 марта 2019

Как говорится в вашем сообщении об ошибке, класс Mat не имеет метода экземпляра Resize(), а некоторые быстрые поиски в Google показывают, что вам необходимо вызвать статический метод класса CvInvoke. Значение enum для кубической интерполяции также было изменено разработчиками EmguCV в определенный момент времени.

Вот рабочий код, соответствующий вашей попытке 1:

var dstMat = new Mat();
var frame = grabber.QueryFrame();
CvInvoke.Resize(frame, dstMat, new Size(500, 320), interpolation: Emgu.CV.CvEnum.Inter.Cubic);
currentframe = dstMat.ToImage<Bgr, byte>();

Обратите внимание, что я сохраняю ссылки на Mat объекты, чтобы потом их удалить. using операторы также могут быть использованы вместо.

Ваши другие проблемы похожи. Не существует безпараметрических методов без параметров, таких как Mat.ToImage() или Image.Convert(). Они даже не имеют особого смысла, потому что вам нужно указать, в какой формат вы хотите конвертировать. В вашем случае вы можете использовать:

var imageFrame =_capture.QueryFrame().ToImage<Bgr, byte>();
var grayFrame = imageFrame.Convert<Gray, byte>();

Последняя ошибка в Image.Draw() вызове исчезнет.

Ваши проблемы предполагают, что вы могли бы выиграть от более внимательного изучения доступных метаданных классов, например, через обозреватель объектов, встроенный в Visual Studio.

Изменить:

В первом методе вы забыли вызвать Dispose() для некоторых объектов, и это вызвало исключение. Вот исправленный код, проверенный и работающий:

private void detectFace()
{
    CascadeClassifier face = new CascadeClassifier(facePath);
    Image<Bgr, Byte> currentframe = null;
    Image<Gray, byte> grayFrame = null;
    Capture grabber;
    grabber = new Capture(videoDevice);
    var dstMat = new Mat();
    var frame = grabber.QueryFrame();
    CvInvoke.Resize(frame, dstMat, new Size(500, 320), interpolation: Emgu.CV.CvEnum.Inter.Cubic);
    currentframe = dstMat.ToImage<Bgr, byte>();
    if (currentframe != null)
    {
        grayFrame = currentframe.Convert<Gray, Byte>();
        Rectangle[] faceDetected = face.DetectMultiScale(grayFrame, 1.1, 10, Size.Empty, Size.Empty);
        foreach (Rectangle faceFound in faceDetected)
        {
            currentframe.Draw(faceFound, new Bgr(Color.Red), 2);
        }

        var oldImage = panAndZoomPictureBox1.Image;
        panAndZoomPictureBox1.Image = currentframe.ToBitmap();
        if (oldImage != null)
        {
            oldImage.Dispose();
        }

        currentframe.Dispose();
        grayFrame.Dispose();
    }

    face.Dispose();

    grabber.Dispose();

    dstMat.Dispose();
    frame.Dispose();
}

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

Я также заметил, что используемая вами версия пакета Emgu довольно старая, хотя NuGet не показывает более новую версию для этого самого пакета. Причина в том, что он был переименован в EMGU.CV.

...