前提・実現したいこと
GUIをC#、処理をC++で行うような画像処理のソフトを開発しようとしています。
その際、intなどの変数は受け渡しできるのですが、Mat型の変数の受け渡しができず困っています。
発生している問題・エラーメッセージ
C++の関数をC#で使う方法はいくつかあると思いますが、こちらのリンクを参考に、C++のdllをC#から使うという構成で作成しました。
はじめに確認として、C#からMat型の変数を受け取り、その変数をそのままreturnするような処理をしようとしましたが、以下のようなハンドルされない例外がありつまずいています。
System.InvalidOperationException:'この型は、その階層内にComVisible(false)の親を含んでいます。このため、IDispatchのQueryInterfacec呼び出し、またはクラスインターフェースは許可されません。'
該当のソースコード
c#
1using System.Runtime.InteropServices; 2using OpenCvSharp; 3 4namespace Application 5{ 6 public partial class MainWindow : System.Windows.Window 7 { 8 [DllImport( "Library.dll" )] 9 static extern Mat Test(Mat image); 10 11 public MainWindow() 12 { 13 InitializeComponent(); 14 Mat image = Cv2.Imread("test.jpg"); 15 Cv2.Imshow("image", image); 16 Mat image2 = Test(image); 17 Cv2.Imshow("image2", image2); 18 } 19 } 20}
c++
1//library.h 2#pragma once 3#include <opencv2/opencv.hpp> 4 5extern "C" 6{ 7 __declspec( dllexport ) cv::Mat Test(cv::Mat image); 8} 9 10//library.cpp 11#include <iostream> 12#include "library.h" 13 14cv::Mat Test(cv::Mat image) 15{ 16 return image; 17}
構造体は一般的にアドレス渡しをします。
「C/C++で作られたDLLをC#から利用する際の引数の渡し方色々」
https://ymegane88.hatenablog.com/entry/2019/08/12/013017
返信遅れて申し訳ございません、ありがとうございます。
確認してみます。
C++/CLI にしたなら、OpenCvSharp を参照設定して使うだけでは?
System.String^ は System.Runtime.InteropServices.Marshal クラスを使って BSTR に変換できます。
そこから std:string に変換すれば良いと思います。
Marshal.StringToBSTR(String) メソッド
https://docs.microsoft.com/ja-jp/dotnet/api/system.runtime.interopservices.marshal.stringtobstr?view=netframework-4.8
Marshal.PtrToStringBSTR(IntPtr) メソッド
https://docs.microsoft.com/ja-jp/dotnet/api/system.runtime.interopservices.marshal.ptrtostringbstr?view=netframework-4.8
なんだか明後日の方向に向かっているような気がします。メモリの解放もれに気を付けてください。
ありがとうございます。
情報がぬけていて申し訳ございませんが、最終的にはc++の物体検出プログラムの活用をしたいと考えており、その前段階として簡単なopencvの処理をc++側でさせようとしています。
ありがとうございます。
確認してみます。
imshowの引数にSystem::String^からstd::stringに変更したものを指定することを試してみましたが、同様にアンマネージドだからマネージドで書きましょう、となっています。
```c++
void OpenCVLibrary::ProcMat::test() {
System::String^ sys_name = "dog.jpg";
std::string std_name = msclr::interop::marshal_as<std::string>(sys_name);
cv::mat = imread(std_name);
cv::imshow("test", mat);
cv::waitKey(0);
}
```
申し訳ございません、見当はずれなことをしていましたらご指摘ください。
marshal_as なんてあったんですね。
「同様にアンマネージドだからマネージドで書きましょう」ってどういう意味ですか?
ありがとうございました。
ハンドルされない例外(System.Runtime.InteropServices.SEHException: )が表示されたときに
Inspection of unmanaged type 'std::basic_string<char,std::char_traits<char>,std::allocator<char> >*' requires unmanaged debugging to be enabled. Please set the debugger type to 'Mixed' and try again
と表示されています。書かれている通りデバッガーのモードを変更しても変化はありませんでした。
![デバッグ時の表示](https://ddjkaamml8q8x.cloudfront.net/questions/2022-01-20/1ca9e509-7e40-4652-a9f4-fe5d88dbd7c7.png)
std_name でエラーが出てますね。
marshal_as の使い方ってこれでいいんですか?
ありがとうございます。
marchal_asは問題なさそうです。
c++/cliのWindowsフォームアプリケーションで試しにこの書き方をしましたが問題ありませんでした。
画像のようにシンプルにstd::stringで変数を使ったときと同様のエラーが出ているようです。
![デバッグ時](https://ddjkaamml8q8x.cloudfront.net/questions/2022-01-20/1903f59c-a393-4dce-985e-fb1ddcb60dac.png)
C++/CLR の役割ですが、あれこれ機能を持たせようとするから問題なので
C++ のライブラリがエクスポートした関数と C# との橋渡しに留めてみては?
あ、32bit/64bit は大丈夫なんでしょうか?
imread の引数は st:string なので、OpenCV ですよね? cv::imgshow って OpenCVSharp じゃないですか?
ありがとうございます。
64bitで統一していてそれは問題なさそうです。
opencvでもcv::imshowがあるので大丈夫かなと思います。
気がかりなのがimreadでstd::stringを使うのは問題なくて、imshowで使うときに例外が発生することなんですよね、おそらくメモリを参照しようとしたらうまく書き込めていなかったといったことなのですが..
>opencvでもcv::imshowがあるので大丈夫かなと思います。
確実ですか?エラーメッセージが .NET のものなので気になります。
ありがとうございます。
```
#include <opencv2/opencv.hpp>
int main() {
cv::Mat img;
img = cv::imread("suwawachan.jpg");
cv::imshow("title", img);
cv::waitKey(0);
return 0;
}
```
[こちら](https://swallow-incubate.com/archives/blog/20181221/)からコピーしてきましたがこのようにかけるのでopencv(c++)でもcv:imshowは問題なさそうです。
上のコードは imread, 下のコードは c:imread になってますね。
上のコードはなぜ cv:imread じゃないんですか?
よくわからないですし、明後日の方向に向かってるようなので撤退します。
ありがとうございます。
承知しました。
あなたの回答
tips
プレビュー