Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将图像从C#发送到正确接受OpenCV Mat的DLL? 我有一个C++类,我创建了一个C dll,用于我们的C语言解决方案。现在我需要将图像发送到DLL,但我不知道正确的方法。这是C++函数签名: std::vector<Prediction> Classify(const cv::Mat& img, int N = 2);_C#_C++_Opencv_Dll - Fatal编程技术网

如何将图像从C#发送到正确接受OpenCV Mat的DLL? 我有一个C++类,我创建了一个C dll,用于我们的C语言解决方案。现在我需要将图像发送到DLL,但我不知道正确的方法。这是C++函数签名: std::vector<Prediction> Classify(const cv::Mat& img, int N = 2);

如何将图像从C#发送到正确接受OpenCV Mat的DLL? 我有一个C++类,我创建了一个C dll,用于我们的C语言解决方案。现在我需要将图像发送到DLL,但我不知道正确的方法。这是C++函数签名: std::vector<Prediction> Classify(const cv::Mat& img, int N = 2);,c#,c++,opencv,dll,C#,C++,Opencv,Dll,dll中的代码: CDLL2_API void Classify_image(unsigned char* img_pointer, unsigned int height, unsigned int width, char* out_result, int* length_of_out_result, int top_n_results) { auto classifier = reinterpret_cast<Classifier*>(GetHandle(

dll中的代码:

CDLL2_API void Classify_image(unsigned char* img_pointer, unsigned int height, unsigned int width, char* out_result, int* length_of_out_result, int top_n_results)
    {
        auto classifier = reinterpret_cast<Classifier*>(GetHandle());
        cv::Mat img = cv::Mat(height, width, CV_32FC3, (void*)img_pointer);

        std::vector<Prediction> result = classifier->Classify(img, top_n_results);

        //misc code...
        *length_of_out_result = ss.str().length();
    }
但每当我尝试运行代码时,就会出现访问冲突错误:

类型为“System.AccessViolationException”的未处理异常 在使用dotNet.exe进行分类时发生

其他信息:尝试读取或写入受保护内存。 这通常表示其他内存已损坏

异常错误显示:

{“试图读取或写入受保护的内存。这通常是一个错误 表示其他内存已损坏。“}

对代码的深入研究表明,我在这个函数中得到了异常错误:

void Classifier::Preprocess(const cv::Mat& img, std::vector<cv::Mat>* input_channels)
{
    /* Convert the input image to the input image format of the network. */
    cv::Mat sample;
    if (img.channels() == 3 && num_channels_ == 1)
        cv::cvtColor(img, sample, cv::COLOR_BGR2GRAY);
    else if (img.channels() == 4 && num_channels_ == 1)
        cv::cvtColor(img, sample, cv::COLOR_BGRA2GRAY);
    else if (img.channels() == 4 && num_channels_ == 3)
        cv::cvtColor(img, sample, cv::COLOR_BGRA2BGR);
    else if (img.channels() == 1 && num_channels_ == 3)
        cv::cvtColor(img, sample, cv::COLOR_GRAY2BGR);
    else
        sample = img;

    //resize image according to the input
    cv::Mat sample_resized;
    if (sample.size() != input_geometry_)
        cv::resize(sample, sample_resized, input_geometry_);
    else
        sample_resized = sample;

    cv::Mat sample_float;
    if (num_channels_ == 3)
        sample_resized.convertTo(sample_float, CV_32FC3);
    else
        sample_resized.convertTo(sample_float, CV_32FC1);

    cv::Mat sample_normalized;
    cv::subtract(sample_float, mean_, sample_normalized);

    /* This operation will write the separate BGR planes directly to the
    * input layer of the network because it is wrapped by the cv::Mat
    * objects in input_channels. */
    cv::split(sample_normalized, *input_channels);

    CHECK(reinterpret_cast<float*>(input_channels->at(0).data)
        == net_->input_blobs()[0]->cpu_data())
        << "Input channels are not wrapping the input layer of the network.";
}
进一步调查和调试()使罪犯可见
这种方法被证明是完全错误的,或者至少是错误的。使用此代码,
C++
侧的图像似乎已正确初始化,通道数、高度和宽度似乎都很好

