使用虹軟人臉識別的開發過程當中遇到了轉換的問題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#的親,大家怎麼轉換的?