c# - 为什么我无法将 IntPtr 转换为 byte[]?
问题描述
我正在做一个项目,使 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 转换的 byte[] 的过程中,输入数据 (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...)
我不知道我在哪里做错了......非常感谢任何帮助或建议!
解决方案
推荐阅读
- sas - 有没有一种方法可以像 R 一样访问 SAS 中的数据本身?
- reactjs - 调试 React-Native UI 问题的最佳工具/实践
- ios - Stack View 中的自定义 Facebook 按钮
- flutter - 使用 Elasticsearch 颤振
- docker - 运行 multi-stacker docker built docker image 失败 – Nexts 找不到 React 模块
- angular - 尝试运行我的 Angular Schematics 时出错
- macos - SocketException:在 macOS 上使用颤振应用程序连接失败(操作系统错误:不允许操作,errno = 1)
- c++ - 我怎样才能摆脱这种额外的间接级别?
- python - 在 Django 中访问一对一的表字段值
- visual-studio-code - VS Code 自动格式化奇怪的包装行为