如何使用 Opencv 加载图像并将其传递给 Unity(通过 C++ dll)?

伯努瓦·兰迪

语境

我目前正在使用 opencv 检测视频源中的某些模式并将该信息发送到 Unity 游戏。我找到了 Aruco ,一个 opencv 模块以及 ArucoUnity ArucoUnityPlugin 但它不符合我的要求,所以我目前正在重新制作一个更简单的版本(ei 使用 opencv 作为 lib 制作一个 dll 并在 Unity 中导入其功能)。

问题

虽然使用简单的参数(int、string)并设法取回值,但我正在努力将图像加载到 Mat(通过 imread 函数)并在 C# 中取回 Mat。我可以使用 new Mat() 创建一个空的 Mat() 并将其返回到 C# 中,我可以将 imagetest 加载到 Mat 中,但是当我尝试将其放入返回的 Mat 中时,应用程序崩溃了。

代码

C++

mat.hpp(部分)

#ifdef PATTERNRECOGNITIONTOCLONEDLL_EXPORTS
#define PATTERNRECOGNITION_API __declspec(dllexport)
#else
#define PATTERNRECOGNITION_API __declspec(dllimport)
#endif
extern "C" {
    const string pluginFolderPath = "./Assets/Plugin/";

    PATTERNRECOGNITION_API cv::Mat* mat_new();
    PATTERNRECOGNITION_API cv::Mat* mat_loadPath(const char* path);
}

mat.cpp(部分)

cv::Mat* mat_new() // This works
{
    return new cv::Mat();
}

cv::Mat* mat_loadPath(const char* path) // This doesn't
{
    Mat* matPtr = new cv::Mat(); // Create an empty Mat
    *matPtr = cv::imread(pluginFolderPath + string(path), cv::IMREAD_COLOR); // read the image into the Mat
    return matPtr;
}

C#

Mat.cs(部分)

class Mat : HandleCppPtr
{
    public Mat(string path) : base(mat_loadPath(path))
    {
    }
    public Mat() : base(mat_new())
    {
    }
}

HandleCppPtr.cs(部分)

public enum DeleteResponsibility
{
    True,
    False
}

public abstract class  HandleCppPtr
{

    public HandleCppPtr(IntPtr cppPtr, DeleteResponsibility deleteResponsibility = DeleteResponsibility.True)
    {
        CppPtr = cppPtr;
        this.deleteResponsibility = deleteResponsibility;
    }

    ~HandleCppPtr()
    {
        if(this.deleteResponsibility == DeleteResponsibility.True)
        {
            Debug.Log("[C# ]Deleting HandleCppPtr object -> " + this.ToString());
            DeleteCppPtr();
        }
        else
        {
            Debug.Log("[C# ] NOT Deleting HandleCppPtr object because deleteResp is False -> " + this.ToString());
        }
    }

    public IntPtr CppPtr
    {
        get { return handle.Handle; }
        set { handle = new HandleRef(this, value); }
    }
    public DeleteResponsibility deleteResponsibility;
    HandleRef handle;
    protected abstract void DeleteCppPtr();
}

错误

当我尝试使用以下 C# 代码创建 Mat 时:
void Update()
{
    string testImagePath = "TestMatImage.png";
    if (Input.GetKeyDown(KeyCode.P))
    {
        Debug.Log("[C# ] Loading Image by Path = " + testImagePath);
        Mat mat = new Mat(testImagePath);
        Debug.Log(mat.ToString());
    }
}

它崩溃了,我收到以下错误:Microsoft Visual C++ 运行时库

运行时错误!程序:

此应用程序已请求运行时以异常方式终止。请联系应用程序的支持团队了解更多信息。

