You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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 matType values and memory layout match.
  • Memory Safety: Ensure the C# Mat object 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:10:26