基于uint16指针创建Mat:C#与C++跨语言DLL交互技术问询
Hey there! Let's work through this OpenCV cross-language Mat passing issue you're facing.
First off, the problem with your current approach is that you're only passing the raw data pointer of the C# Mat to C++—but a proper OpenCV cv::Mat needs more than just the pixel data to be correctly reconstructed. You also need key metadata like the matrix's dimensions (rows/cols), pixel type (e.g., 16-bit unsigned single channel), and memory step (the number of bytes per row, which accounts for memory alignment).
Here's how to fix this step by step:
1. Update your C++ DLL function to accept all necessary Mat metadata
Instead of just taking an LPVOID for the data pointer, modify the function signature to include the rows, cols, pixel type, and step values. This lets you properly reconstruct a valid cv::Mat in C++:
#include <opencv2/opencv.hpp> double CustomData::calculate(LPVOID dataPtr, int rows, int cols, int matType, size_t step) { // Reconstruct the cv::Mat using the passed metadata cv::Mat inputMat(rows, cols, matType, dataPtr, step); double sum = 0; // Safely iterate over the 16-bit unsigned data (adjust if your type differs) if (inputMat.type() == CV_16UC1) { for (int y = 0; y < inputMat.rows; ++y) { const UINT16* rowData = inputMat.ptr<UINT16>(y); for (int x = 0; x < inputMat.cols; ++x) { sum += rowData[x]; } } } return sum; }
2. Adjust your C# code to pass all required Mat properties
Assuming you're using a library like OpenCVSharp or Emgu CV (common for C# OpenCV bindings), your C# Mat object exposes all the metadata we need. Use DllImport to call the updated C++ function, passing these properties:
using System.Runtime.InteropServices; using OpenCvSharp; // Or Emgu.CV if you're using that public class MatProcessor { [DllImport("YourCppDll.dll", CallingConvention = CallingConvention.Cdecl)] private static extern double calculate(IntPtr dataPtr, int rows, int cols, int matType, long step); public static double CalculateSum(Mat mat) { // Ensure the Mat is valid before passing if (mat == null || !mat.IsValid()) { throw new ArgumentException("Invalid Mat object"); } // Pass all necessary metadata to the C++ function return calculate(mat.DataPointer, mat.Rows, mat.Cols, mat.Type, mat.Step); } }
3. If you must only pass a single pointer (e.g., fixed partner interface)
If your partner's API is locked to only accepting a single LPVOID, you can package all the Mat metadata into a struct, then pass a pointer to that struct from C# to C++:
C++ struct definition:
struct MatMetadata { void* dataPtr; int rows; int cols; int matType; size_t step; }; double CustomData::calculate(LPVOID ptr) { MatMetadata* meta = static_cast<MatMetadata*>(ptr); cv::Mat inputMat(meta->rows, meta->cols, meta->matType, meta->dataPtr, meta->step); // Same sum calculation as before... double sum = 0; if (inputMat.type() == CV_16UC1) { for (int y = 0; y < inputMat.rows; ++y) { const UINT16* rowData = inputMat.ptr<UINT16>(y); for (int x = 0; x < inputMat.cols; ++x) { sum += rowData[x]; } } } return sum; }
C# corresponding struct and call:
[StructLayout(LayoutKind.Sequential)] private struct MatMetadata { public IntPtr dataPtr; public int rows; public int cols; public int matType; public long step; } [DllImport("YourCppDll.dll", CallingConvention = CallingConvention.Cdecl)] private static extern double calculate(IntPtr metaPtr); public static double CalculateSum(Mat mat) { var meta = new MatMetadata { dataPtr = mat.DataPointer, rows = mat.Rows, cols = mat.Cols, matType = mat.Type, step = mat.Step }; // Pin the struct to prevent GC from moving it during the call GCHandle handle = GCHandle.Alloc(meta, GCHandleType.Pinned); try { return calculate(handle.AddrOfPinnedObject()); } finally { handle.Free(); } }
Key Notes to Avoid Bugs:
- Version Compatibility: Make sure your C# OpenCV binding (OpenCVSharp/Emgu CV) uses the same OpenCV version as your C++ DLL. This ensures the
matTypevalues and memory layout match. - Memory Safety: Ensure the C#
Matobject stays alive for the entire duration of the C++ function call—don't dispose it mid-execution, as that would invalidate the data pointer. - Pixel Type Matching: Double-check that the
CV_16UC1(or whatever type you're using) matches the actual type of your Mat in both C# and C++. Mismatched types will cause garbage data or crashes.
内容的提问来源于stack exchange,提问作者Mathieu Gauquelin

