使用 EmguCV 3.1.0.1 从视频捕获中检测
Posted
技术标签:
【中文标题】使用 EmguCV 3.1.0.1 从视频捕获中检测【英文标题】:Detection from video capture with 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().MatchTemplate
或grabber.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:无法识别或不支持的数组类型
【问题讨论】:
【参考方案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();
我做了尽可能少的修复以使其正常工作。有很大的改进空间。您可以只创建一次 Capture
和 CascadeClassifier
而不是每个计时器滴答声,这将大大提高性能。
我还注意到你使用的 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 中执行得更好。在我的编辑中提到的小修改(创建一次Capture
和CascadeClassifier
)后,在我的 PC 上,该程序以全相机 fps 工作,消耗约 30% 的 CPU。在需要运行此程序的机器上是否有支持 OpenCL 的 GPU?如果是这样,也许您可以从 Emgu.CV 中的 OpenCL 中受益,如以下答案:***.com/a/32035912/6866539 您也可以尝试减小捕获的帧大小。
一些示例可在github.com/emgucv/emgucv/tree/master/Emgu.CV.Example获得以上是关于使用 EmguCV 3.1.0.1 从视频捕获中检测的主要内容,如果未能解决你的问题,请参考以下文章