使用虹软人脸识别的开发过程当中遇到了转换的问题bash
由于不会用C#直接打开摄像头,就只能用第三方dll。一开始用Aforge,后来发现有个问题,关闭摄像头总是陷入等待,因此抛弃了。前一阵子开始用封装了OpenCV的Emgu,一路走来也是N声叹息。
网络
VideoCapture _VideoCapture;
Mat _Frame = new Mat();复制代码
2.初始化视频ide
_VideoCapture = new VideoCapture();//_VideoCapture.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameWidth, 1024); //设置宽度//_VideoCapture.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameHeight, 768);//设置高度_VideoCapture.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.Fps, 10);//设置每秒钟的帧数_VideoCapture.Start();_VideoCapture.ImageGrabbed += _VideoCapture_ImageGrabbed; //视频事件
测试
3.视频显示this
private void _VideoCapture_ImageGrabbed(object sender, EventArgs e){_VideoCapture.Retrieve(_Frame, 1);this.pictureBox1.Image = _Frame.Bitmap; //很神奇的pictureBox,竟然不在UI线程也能显示}
spa
4.获取当前帧
用于人脸比对,通常在另一个线程线程
Mat curFrame=_VideoCapture.QueryFrame();
code
一切十分完美,就是_Frame.Bitmap彷佛没有Dispose(后来发现Mat的地址是不变,不会发生内存泄漏),但运行起来也没问题。
orm
Mat curFrame=_VideoCapture.QueryFrame();
Bitmap bitmap=curFrame.Bitmap;视频
var bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
int width = (bitmap.Width + 3) / 4 * 4;
var bytesCount = bmpData.Height * width * 3;
IntPtr pImageData = Marshal.AllocCoTaskMem(bytesCount);
if (width == bitmap.Width)
CopyMemory(pImageData, bmpData.Scan0, bytesCount);
else
for (int i = 0; i < bitmap.Width; i++)
CopyMemory(IntPtr.Add(pImageData, i * width * 3), IntPtr.Add(bmpData.Scan0, i * bmpData.Stride), bmpData.Stride);
bitmap.UnlockBits(bmpData);
获得了ArcFace所需的图片数据pImageData,测试一下挺好,能运行。时间一长,报错了:“试读取或写入受保护的内存。这一般指示其余内存已损坏。
估计人脸识别的线程和显示视频的线程冲突了,查看了Emgu的源代码,发现QueryFrame就是封装了Retrieve。
好吧,克隆一下,Bitmap bitmap=(Bitmap)curFrame.Bitmap.Clone();问题依旧!查看地址发现Clone没卵用!
IntPtr _PImageData;
int _ImageWidth,_ImageHeight,_ImageSize;
2.初始化
_ImageWidth=_VideoCapture.Width;
_ImageHeight=_VideoCapture.Height;
_ImageSize = _VideoCapture.Width * _VideoCapture.Height * 3;_PImageData = Marshal.AllocCoTaskMem(_ImageSize);
3.转换
Marshal.Copy(_Frame.GetData(), 0, _PImageData, _ImageSize);
ASFDetectFaces(pEngine,_ImageWidth, _ImageHeight,513,_PImageData, out var faceInfo);...
一切变得如此简单,长叹一声!
videoCapture = new VideoCapture("string filename");
如某tplink的IP摄像头的filename是这样的"rtsp://admin:admin@192.168.0.159/stream1",格式是rstp://用户名:密码@ip地址/...各位C#的亲,大家怎么转换的?