Ask Your Question

Kamil's profile - activity

2015-04-10 01:51:37 -0600 received badge  Teacher (source)
2015-04-09 23:01:56 -0600 received badge  Necromancer (source)
2015-04-09 09:34:13 -0600 answered a question Convert DLL IntPtr to byte[] to bitmap

I have tested two ways that solve C# (Bitmap) and native C++ (cv::Mat) communication problem. All communication is based by C++ Dll which is used in C# by DllImport-ing (PInvoke). For image information storing I use two similar structures. C++ structure consists char* member for image data and C# structure consists InPtr for same data. C# structure is defined as [StructLayout(LayoutKind.Sequential)]. This "ImgBridge" is main condition for successful communication.

There are two functions for C# that convert C# (Bitmap) to C++ (cv::Mat) and vice versa via mentioned "ImgBridge".:

public static unsafe Bitmap ImgBridge2Bitmap(ImgBridge imgBridge)
{
    if (    (0 < imgBridge.mImgWidth)
        &&  (0 < imgBridge.mImgHeight))
    {
        PixelFormat pixelFormat = GetPixelFormat(imgBridge.mBitsPerPixel);

        if (pixelFormat != PixelFormat.Undefined)
        {
            Bitmap bitmap = new Bitmap(imgBridge.mImgWidth, imgBridge.mImgHeight, pixelFormat);

            if (pixelFormat == PixelFormat.Format8bppIndexed)
            {
                SetGrayscalePalette(bitmap);
            }                                            

            BitmapData bitmapData = bitmap.LockBits(
                 new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                 ImageLockMode.WriteOnly,
                 pixelFormat);

            CopyImgData(
                imgBridge.mBytesPerPixel,
                imgBridge.mImgWidth,
                imgBridge.mImgHeight,
                imgBridge.mBytesPerRow,
                imgBridge.mImgData,
                bitmapData.Stride,
                bitmapData.Scan0);

            bitmap.UnlockBits(bitmapData);

            return bitmap;
        }
    }

    return null;
}

_

public static unsafe ImgBridge Bitmap2ImgBridge(Bitmap bitmap)
{
    ImgBridge imgBridge = new ImgBridge();

    if (bitmap != null)
    {
        int BitsPerPixel = GetBitsPerPixel(bitmap.PixelFormat);

        if (BitsPerPixel != -1)
        {
            BitmapData bitmapData = bitmap.LockBits(
               new Rectangle(0, 0, bitmap.Width, bitmap.Height),
               ImageLockMode.ReadOnly,
               bitmap.PixelFormat);

            imgBridge.mImgWidth = bitmap.Width;
            imgBridge.mImgHeight = bitmap.Height;

            imgBridge.mChannelsCount = (BitsPerPixel / 8);
            imgBridge.mPixelsCount = (imgBridge.mImgWidth * imgBridge.mImgHeight);
            imgBridge.mBytesPerPixel = (BitsPerPixel / 8);
            imgBridge.mBitsPerPixel = BitsPerPixel;
            imgBridge.mBytesPerRow = (imgBridge.mBytesPerPixel * imgBridge.mImgWidth);

            imgBridge.mImgSize = (imgBridge.mPixelsCount * imgBridge.mBytesPerPixel);
            imgBridge.mImgData = Marshal.AllocHGlobal(imgBridge.mImgSize);

            CopyImgData(
                imgBridge.mBytesPerPixel,    
                bitmap.Width,
                bitmap.Height,    
                bitmapData.Stride,
                bitmapData.Scan0,    
                imgBridge.mBytesPerRow,
                imgBridge.mImgData);

            bitmap.UnlockBits(bitmapData);                              
        }
    }

    return imgBridge;
}

Both these function use CopyImgData function.:

public static unsafe void CopyImgData(int PixelSize, int ImgWidth, int ImgHeight,
    int SrcImgBytesPerRow, IntPtr SrcImgData, 
    int DstImgBytesPerRow, IntPtr DstImgData)
{
    if ((0 < PixelSize) && (0 < ImgWidth) && (0 < ImgHeight))
    {
        for (int h = 0; h < ImgHeight; h++)
        {
            byte* pSrcRow = ((byte*) SrcImgData + (h * SrcImgBytesPerRow));
            byte* pDstRow = ((byte*) DstImgData + (h * DstImgBytesPerRow));

            for (int w = 0; w < ImgWidth; w++)
            {
                for (int p = 0; p < PixelSize; p++)
                {
                    pDstRow[w * PixelSize + p] = pSrcRow[w * PixelSize + p];
                }
            }
        }
    }
}

