1.问题或需求描述 C# Bitmap 与 C++ opencv Mat 之间相互转换 2.解决方法或原理: 本文场景:使用C# 调用 由C++ 封装的基于opencv的视觉算法库,演示如何在两者之间互传图像数据。 CxxDll.cpp 部
1.问题或需求描述
C# Bitmap 与 C++ opencv Mat 之间相互转换
2.解决方法或原理:
本文场景:使用C# 调用 由C++ 封装的基于opencv的视觉算法库,演示如何在两者之间互传图像数据。
CxxDll.cpp 部分源码:
DLL_API void WINAPI ColorToGray(
IN unsigned char* img_src_data, IN int img_src_w, IN int img_src_h, IN int img_src_ch, int img_src_stride,
OUT unsigned char* img_dst_data, OUT int& img_dst_w, OUT int& img_dst_h, OUT int& img_dst_ch, OUT int& img_dst_stride
)
{
img_dst_w = 0;
img_dst_h = 0;
img_dst_ch = 0;
img_dst_stride = 0;
if (img_src_ch != 3) throw std::exception("error: img_src must be 3 channels");
Mat img_src = Mat(img_src_h, img_src_w, CV_8UC3, img_src_data, img_src_stride).clone();
Mat img_dst;
cvtColor(img_src, img_dst, COLOR_BGR2GRAY);
if (img_dst.empty() == false)
{
img_dst_w = img_dst.cols;
img_dst_h = img_dst.rows;
img_dst_ch = img_dst.channels();
img_dst_stride = 4 * ((img_dst_w * img_dst_ch + 3) / 4);
if ((img_dst_stride == img_dst.step.p[0]))
memcpy(img_dst_data, img_dst.data, img_dst.total());
else
{
uchar * img_dst_data_temp = new uchar[img_dst.cols * img_dst_stride];
uchar* img_dst_ptr = img_dst.ptr();
int idx = 0;
int offset = 0;
int offset_count = img_dst_stride - img_dst.step.p[0];
for (int y = 0; y < img_dst.rows; y++)
{
for (int x = 0; x < img_dst.step.p[0]; x++)
{
idx = y * img_dst.step.p[0] + x;
img_dst_data_temp[idx + offset] = img_dst_ptr[idx];
}
for (int x = 0; x < offset_count; x++)
{
img_dst_data_temp[idx + (++offset)] = 0;
}
}
memcpy(img_dst_data, img_dst_data_temp, img_dst.rows * img_dst_stride);
delete[] img_dst_data_temp;
}
}
}
Test.cs 部分源码:
[DllImport("CxxDll.dll", EntryPoint = "ColorToGray")]
public static extern void ColorToGray(
[In] IntPtr img_src_data, [In] int img_src_w, [In] int img_src_h, [In] int img_src_ch, [In] int img_src_stride,
[Out] IntPtr img_dst_data, ref int img_dst_w, ref int img_dst_h, ref int img_dst_ch, ref int img_dst_stride
);
private void Test()
{
Bitmap img_src;
BitmapData img_src_data;
IntPtr img_dst_data;
int img_dst_w = 0;
int img_dst_h = 0;
int img_dst_ch = 0;
int img_dst_stride = 0;
Func<int, PixelFormat, int> GetStride = (width, format) =>
{
int bitsPerPixel = System.Drawing.Image.GetPixelFormatSize(format);
int bytesPerPixel = (bitsPerPixel + 7) / 8;
int stride = 4 * ((width * bytesPerPixel + 3) / 4);
return stride;
};
img_src = (Bitmap)Bitmap.FromFile("C:\\Users\\Administrator\\Desktop\\IMG\\img_001.png");
pictureBoxSrc.Image = img_src;
if (img_src.PixelFormat != PixelFormat.Format24bppRgb)
img_src = img_src.Clone(new Rectangle(0, 0, img_src.Width, img_src.Height), PixelFormat.Format24bppRgb);
img_src_data = img_src.LockBits(new Rectangle(0, 0, img_src.Width, img_src.Height), ImageLockMode.ReadOnly, img_src.PixelFormat);
img_dst_data = Marshal.AllocHGlobal((Int32)(img_src_data.Height * GetStride(img_src_data.Width, PixelFormat.Format8bppIndexed)));
try
{
ColorToGray(
img_src_data.Scan0,
img_src_data.Width,
img_src_data.Height,
System.Drawing.Image.GetPixelFormatSize(img_src_data.PixelFormat) / 8,
img_src_data.Stride,
img_dst_data,
ref img_dst_w,
ref img_dst_h,
ref img_dst_ch,
ref img_dst_stride
);
//非托管数据源
Bitmap bmp = new Bitmap(img_dst_w, img_dst_h, img_dst_stride, PixelFormat.Format8bppIndexed, img_dst_data);
ColorPalette cp = bmp.Palette;
for (int i = 0; i < 256; i++) cp.Entries[i] = Color.FromArgb(i, i, i);
bmp.Palette = cp;
//使用托管数据源
Bitmap img_dst = new Bitmap(bmp.Width, bmp.Height);
using (Graphics g = Graphics.FromImage(img_dst))
{
g.Clear(Color.Black);
Rectangle imageRectangle = new Rectangle(0, 0, bmp.Width, bmp.Height);
g.DrawImage(bmp, imageRectangle, imageRectangle, GraphicsUnit.Pixel);
}
pictureBoxDst.Image = img_dst;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
img_src.UnlockBits(img_src_data);
if (img_dst_data != IntPtr.Zero)
{
Marshal.Release(img_dst_data);
Marshal.FreeHGlobal(img_dst_data);
}
}
}
3.备注说明
1>Bitmap data stride: width * channel 并补齐至最接近的 4 的整倍数,为什么是4的整数,请参考下面内容。
注意Bitmap data 和 Mat.data 是有区别的,前者包含像素数据和填充,而后者只包含像素数据。
2>为快速理解内容,本文只展示核心代码,并聚拢了代码,部分代码专为本文教学而改,可能包含错误,请读者辨识性阅览。
4.结果演示: