【发布时间】:2021-03-19 13:55:51
【问题描述】:
上下文
我目前正在使用opencv 来检测视频源中的某些模式并将该信息发送到 Unity 游戏。 我找到了Aruco,一个opencv 模块以及 ArucoUnity 和ArucoUnityPlugin。但它不符合我的要求,所以我目前正在重新制作一个更简单的版本(即使用 opencv 作为库制作一个 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
}
【问题讨论】:
-
如果你需要 C# 中的 OpenCV,你可以使用 Emgu:emgu.com/wiki/index.php/Main_Page 这简化了 C++ 包装部分。
-
感谢 Sdra,我不确定它是否有效,因为我已经在 C++ 中完成了大部分图像分析(并且只将结果发送到 C#/Unity 端)。据我了解,Emgu 允许 C# 调用 opencv 的函数,这意味着我必须将所有这些分析移植到 C# 端。 (+ 我必须说服人们购买许可证)我希望能够让 Matrix 调用工作,但我会研究 Emgu 代码,看看他们是否做了类似的事情,如果他们做了,如何做。