元帅的基本定义是:
可见,Marshal主要是用来操作非托管内存的。此类中定义的大多数方法是提供给开发人员的托管和非托管编程模型之间的桥梁。例如, StringToHGlobalAnsi 方法将ANSI字符从指定的字符串(在托管堆中)复制到非托管堆中的缓冲区。该方法还分配适当大小的目标堆。
System.Runtime。InteropServices Marshal所在的命名空间主要用于跨平台调用。
我们今天主要分析,大恒相机中的元帅用法
void __UpdateImageData(IBaseData objIBaseData)
{
try
{
GX_VALID_BIT_LIST emValidBits = GX_VALID_BIT_LIST.GX_BIT_0_7;
if (null != objIBaseData)
{
emValidBits = __GetBestValudBit(objIBaseData.GetPixelFormat());
if (GX_FRAME_STATUS_LIST.GX_FRAME_STATUS_SUCCESS == objIBaseData.GetStatus())
{
if (m_bIsColor)
{
IntPtr pBufferColor = objIBaseData.ConvertToRGB24(emValidBits, GX_BAYER_CONVERT_TYPE_LIST.GX_RAW2RGB_NEIGHBOUR, true);
Marshal.Copy(pBufferColor, m_byColorBuffer, 0, m_nWidth * m_nHeigh * 3);
}
else
{
IntPtr pBufferMono = IntPtr.Zero;
if (__IsPixelFormat8(objIBaseData.GetPixelFormat()))
{
pBufferMono = objIBaseData.GetBuffer();
}
else
{
pBufferMono = objIBaseData.ConvertToRaw8(emValidBits);
}
Marshal.Copy(pBufferMono, m_byMonoBuffer, 0, m_nWidth * m_nHeigh);
}
}
}
}
catch (Exception)
{
}
}
相机拍到的图像格式为:IBaseData,如下
#region 程序集 GxIAPINET.dll, v1.0.6417.17503
// C:\Program Files\Daheng Imavision\MER-Series\Samples\CSharp SDK\x64\DoNET\GxIAPINET.dll
#endregion
using System;
namespace GxIAPINET
{
public interface IBaseData
{
IntPtr ConvertToRaw8(GX_VALID_BIT_LIST emValidBits);
IntPtr ConvertToRGB24(GX_VALID_BIT_LIST emValidBits, GX_BAYER_CONVERT_TYPE_LIST emConvertType, bool bFlip);
IntPtr GetBuffer();
ulong GetFrameID();
ulong GetHeight();
ulong GetPayloadSize();
GX_PIXEL_FORMAT_ENTRY GetPixelFormat();
GX_FRAME_STATUS_LIST GetStatus();
ulong GetTimeStamp();
ulong GetWidth();
IntPtr ImageProcess(IImageProcessConfig objCfg);
}
}
其中GetBuffer()就是拿到图像在内存中的地址,其他几个函数为功能性函数,不再多作解释。
首先默认图像格式emValidBits是0-7位表示的,
其次如果图像存在(图像不为空),就获取图像在内存中的真实格式:
emValidBits = __GetBestValudBit(objIBaseData.GetPixelFormat());
接下来,如果图像状态为success,即如果拍照成功,就判断,图像色彩是RGB还是其他灰度等,并做相应的处理。图像色彩由isRGB判断,具体函数在init()中,如下
void Init()
{
m_strSN = m_objIGXDevice.GetDeviceInfo().GetSN();
string strValue = null;
if (null != m_objIGXDevice)
{
m_nWidth = (int)m_objIGXDevice.GetRemoteFeatureControl().GetIntFeature("Width").GetValue();
m_nHeigh = (int)m_objIGXDevice.GetRemoteFeatureControl().GetIntFeature("Height").GetValue();
m_byMonoBuffer = new byte[m_nWidth * m_nHeigh];
m_byColorBuffer = new byte[m_nWidth * m_nHeigh * 3];
if (m_objIGXDevice.GetRemoteFeatureControl().IsImplemented("PixelColorFilter"))
{
strValue = m_objIGXDevice.GetRemoteFeatureControl().GetEnumFeature("PixelColorFilter").GetValue();
if ("None" != strValue)
{
m_bIsColor = true;
}
}
}
if (null != m_pic_ShowImage)
{
Bitmap bitmap = m_pic_ShowImage.Image as Bitmap;
m_pic_ShowImage.Image = m_bitmap;
if (bitmap != null)
{
bitmap.Dispose();
}
}
}
可以看到图像色彩是通过相机的配置属性读取
strValue = m_objIGXDevice.GetRemoteFeatureControl()。GetEnumFeature(“PixelColorFilter”)。GetValue();
接下来,针对不同的图像色彩做不同的图像转换处理
对于彩色图像,操作如下
IntPtr pBufferColor = objIBaseData.ConvertToRGB24(emValidBits, GX_BAYER_CONVERT_TYPE_LIST.GX_RAW2RGB_NEIGHBOUR, true);
Marshal.Copy(pBufferColor, m_byColorBuffer, 0, m_nWidth * m_nHeigh * 3);
可以看到,Marshal.Copy的作用是把非托管内存中的图像数据,复制到了托管内存中 即数组中,并且规定了所占用的堆栈大小。
m_bycolorBuffer的申明如下:
byte[] m_byMonoBuffer = null; ///<黑白相机buffer
byte[] m_byColorBuffer = null; ///<彩色相机buffer
对于灰度图像,操作如下:
IntPtr pBufferMono = IntPtr.Zero;
if (__IsPixelFormat8(objIBaseData.GetPixelFormat()))
{
pBufferMono = objIBaseData.GetBuffer();
}
else
{
pBufferMono = objIBaseData.ConvertToRaw8(emValidBits);
}
Marshal.Copy(pBufferMono, m_byMonoBuffer, 0, m_nWidth * m_nHeigh);
Marsharl作用一样,InPtr.Zero用于初始化
随后显示出来即可。
那么我们为什么要用到非托管代码呢?为什么要转到非托管内存上呢?
1.其实整个.NET项目都是运行在.NET Framework上的托管代码,这个道理和JAVA虚拟机的机制是类似的。
最简单的说呢,受托管的代码不能直接写内存,是安全的,而非托管代码是非安全代码,可以使用指针操作内存。
一般的项目使用托管代码都行了,也就是说在程序里面不需要用到非安全代码。
对于一些对速度要求高的部分功能可以考虑使用非安全代码,使用指针等读写内存,而对于真个项目来说还是受托管的安全代码。
2.C++库中有些函数通过指针来使用,在C#中可能需要转到托管内存中,来通过GC的释放达到内存有效利用。