我正在尝试使用 EmguCV 3.1.0.1 库通过视频捕获实现人脸检测,该库由 VS15 的 NuGet 包安装在 PC Windows 10 64 位操作系统的 WinForms 桌面应用程序中。
我的目标是从摄像机检测和跟踪人脸并检测微笑,但对于下面的示例,我将仅使用人脸 HaarCascade
.xml 和 CascadeClassifier
。
因此,我将 DirectShowLib
库用于 comboBox1_SelectedIndexChanged
SelectedItem
的 videoDevice
:
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);
说:
Error CS0234 The type or namespace name 'INTER' does not exist in the namespace 'Emgu.CV.CvEnum' (are you missing an assembly reference?)
相反,我尝试使用 currentframe = grabber.QueryFrame().Resize(500, 320, Emgu.CV.CvEnum.TemplateMatchingType.CcoeffNormed);
,与 grabber.QueryFrame ().MatchTemplate
或 grabber.QueryFrame().Retrieve
,但另一个错误仍然在同一行:
Error CS1061 'Mat' does not contain a definition for 'Resize' and no extension method 'Resize' accepting a first argument of type 'Mat' could be found (are you missing a using directive or an assembly reference?)
我不确定我必须在哪里下载所需的 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())
:
Error CS0411 The type arguments for method 'Mat.ToImage(bool)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
行 var grayframe = imageFrame.Convert();
:
Error CS0411 The type arguments for method 'Image.Convert()' cannot be inferred from the usage. Try specifying the type arguments explicitly.
行 imageFrame.Draw(face, new Bgr(Color.Red), 3);
:
Error CS1503 Argument 2: cannot convert from 'Emgu.CV.Structure.Bgr' to '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();
}
}
未处理的异常:
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
方法二:
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();
}
}
}
异常(exception):
Emgu.CV.Util.CvException' occurred in Emgu.CV.World.dll Additional information: OpenCV: Unrecognized or unsupported array type
最佳答案
如您的错误消息所述,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。
关于c# - 使用 EmguCV 3.1.0.1 从视频捕获中检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55198568/