将位图从c#传递到c ++

我有一个基于opencv用C ++编写的图像处理函数。 在我的wpf应用程序中,我使用AForge库来访问网络摄像头并在UI上更新它。 这是处理新帧的function。

void UI_NewFrame(object sender, NewFrameEventArgs eventArgs) { try { System.Drawing.Bitmap bitmapFrame = (Bitmap)eventArgs.Frame.Clone(); MemoryStream ms = new MemoryStream(); bitmapFrame.Save(ms, ImageFormat.Bmp); ms.Seek(0, SeekOrigin.Begin); BitmapImage bitmapImageFrame = new BitmapImage(); bitmapImageFrame.BeginInit(); bitmapImageFrame.StreamSource = ms; bitmapImageFrame.EndInit(); bitmapImageFrame.Freeze(); CurrentFrame = bitmapImageFrame; } catch (Exception ex) { Debug.WriteLine("fatal::" + ex.Message); } } 

这是我的c ++代码:

 void FaceTracker(unsigned char* imageBuffer, int width, int height){ Mat frame(Size(width, height), CV_8UC4, imageBuffer, Mat::AUTO_STEP); Mat gray; cvtColor(frame, gray, COLOR_BGR2GRAY); //do more operations } 

我有两个选择。 我已经找到了一个代码,用于使用CopyPixels将数据从BitmapImage复制到IntPtr缓冲区。 我测试了它,它工作正常。 但我也读过我可以使用GetHBitmap简单地将句柄传递给Bitmap。 但这不适合我。 我读了这个如何将.NET位图传递给本机DLL? 但我不明白有关GetDIBits的部分。 我也尝试锁定位图像素并像这样传递:

 bitmapFrame.LockBits(new Rectangle(0, 0, bitmapFrame.Width, bitmapFrame.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb); NativeFunctions.FaceTracker(bitmapFrame.GetHbitmap(), bitmapFrame.Width, bitmapFrame.Height); 

并简单地传递HBitMap,既不起作用。 我总是得到一个exception,说明内存访问冲突。

取决于范围。 如果可以保证在其他地方不使用位图,则可以锁定图像缓冲区,然后将指针向下传递给C ++代码,然后将其解锁。

LockBits命令返回一个BitmapData类,该类在其Scan0属性中具有指向图像缓冲区的指针:

 BitmapData bmpData = bitmapFrame.LockBits(new Rectangle(0, 0, bitmapFrame.Width, bitmapFrame.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb); NativeFunctions.FaceTracker(bmpData.Scan0 , bitmapFrame.Width, bitmapFrame.Height); bitmapFrame.UnlockBits(bmpData); //Remember to unlock!!! 

您可以使用Bitmap.Save()方法将其转换为内存流,然后将其发送到C++ dll

 public Image ConvertImage(Image image) { MemoryStream convertedImageMemoryStream; using (MemoryStream sourceImageStream = new MemoryStream()) { image.Save(sourceImageStream, System.Drawing.Imaging.ImageFormat.Png); byte[] sourceImageData = sourceImageStream.ToArray(); // Send it to dll and get the IntPtr byte array from dll byte[] imageData = new byte[imInfo.size]; Marshal.Copy(imInfo.data, imageData, 0, imInfo.size); if (imInfo.data != IntPtr.Zero) AlgorithmCpp.ReleaseMemoryFromC(imInfo.data); convertedImageMemoryStream = new MemoryStream(imageData); } Image processed = new Bitmap(convertedImageMemoryStream); return processed; } 

然后,在C++ dll使用解码如cv::imdecode()方法来获取图像。

 DllExport void convertToGray(unsigned char* data, int dataLen) { vector inputImageBytes(data, data + dataLen); Mat image = imdecode(inputImageBytes, CV_LOAD_IMAGE_COLOR); Mat processed; cvtColor(image, processed, CV_BGR2GRAY); vector bytes; imencode(".png", processed, bytes); // .... 

这种方式有一些优点,例如, 1. fewer data to transfer 2. minimum implementation effort from both C# and C++ end. 3. Does not depend on the source image type eg. color or grayscale or any other color palate type. So it's very safe to use. 1. fewer data to transfer 2. minimum implementation effort from both C# and C++ end. 3. Does not depend on the source image type eg. color or grayscale or any other color palate type. So it's very safe to use.

唯一的问题是它是CPU密集型的,因为有编码和解码。

细节在这里 。

HBITMAP是位图的不透明句柄。 它不是像素缓冲区。 所以你的两段代码不匹配。

如果将HBITMAP传递给本机代码,则需要本机代码使用GDI函数来获取像素缓冲区并对其进行操作。 或者,您可以在托管代码中获取像素缓冲区并将其传递给本机代码。 无论你走哪条路,你都需要匹配互操作的两面。

我建议你使用EmguCV。 它是C#中openCV的包装器。 你不必担心DLL,lib等。我可以看到你想从webcamera追踪一张脸。 EmguCV让您可以捕获webcamera图像,然后以非常简单的方式跟踪人脸: http ://www.emgu.com/wiki/index.php/Face_detection此链接也可以帮助您。 请享用。