At the beginning I had written that I have tested two ways. The second one inspired by GitHub/shimat/opencvsharp project https://github.com/shimat/opencvsharp... If you would like to try this one you will need to extract CopyMemory function https://github.com/shimat/opencvsharp... and implement it in your C# code. After this process you have to swap original CopyImgData function by

byte* pSrcImgData = (byte*) imgBridge.mImgData.ToPointer();
byte* pDstImgData = (byte*) bitmapData.Scan0.ToPointer();

int SrcStep = imgBridge.mBytesPerRow;
int DstStep = (((imgBridge.mImgWidth * imgBridge.mChannelsCount) + 3) / 4 * 4);

switch (pixelFormat)
{
    case PixelFormat.Format1bppIndexed:
    {
        // TODO

        break;
    }
    case PixelFormat.Format8bppIndexed:
    case PixelFormat.Format24bppRgb:
    {                                           
        for (int h = 0; h < imgBridge.mImgHeight; h++)
        {
            long SrcOffset = (h * SrcStep);
            long DstOffset = (h * DstStep);

            CopyMemory((pDstImgData + DstOffset), (pSrcImgData + SrcOffset), (uint) (imgBridge.mImgWidth * imgBridge.mChannelsCount));
        }                                     

        break;
    }
    default:
    {
        break;
    }
}

for ImgBridge2Bitmap and by this

int SrcStep = (((imgBridge.mImgWidth * imgBridge.mBytesPerPixel) + 3) / 4 * 4);
int DstStep = imgBridge.mBytesPerRow;                                

switch (bitmap.PixelFormat)
{
    case PixelFormat.Format1bppIndexed:
    {
        // TODO

        break;
    }
    case ...
(more)
2015-04-09 08:12:05 -0600 received badge  Editor (source)
2015-04-08 02:50:09 -0600 answered a question Convert DLL IntPtr to byte[] to bitmap

Hello to everyone,

have anybody solved this problem yet ? I am just trying to send my own structure (ImgBridge) with image data from native c++ to c# via DllImport-ing (PInvoke). On C++ side image data are stored in uchar* and on C# side they are stored in IntPtr (this image data, width, height etc. are members of ImgBridge structure). Communication works fine so that means if i send image from native c++ to C# I can create and display an bitmap or send it back to C++. Despite of this fact I have one problem. If I send rotated image (cv::warpAffine) from C++ to C# I can not reconstruct a valid Bitmap from this data. I hope it is not problem of rotating.. Image looks that it is snap by diagonal CPlusPlus_2_CSharp.jpg and I do not why. Image data are continuous (cv::Mat::isContinuous()) and I have suspicion on my converting function. Could you help me with this problem please? (I do not want to use Emgu, OpenCVSharp or any other) Thank You

This is a fragment of my code (C#) which convert communication structure to Bitmap.:

public static Bitmap ImgBridge2Bitmap(ImgBridge imgBridge)
{
   if (    (0 < imgBridge.mImgWidth)
       &&  (0 < imgBridge.mImgHeight))
   {
      PixelFormat pixelFormat = GetPixelFormat(imgBridge.mBitsPerPixel);

      if (pixelFormat != PixelFormat.Undefined)
      {
         Bitmap bitmap = new Bitmap(
            imgBridge.mImgWidth,
            imgBridge.mImgHeight,
            pixelFormat);

         if (bitmap.PixelFormat == PixelFormat.Format8bppIndexed)
         {
            SetGrayscalePalette(bitmap);
         }                                            

         BitmapData bitmapData = bitmap.LockBits(
            new Rectangle(0, 0, bitmap.Width, bitmap.Height),
            ImageLockMode.WriteOnly,
            bitmap.PixelFormat);

         byte[] RgbValues = new byte[imgBridge.mDataSize];

         Marshal.Copy(imgBridge.mData, RgbValues, 0, imgBridge.mDataSize);

         Marshal.Copy(RgbValues, 0, bitmapData.Scan0, imgBridge.mDataSize);                                                  

         bitmap.UnlockBits(bitmapData);                                                                                  
         return bitmap;
      }
   }   
   return null;
}