Convert DLL IntPtr to byte[] to bitmap
Initially I thought to send an image from C++ opencv to C# required converting the opencv mat to an equivalent emgucv object. I have come to learn that it just requires unpacking the mat object to a type that C# can understand, which is uchar . . .apparently same as byte in C#
I have a C++ program that reads and an image and converts it to uchar (which is what a Mat object is anyway).
void DisplayImage::ReadImage()
{
cv::Mat image = cv::imread("2015-02-05.jpg");
image_rows = image.rows;
image_cols = image.cols;
image_type = image.type();
//image_uchar is data member of uchar*
image_uchar = MatToBytes(image);
}
uchar *DisplayImage::MatToBytes(cv::Mat image)
{
int image_size = image.total() * image.elemSize();
uchar * image_uchar = new uchar[image_size];
//image_uchar is a class data member of uchar*
std::memcpy(image_uchar,image.data,image_size * sizeof(uchar));
return image_uchar;
}
cv::Mat DisplayImage::BytesToMat()
{
cv::Mat img(image_rows,image_cols,image_type,image_uchar,cv::Mat::AUTO_STEP);
return img;
}
In the main program I assign a Mat object to the returned value from BytesToMat() and image looks fine.
My DLL looks like below
DisplayImage displayImage = DisplayImage();
extern "C" __declspec(dllexport) void SetImage()
{
displayImage.ReadImage();
}
extern "C" __declspec(dllexport) uchar *GetImage()
{
return displayImage.image_uchar;
}
Just by the way; I firstly started by assigning the pointer to uchar (in C++) with a simple text and displayed it C# by Marshaling returned IntPtr (from dll) to PtrToStringAnsi and it worked.
[DllImport(@".\WrapperForPlayer.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
unsafe public static extern IntPtr GetImage();
[DllImport(@".\WrapperForPlayer.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void SetImage();
static void Main(string[] args)
{
//byte[] image_byte = new byte[500];
SetImage();
IntPtr intPtr = GetImage();
unsafe
{
byte* image_byte = (byte*)intPtr;
}
Console.Read();
}
The only difference now is that the returned IntPtr contains address to image data which I want to turn to byte[] and then it will be easy to convert to Bitmap. How can I do that?
Hi,
Maybe a stupid question, is there a particular reason to not do the reading directly with EmguCV ?
imho, you can pass the IntPtr 'as is' to the Bitmap constructor.
but you got a memleak here:
uchar * image_uchar = new uchar[image_size];
@berak thanks for your response, the Bitmap constructor does not take IntPtr, it takes a System.Drawing.Image type. I tried to cast it but no luck @Eduardo I need to do this exercise because later I am going to read the image using emgucv and send it C++ for processing using opencv. Your next question might be to just use Emgucv since its equivalent to opencv and has most methods wrapped. Well I might just do that . . .port everything to C# Emgucv and compromise performance.
just try:
@berak I tried that, thanks! but nothing loaded in the PictureBox. I debugged the code and the value ptr changes to indicate that it received something. I've been doing some more reading. . .is it not because char * in C++ is unmanaged and cannot be interpreted by C#?