使用EmguCV 3.1.0.1从视频捕获中进行检测

时间:2019-03-16 15:43:18

标签: c# winforms computer-vision emgucv face-detection

我正在尝试使用 EmguCV 3.1.0.1 库通过视频捕获实现人脸检测,该库由VS15的NuGet软件包在WinForms桌面应用程序中的PC Windows 10 64位OS上安装。

我的目标是从摄像机中检测和跟踪人脸并检测笑容,但是在下面的示例中,我将仅使用人脸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().MatchTemplategrabber.QueryFrame().Retrieve 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(); } } 一起使用,但另一个错误仍然与以下内容相同:

  

错误CS1061“垫子”不包含以下内容的定义:   'Resize'并且没有扩展方法'Resize'接受第一个参数   可以找到类型为'Mat'的(您是否缺少using指令或   程序集参考?)

我不确定我必须在哪里下载所需的dll-s(如果是丢失的原因?),以及我应该另外添加哪些dll-s。

尝试2:

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

var grayframe = imageFrame.Convert();行:

  

错误CS0411无法从用法中推断出方法'Mat.ToImage(bool)'的类型参数。尝试指定   明确键入参数。

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

  

错误CS0411无法从中推断方法'Image.Convert()'的类型参数   用法。尝试显式指定类型参数。

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(); } } 行:

  

错误CS1503参数2:无法从“ Emgu.CV.Structure.Bgr”转换   到“ TColor”

任何指南,建议或示例都会有所帮助

Michal Nawrocik 编辑,答案如下:

方法1:

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

未处理的异常:

  

System.AccessViolationException'发生在Emgu.CV.World.dll中   附加信息:尝试读取或写入受保护的内存。   这通常表明其他内存已损坏

方法2:

DbContext

例外:

  

Emgu.CV.Util.CvException”发生在Emgu.CV.World.dll中   信息:OpenCV:无法识别或不受支持的数组类型

1 个答案:

答案 0 :(得分:0)

正如您的错误消息所述,Mat类没有Resize()实例方法,一些快速的搜索显示您需要调用CvInvoke类的静态方法。 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();
}

我进行了尽可能少的修复,以使其正常运行。有相当大的改进空间。您只需创建一次CaptureCascadeClassifier即可(而不是每个计时器滴答),这将大大提高性能。

我还注意到您使用的Emgu软件包的版本相当旧,即使NuGet对此软件包没有显示较新的版本。原因是它已重命名为EMGU.CV。