如何让 .NET 位图和 OpenCV 图像指向同一块内存?我知道我可以从一个复制到另一个,但我希望它们只指向相同的像素。
使用 Emgu 的解决方案的奖励积分。
以下只是一个理论,可能行不通,我对 opencv/emgucv 不是很有经验
两者System.Drawing.Bitmap
都有Emgu.CV.Image
构造函数scan0
作为参数。您可以为图像分配内存并将此指针传递给该构造函数。可以通过var ptr = Marshal.AllocHGlobal(stride*height)
(不要忘记释放 ofc)或通过分配足够大小的托管数组并获取其地址来分配内存。地址可以通过以下方式获取:
var array = new byte[stride*height];
var gch = GCHandle.Alloc(array, GCHandleType.Pinned);
var ptr = gch.AddrOfPinnedObject();
这也是“固定”数组,因此垃圾收集器不能移动它,地址也不会改变。
我们将使用这些构造函数:
Bitmap(int width, int height, int stride, PixelFormat format, IntPtr scan0);
Image<Bgr, Byte>(int width, int height, int stride, IntPtr scan0);
width
和height
论据是不言自明的。
format
对于位图是PixelFormat.Format24bppRgb
. stride
是单行图像的字节数,它也必须对齐(是 4 的倍数)。你可以这样得到它:
var stride = (width * 3);
var align = stride % 4;
if(align != 0) stride += 4 - align;
并且scan0
是指向我们的内存块的指针。
所以我建议在创建System.Drawing.Bitmap
和Emgu.CV.Image
使用这些构造函数之后会使用相同的内存块。如果不是,则意味着 opencv 或 Bitmap 或两者都复制提供的内存块和可能的解决方案(如果存在)绝对不值得努力。
从Emgu.CV
来源:
// Summary:
// The Get property provide a more efficient way to convert Image<Gray, Byte>,
// Image<Bgr, Byte> and Image<Bgra, Byte> into Bitmap such that the image data
// is shared with Bitmap. If you change the pixel value on the Bitmap, you change
// the pixel values on the Image object as well! For other types of image this
// property has the same effect as ToBitmap() Take extra caution not to use
// the Bitmap after the Image object is disposed The Set property convert the
// bitmap to this Image type.
public Bitmap Bitmap { get; set; }
所以基本上,对于特定类型的图像,您可以使用.Bitmap
CV 图像的属性,然后直接指向 CV 图像数据。
例子:
string filename;
// ... point filename to your file of choice ...
Image<Bgr, byte> cvImg = new Image<Bgr, byte>(filename);
Bitmap netBmp = cvImg.Bitmap;
不确定这是否有帮助,但您可以使用 .Ptr 从 Emgu 图像中获取指针
例如 IntPtr ip= img1.Ptr;