【问题标题】:Detection from video capture with EmguCV 3.1.0.1使用 EmguCV 3.1.0.1 从视频捕获中检测
【发布时间】:2019-08-07 11:25:05
【问题描述】:

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

我的目标是从摄像机中检测和跟踪人脸并检测微笑,但对于下面的示例,我将仅使用面部 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 一起使用,但另一个错误仍然在同一行:

错误 CS1061 'Mat' 不包含定义 “调整大小”并且没有扩展方法“调整大小”接受第一个参数 可以找到“Mat”类型的(您是否缺少 using 指令或 汇编参考?)

我不确定我必须在哪里下载所需的 dll-s(如果它是丢失的原因?)以及我应该将哪些 dll-s 添加到引用中。

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

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

错误 CS0411 无法从用法推断方法“Mat.ToImage(bool)”的类型参数。尝试指定 显式输入参数。

线var grayframe = imageFrame.Convert();:

错误 CS0411 方法“Image.Convert()”的类型参数无法从 用法。尝试明确指定类型参数。

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

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

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

Michal Nawrocik 编辑回答如下:

方法一:

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

未处理的异常:

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

方法二:

 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:无法识别或不支持的数组类型

【问题讨论】:

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


    【解决方案1】:

    正如您的错误消息所说,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。

    【讨论】:

    • 您好,感谢您的反馈。我已经根据您上面的回答编辑了代码,但是两种方法都会引发未处理的异常,第一种是:System.AccessViolationException' occurred in Emgu.CV.World.dll Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt,第二种方法:Emgu.CV.Util.CvException' occurred in Emgu.CV.World.dll Additional information: OpenCV: Unrecognized or unsupported array type
    • @viktor80 我编辑了我的答案并添加了您的第一个方法中缺少的代码。
    • 我确信这个解决方案应该可以工作,但至少在我这边似乎有问题。图像移动不顺畅,而是挂起,并且跟踪矩形 faceFound.X 或 Y 的坐标取值,冻结和移动之间的时间间隔很大。我使用了更老的 EmguCV 2,它具有等效的代码,并且工作正常,对我来说缺少旧的库版本是新的 haarcascade xml-s 不适合它。在哪里可以下载最新版本的 EMGU.CV 并找到有用的示例?
    • EMGU.CV 在 NuGet 上可用,它只是一个不同的包。我很确定有一些方法可以使您的代码在新版本中比在 2.x 中执行得更好。在我的编辑中提到的小修改(创建一次CaptureCascadeClassifier)后,在我的 PC 上,该程序以全相机 fps 工作,消耗约 30% 的 CPU。在需要运行此程序的机器上是否有支持 OpenCL 的 GPU?如果是这样,也许您可​​以从 Emgu.CV 中的 OpenCL 中受益,如以下答案:stackoverflow.com/a/32035912/6866539 您也可以尝试减小捕获的帧大小。
    猜你喜欢
    • 2018-10-15
    • 2012-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多