( https://i.stack.imgur.com/LN0Xb.png )

编辑 1

我曾尝试打印指针以查看在使用 imread 时是否没有发生恶作剧,但值(在重新启动之间更改时)前后相同。所以似乎不是这样。仍然在这里我使用的代码。
cv::Mat* mat_loadPath(const char* path)
{
    string message = "[C++] Loading mat by Path -> " + pluginFolderPath + string(path);
    DebugLog(message.c_str()); // Custom function that send debug message to Unity
    // PRINT : [C++] Loading mat by Path -> ./Assets/Plugin/TestMatImage.png
    
    Mat* matPtr = new cv::Mat(); // Create an empty Mat
    message = "[C++] Mat Not Loaded -> at " + std::to_string((int)matPtr) + "  (" + std::to_string(matPtr->rows) + "," + std::to_string(matPtr->cols) + ") ";
    DebugLog(message.c_str());
    // PRINT: [C++] Mat Not Loaded -> at -1895966160  (0,0) 

    *matPtr = cv::imread(pluginFolderPath + string(path), cv::IMREAD_COLOR); // read the image into the Mat
     message = "[C++] Mat Loaded -> at "+ std::to_string((int)matPtr) +"  (" + std::to_string(matPtr->rows) + "," + std::to_string(matPtr->cols) + ") " + std::to_string(matPtr->at<Vec3b>(0, 0).val[1]);
    DebugLog(message.c_str());
    // PRINT: [C++] Mat Loaded -> at -1895966160  (10,10) 231
        
    return new cv::Mat(); // If this is replaced by matPtr, the call of the 
}
伯努瓦·兰迪

我找到了崩溃的原因,后来我想获得我作为错误类型的值(Vecd 而不是正确的 Vec3b)的值。此外,我在测试时也没有使用“new cv::Mat()”,这会导致 Mat 被 C++ 丢弃(以及指向随机内容的 C#)。

对于任何想要做类似事情的人,这里是我的代码(即使它的灵感来自 NormandErwan 的 ArucoUnity/ArucoUnityPlugin)。

C++

在某处有以下内容(对我来说它在 PatternRecognition.hpp 中)
#ifdef PATTERNRECOGNITIONTOCLONEDLL_EXPORTS
#define PATTERNRECOGNITION_API __declspec(dllexport)
#else
#define PATTERNRECOGNITION_API __declspec(dllimport)
#endif

.hpp文件

#include <opencv2/core.hpp>
#include "PatternRecognition.hpp"


using namespace CloneToTangible;

extern "C" {

    const string pluginFolderPath = "./Assets/Plugin/";

    PATTERNRECOGNITION_API cv::Mat* mat_new();
    PATTERNRECOGNITION_API cv::Mat* mat_loadPath(const char* path);

    PATTERNRECOGNITION_API void mat_delete(cv::Mat* matPtr);

    PATTERNRECOGNITION_API Vec3b* mat_at(cv::Mat* mat, uint posX, uint posY);

    PATTERNRECOGNITION_API int mat_rows(cv::Mat* mat);
    PATTERNRECOGNITION_API int mat_cols(cv::Mat* mat);

    PATTERNRECOGNITION_API int mat_type(cv::Mat* mat);
}

垫子文件

#include "pch.h"
#include "mat.hpp"
#include <opencv2\imgcodecs.hpp>

cv::Mat* mat_new()
{
    Mat* matPtr = new cv::Mat();
    //DebugLog(("[C++] Mat Loaded -> at " + std::to_string((int)matPtr) + "  (" + std::to_string(matPtr->rows) + "," + std::to_string(matPtr->cols) + ") " + std::to_string(matPtr->at<Vec3b>(0, 0).val[1])).c_str());
    return matPtr;
}

cv::Mat* mat_loadPath(const char* path)
{
    //DebugLog(("[C++] Loading mat by Path -> " + pluginFolderPath + string(path)).c_str());
    Mat* matPtr = new cv::Mat();
    *matPtr = cv::imread(pluginFolderPath + string(path), cv::IMREAD_COLOR);
    //DebugLog(("[C++] Mat Loaded -> at " + std::to_string((int)matPtr) + "  (" + std::to_string(matPtr->rows) + "," + std::to_string(matPtr->cols) + ") " + std::to_string(matPtr->at<Vec3b>(0, 0).val[1])).c_str());
    return matPtr;
}

void mat_delete(cv::Mat* matPtr)
{
    delete matPtr;
}

Vec3b* mat_at(cv::Mat* mat, uint posX, uint posY)
{
    return new Vec3b(mat->at<Vec3b>(posX,posY));
}

int mat_rows(cv::Mat* mat)
{
    //DebugLog(("Returning rows for " + std::to_string((int)&mat) + " which is " + std::to_string(mat->rows)).c_str());
    return mat->rows;
}

int mat_cols(cv::Mat* mat)
{
    //DebugLog(("Returning cols for " + std::to_string((int)&mat) + " which is " + std::to_string(mat->cols)).c_str());
    return mat->cols;
}

int mat_type(cv::Mat* mat)
{
    return mat->type();
}

vec3b.hpp

#include <opencv2/core.hpp>
#include "PatternRecognition.hpp"

extern "C" {

    PATTERNRECOGNITION_API cv::Vec3b* cv_Vec3b_new(unsigned char v0, unsigned char v1, unsigned char v2);

    PATTERNRECOGNITION_API void cv_Vec3b_delete(cv::Vec3b* vec3dPtr);

    PATTERNRECOGNITION_API unsigned char cv_Vec3b_get(cv::Vec3b* vec3dPtr, int i);

    PATTERNRECOGNITION_API void cv_Vec3b_set(cv::Vec3b* vec3dPtr, int i, unsigned char value);

    PATTERNRECOGNITION_API void cv_Vec3b_setAll(cv::Vec3b* vec3dPtr, unsigned char v0, unsigned char v1, unsigned char v2);;
}

vec3b.cpp

#include "pch.h"
#include "vec3b.hpp"

cv::Vec3b* cv_Vec3b_new(unsigned char v0, unsigned char v1, unsigned char v2)
{
    return new cv::Vec3b(v0, v1, v2);
}

void cv_Vec3b_delete(cv::Vec3b* vec3bPtr)
{
    int n = (*vec3bPtr)[0];
    delete vec3bPtr;
}

unsigned char cv_Vec3b_get(cv::Vec3b* vec3bPtr, int i)
{
    unsigned char value = 0;
    try {
        value = (*vec3bPtr)[i];
    }
    catch (const cv::Exception& e) {
        return value;
    }
    return value;
}

void cv_Vec3b_set(cv::Vec3b* vec3bPtr, int i, unsigned char value)
{
    try {
        (*vec3bPtr)[i] = value;
    }
    catch (const cv::Exception& e) {
    }
}

void cv_Vec3b_setAll(cv::Vec3b* vec3bPtr, unsigned char v0, unsigned char v1, unsigned char v2)
{
    try {
        (*vec3bPtr)[0] = v0;
        (*vec3bPtr)[1] = v1;
        (*vec3bPtr)[2] = v2;
    }
    catch (const cv::Exception& e) {
    }
}

C#

垫子
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

class Mat : HandleCppPtr
{
    public int cols
    {
        get { return mat_cols(CppPtr); }
    }
    public int rows
    {
        get { return mat_rows(CppPtr); }
    }
    public int type
    {
        get { return mat_type(CppPtr); }
    }

    [DllImport("PatternRecognitionToCloneDLL")]
    static extern IntPtr mat_new();

    [DllImport("PatternRecognitionToCloneDLL")]
    public static extern IntPtr mat_loadPath(string path);

    [DllImport("PatternRecognitionToCloneDLL")]
    static extern void mat_delete(IntPtr matPtr);

    [DllImport("PatternRecognitionToCloneDLL")]
    static extern IntPtr mat_at(IntPtr matPtr, uint x, uint y);

    [DllImport("PatternRecognitionToCloneDLL")]
    static extern int mat_cols(IntPtr matPtr);

    [DllImport("PatternRecognitionToCloneDLL")]
    static extern int mat_rows(IntPtr matPtr);

    [DllImport("PatternRecognitionToCloneDLL")]
    static extern int mat_type(IntPtr matPtr);

    public Mat(string path, DeleteResponsibility deleteResponsibility = DeleteResponsibility.True) : base(mat_loadPath(path), deleteResponsibility)
    {
        Debug.Log("[C#] Mat Instantiation : Mat(string path) ");
    }

    public Mat(DeleteResponsibility deleteResponsibility = DeleteResponsibility.True) : base(mat_new(), deleteResponsibility)
    {
        Debug.Log("[C#] Mat Instantiation : Mat() ");
    }
    public Mat(IntPtr cppPtr, DeleteResponsibility deleteResponsibility = DeleteResponsibility.True) : base(cppPtr, deleteResponsibility)
    {

    }

    public Vec3b At(uint x, uint y)
    {
        if (x < rows && y < cols)
            return new Vec3b(mat_at(this.CppPtr, x, y));
        else
            return new Vec3b();
    }

    protected override void DeleteCppPtr()
    {
        //Debug.Log("[C#] Mat Destruction : DeleteCppPtr(), before mat_delete() call ");
        mat_delete(this.CppPtr);
        //Debug.Log("[C#] Mat Destruction : DeleteCppPtr(), after mat_delete() call ");
    }

    public override string ToString()
    {
        string message = "Mat->";
        int rows = mat_rows(this.CppPtr);
        Debug.Log("[C#] Mat has " + rows + " rows");
        int cols = mat_cols(this.CppPtr);
        Debug.Log("[C#] Mat has " + cols + " cols");
        for (uint x = 0; x < rows; x++)
        {
            message += "\n {";
            for (uint y = 0; y < cols; y++)
            {
                message += At(x, y).ToString();
            }
            message += "}";
        }
        return message;
    }

}

Vec3b.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

public class Vec3b : HandleCppPtr
{

    [DllImport("PatternRecognitionToCloneDLL")]
    static extern IntPtr cv_Vec3b_new(byte v0, byte v1, byte v2);

    [DllImport("PatternRecognitionToCloneDLL")]
    static extern void cv_Vec3b_delete(IntPtr vec3bPtr);


    [DllImport("PatternRecognitionToCloneDLL")]
    static extern byte cv_Vec3b_get(IntPtr vec3bPtr, int i);

    [DllImport("PatternRecognitionToCloneDLL")]
    static extern void cv_Vec3b_set(IntPtr vec3bPtr, int i, byte value);

    [DllImport("PatternRecognitionToCloneDLL")]
    static extern void cv_Vec3b_setAll(IntPtr vec3bPtr, byte v0, byte v1, byte v2);

    public Vec3b(byte v0 = 0, byte v1 = 0, byte v2 = 0) : base(cv_Vec3b_new(v0, v1, v2))
    {
    }

    public Vec3b(IntPtr cppPtr) : base(cppPtr)
    {
    }

    protected override void DeleteCppPtr()
    {
        cv_Vec3b_delete(this.CppPtr);
    }

    public int Get(int i)
    {
        return cv_Vec3b_get(this.CppPtr, i);
    }

    public void Set(int i, byte value)
    {
        cv_Vec3b_set(this.CppPtr, i, value);
    }


    public void Set(byte v0, byte v1, byte v2)
    {
        cv_Vec3b_setAll(this.CppPtr, v0, v1, v2);
    }

    public override string ToString()
    {
        string message = "Vec3b->";
        message += "(" + Get(0) + "," + Get(1) + "," + Get(2) + ")";
        return message;
    }

}

处理CppPtr.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;


public enum DeleteResponsibility
{
    True,
    False
}
public abstract class  HandleCppPtr
{

    public HandleCppPtr(IntPtr cppPtr, DeleteResponsibility deleteResponsibility = DeleteResponsibility.True)
    {
        CppPtr = cppPtr;
        this.deleteResponsibility = deleteResponsibility;
    }

    ~HandleCppPtr()
    {
        if(this.deleteResponsibility == DeleteResponsibility.True)
        {
            //Debug.Log("[C# ]Deleting HandleCppPtr object -> " + this.ToString());
            DeleteCppPtr();
        }
        else
        {
            //Debug.Log("[C# ] NOT Deleting HandleCppPtr object because deleteResp is False -> " + this.ToString());
        }
    }

    public IntPtr CppPtr
    {
        get { return handle.Handle; }
        set { handle = new HandleRef(this, value); }
    }
    public DeleteResponsibility deleteResponsibility;
    HandleRef handle;
    protected abstract void DeleteCppPtr();
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

将opencv读取图像传递给dll c++函数

LabVIEW使用C DLL使用OpenCV DLL

如何仅使用* .lib文件而不是OpenCV C ++中的* .dll

如何将图像从C#发送到正确接受OpenCV Mat的dll?

C#如何扩展参数并将其传递给属性

如何使用C#加载DLL?

unity3d导入c ++ dll以通过引用方法传递

如何使用Jsoup获取图像并将其传递给ImageView

打包OpenCV Dll以分发C ++ DLL

如何使用C .dll

如何使用户输入成为数组并将其传递给C#中的方法?

如何从 LINQ 加载 ViewModel 并将其传递给 View

如何在C或C ++中包装参数并将其传递给system或exec *

如何在C ++文件中使用opencv函数并将其与Python绑定?

如何使用ctypes将python列表传递给C函数(dll)

如何使Windows START命令通过管道接受标准输入并将其传递给它调用的命令?

如何通过procmail获取复制的电子邮件的文件名并将其传递给脚本?

如何使用opencv通过键盘输入捕获图像?

如何读取文件中的数据,并将其传递给struct〜> C

如何将输出通过管道传递到sh脚本并将其通过管道传递给命令?

如何使PostgreSQL加载依赖DLL的C模块?

如何在C ++中使用OpenCV拼接4张图像

如何通过参考传递opencv mat

无法使用OpenCv 3.4.5从具有C ++ dll的IP摄像机(rtsp)抓取帧

opencv是如何通过trackbar进行图像缩放的?

无法加载DLL'opencv_core290

Python Opencv DLL加载失败-Windows 10

使用Java绑定识别OpenCV缺少的DLL

如何使用OpenCV Java压缩图像并将其存储到特定文件夹