但是,当您尝试使用图像时,无论是通过调整图像大小还是使用
imshow()
显示图像,它都会使应用程序崩溃,并给出访问冲突异常,这与调整图像大小时发生的错误以及问题中发布的错误完全相同

看到这一点,我更改了负责将图像处理到
dll
的C代码。新守则如下:

//Dll import 
[DllImport(@"CDll2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void Classify_Image(IntPtr img, uint height, uint width, byte[] out_result, out int out_result_length, int top_n_results = 2);

//...
//main code 

Bitmap img = new Bitmap(txtImagePath.Text);
BitmapData bmpData = img.LockBits(new Rectangle(0, 0, img.Width, img.Height),  ImageLockMode.ReadWrite,  PixelFormat.Format24bppRgb);
result = Classify_UsingImage(bmpData, 1);
img.UnlockBits(bmpData); //Remember to unlock!!!

和DLL中的C++代码:< /P>

#ifdef CDLL2_EXPORTS
#define CDLL2_API __declspec(dllexport)
#else
#define CDLL2_API __declspec(dllimport)
#endif

#include "../classification.h" 
extern "C"
{
    CDLL2_API void Classify_image(unsigned char* img_pointer, unsigned int height, unsigned int width, char* out_result, int* length_of_out_result, int top_n_results = 2);
    //...
}
CDLL2_API void Classify_Image(unsigned char* img_pointer, unsigned int height, unsigned int width, char* out_result, int* length_of_out_result, int top_n_results)
    {
        auto classifier = reinterpret_cast<Classifier*>(GetHandle());

        cv::Mat img = cv::Mat(height, width, CV_8UC3, (void*)img_pointer, Mat::AUTO_STEP);
    
        std::vector<Prediction> result = classifier->Classify(img, top_n_results);
        
        //...
        *length_of_out_result = ss.str().length();
    }
CDLL2\u API void Classify\u图像(无符号字符*img\u指针、无符号整数高度、无符号整数宽度、字符*输出结果、输出结果的整数*长度、顶部结果)
{
自动分类器=重新解释强制转换(GetHandle());
cv::Mat img=cv::Mat(高度、宽度、cv_8UC3,(空*)img_指针、Mat::自动步进);
std::vector result=分类器->分类(img,顶部结果);
//...
*结果的长度=ss.str().length();
}
这样做纠正了我之前遇到的所有访问违规行为


虽然我现在可以轻松地将图像从C#发送到DLL,但我的当前实现存在一些问题。我不知道如何将OpenCV类型从C#发送到所需的函数,正如您所见,目前我使用的是硬编码图像类型,这就引出了一个问题,当我的输入图像是灰度图像或甚至是带有4个通道的png时,我该怎么办?

在尝试了许多不同的方法之后,我想知道这一点对其他寻求同样东西的人是有益的。 简而言之,我能找到的最好方法是(正如@EdChum所说的):

我会将该文件作为内存传递给您的openCV dll,这应该可以 要调用imdecode来嗅探文件类型,您还可以 传旗

还解释了如何发送指向
DLL
的指针,并使用
imdecode
对图像进行解码。这解决了许多其他方法引入的问题。而且还能帮你省去很多麻烦。
以下是intrest的代码:
这就是我在
DLL
C
中的函数的外观:

#ifdef CDLL2_EXPORTS
#define CDLL2_API __declspec(dllexport)
#else
#define CDLL2_API __declspec(dllimport)
#endif

#include "classification.h" 
extern "C"
{
    CDLL2_API void Classify_Image(unsigned char* img_pointer, long data_len, char* out_result, int* length_of_out_result, int top_n_results = 2);
//...
}
实际方法:

CDLL2_API void Classify_Image(unsigned char* img_pointer, long data_len,
                              char* out_result, int* length_of_out_result, int top_n_results)
{
    auto classifier = reinterpret_cast<Classifier*>(GetHandle());
    vector<unsigned char> inputImageBytes(img_pointer, img_pointer + data_len);
    cv::Mat img = imdecode(inputImageBytes, CV_LOAD_IMAGE_COLOR);

    cv::imshow("img just recieved from c#", img);

    std::vector<Prediction> result = classifier->Classify(img, top_n_results);
    //...
    *length_of_out_result = ss.str().length();
}
这是将图像发送回DLL的实际方法:

private string Classify_UsingImage(Bitmap image, int top_n_results)
{
    byte[] result = new byte[200];
    int len;
    Bitmap img;

    if (chkResizeImageCShap.Checked)
        img = ResizeImage(image, int.Parse(txtWidth.Text), (int.Parse(txtHeight.Text)));
    else
        img = image;

    ImageFormat fmt = new ImageFormat(image.RawFormat.Guid);

    var imageCodecInfo = ImageCodecInfo.GetImageEncoders().FirstOrDefault(codec => codec.FormatID == image.RawFormat.Guid);
    //this is for situations, where the image is not read from disk, and is stored in the memort(e.g. image comes from a camera or snapshot)
    if (imageCodecInfo == null)
    {
        fmt = ImageFormat.Jpeg;
    }

    using (MemoryStream ms = new MemoryStream())
    {
        img.Save(ms,fmt);
        byte[] image_byte_array = ms.ToArray();
        Classify_Image(image_byte_array, ms.Length, result, out len, top_n_results);
    }

    return ASCIIEncoding.ASCII.GetString(result);
}

你不应该在一篇文章中问多个问题,同样标题与你在文章中的问题无关:“但每当我试图运行代码时,当它试图将图像转换为字节数组(…)时,我会得到访问冲突错误:”-看起来像是图像转换问题。也许你可以使用一些已经在工作的包装,比如EmguCV或opencvsharp来处理不同的图片?谢谢,但这只是一个问题,不是几个问题,我问了如何做一个具体的动作,然后我解释了我做了什么以及结果是什么。或者这是一个错误的正确方法!或者有更好的方法。无论哪种情况,它都有一个独特的答案,可以解决与这个问题有关的问题!我可以确认,这仍然工作三年后使用一个WPF应用程序与一个C++ DLL使用OpenCV 3.4.3
CDLL2_API void Classify_Image(unsigned char* img_pointer, long data_len,
                              char* out_result, int* length_of_out_result, int top_n_results)
{
    auto classifier = reinterpret_cast<Classifier*>(GetHandle());
    vector<unsigned char> inputImageBytes(img_pointer, img_pointer + data_len);
    cv::Mat img = imdecode(inputImageBytes, CV_LOAD_IMAGE_COLOR);

    cv::imshow("img just recieved from c#", img);

    std::vector<Prediction> result = classifier->Classify(img, top_n_results);
    //...
    *length_of_out_result = ss.str().length();
}
[DllImport(@"CDll2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void Classify_Image(byte[] img, long data_len, byte[] out_result, out int out_result_length, int top_n_results = 2);
private string Classify_UsingImage(Bitmap image, int top_n_results)
{
    byte[] result = new byte[200];
    int len;
    Bitmap img;

    if (chkResizeImageCShap.Checked)
        img = ResizeImage(image, int.Parse(txtWidth.Text), (int.Parse(txtHeight.Text)));
    else
        img = image;

    ImageFormat fmt = new ImageFormat(image.RawFormat.Guid);

    var imageCodecInfo = ImageCodecInfo.GetImageEncoders().FirstOrDefault(codec => codec.FormatID == image.RawFormat.Guid);
    //this is for situations, where the image is not read from disk, and is stored in the memort(e.g. image comes from a camera or snapshot)
    if (imageCodecInfo == null)
    {
        fmt = ImageFormat.Jpeg;
    }

    using (MemoryStream ms = new MemoryStream())
    {
        img.Save(ms,fmt);
        byte[] image_byte_array = ms.ToArray();
        Classify_Image(image_byte_array, ms.Length, result, out len, top_n_results);
    }

    return ASCIIEncoding.ASCII.GetString(result);
}