Почему мне не удалось преобразовать IntPtr в байт []? - PullRequest
0 голосов
/ 05 марта 2020

Я работаю над проектом по созданию DLL для вывода модели из C#.

В процессе вывода мы выполняем предварительную обработку, вывод и последующую обработку для завершения работы. , Вначале я записываю все эти процессы в одну DLL, и она отлично работает. Но что касается понятия «модульность», мой начальник попросил меня разделить этот процесс на три разные библиотеки DLL.

Итак, идеальный поток данных должен быть таким:

                        C#          ||        DLL    (return cv::Mat*)
pre-processing  ||  image->byte[] -----> Mat (...) -> new Mat(result)
                                                            ↓
============================================================↓==============
                        Intptr   <---------------------------
==========================↓================================================
inference       ||      byte[]    -----> Mat (...) -> new Mat(result)
                                                            ↓
============================================================↓==============
                        Intptr   <---------------------------
==========================↓===============================================
post-processing ||      byte[]    -----> Mat (...) -> new Mat(result)

Но во время процесс передачи cv :: Mat * в C# и передачи байта [], преобразованного из Intptr, входные данные (cv :: Mat) не совпадают , как это было показано из исходного cv2.Mat (IntPtr). И вот код, который я пишу для этого (он упрощен ...):

//C++(DLL)
//pre-processing DLL ---------------------------------------------------
//dll_pre.h
extern "C" LIB_API cv::Mat* img_padding(unsigned char* img_pointer, int img_H, int img_W, int* len);

//dll_pre.cpp
LIB_API cv::Mat* img_padding(unsigned char* img_pointer, int img_H, int img_W)
{
    cv::Mat input_pic = cv::Mat(img_H, img_W, CV_8UC(pic_ch), img_pointer);

    //do something...

    *len = input_pic.total() * input_pic.elemSize();

    return new cv::Mat(input_pic);
}
// ---------------------------------------------------------------------

//inference DLL --------------------------------------------------------
//dll_inf.h
extern "C" LIB_API void dll_inference(unsigned char* img_pointer, int img_H, int img_W);

//dll_inf.cpp'
LIB_API void dll_inference(unsigned char* img_pointer, int img_H, int img_W)
{
    cv::Mat input_pic = cv::Mat(img_H, img_W, CV_8UC(pic_ch), img_pointer);

    cv::imwrite("dll_pic.png", input_pic)

    //do something...
}
// ---------------------------------------------------------------------
//C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing; //Bitmap
using System.Drawing.Imaging;
using System.IO; //Memory Stream
using System.Runtime.InteropServices; //Marshal
using System.Diagnostics;//Timer
using OpenCvSharp;


namespace Test_DLL_Console
{
    class Program
    {
        [DllImport(@"dll_pre.dll")]
        private static extern IntPtr img_padding(byte[] img, int img_H, int img_W, out int rt_len);
        [DllImport(@"dll_inf.dll")]
        private static extern void dll_inference(byte[] img, int img_H, int img_W);

        public static byte[] GetRGBValues(Bitmap bmp, out int bmp_w)
        {
            // Lock the bitmap's bits. 
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData =
             bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);

            // Get the address of the first line.
            IntPtr ptr = bmpData.Scan0;

            // Declare an array to hold the bytes of the bitmap.
            int bytes = bmpData.Stride * bmp.Height;
            byte[] rgbValues = new byte[bytes];

            Console.WriteLine($"bytes->{bytes}");
            // Copy the RGB values into the array.
            System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); bmp.UnlockBits(bmpData);
            bmp_w = bmpData.Stride;
            return rgbValues;
        }

        static void Main()
        {
            Bitmap image = new Bitmap("test_pic.bmp");
            int img_W = 0;
            int rt_len = 0;
            byte[] dst = GetRGBValues(image, out img_W);
            IntPtr pre_res = img_padding(dst, image.Height, img_W, out rt_len);
            //Mat pad_res = new Mat(pre_res); //This is the way I get return picture from DLL in C#
            ////pad_res is different from dll_pic.png I saved from dll_inf
            byte[] btarr = new byte[rt_len];
            Marshal.Copy(pre_res, btarr, 0, rt_len);
            dll_inference(btarr, image.Height, img_W);
        }
    }
}

Подводя итог, на данный момент я успешно выполнил преобразование из IntPtr в byte []:

поток данных: IntPtr >> Mat >> Bitmap >> byte []

Но для преобразования потребуется слишком много времени (по моему мнению ...) поэтому я хочу сделать его более простым

Я также попробовал другой способ преобразования, но он все еще не удался:

поток данных: IntPtr >> Mat >> byte []

с этим кодом

//C#
byte[] btarr = new byte[rt_len];
Mat X = new Mat(pre_res);
X.GetArray(image.Height, img_W, btarr);
dll_inference(btarr, image.Height, img_W);
//(But the result is also different from the way it should be...)

Я не знаю, где я сделал не так ... Любая помощь или совет с благодарностью !!

...