前提・実現したいこと
Xamarin.FormsでOpenCVを使って顔認証をしたいと思っています。
Formsの必要がないといわれてしまうかもしれませんが、現時点ではAndroidのみの実装予定です。
Xamarin.FormsからDepencencyServiceを使ってXamarin.Androidに書いてあるC++の処理を呼び出すという流れで考えています。
カメラやギャラリーから画像を取得し、顔認識を行う関数の引数として取得した画像を送り、返り値として顔の位置が表示された画像(下の画像のような状態のもの)が返ってくるようなものにしたいと思っています。
![(b814c28bdf91ebe6aabd69ae43a7313c.jpeg)
C++の処理を.dllとしてビルドして、.dllをAndroidで参照するという流れまでは理解することができたのですが、そこで疑問が出てきたので質問させていただきます。
質問内容
こちらのようなC++のサンプルソースを関数として作成しAndroidでその処理を呼び出すことができるのか
C++のクラスライブラリをプロジェクトの中で作り、できた.dllファイルをそのまま参照しても問題ないのか
これらよりのことを行うことよりも簡単に実装することができるのか
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
これらよりのことを行うことよりも簡単に実装することができるのか
リアルタイムに、あるいは自力で、顔検出をしたいのではなければ、各社が出している WebAPI を使用した方が簡単かと思います。
投稿2018/03/26 15:20
総合スコア1075
0
C/C++のライブラリをC#で呼ぶ方法は
- DllImport属性(System.Runtime.ExceptionServices名前空間)を使う
- C++/CLIによるラッパークラスを経由して呼び出す
の2種類があります。
CppSharpを使えばヘッダーファイルとライブラリファイルを解析をしてC++/CLI用のコードとC#用のコードを自動生成してくれます。C/C++の解析にClangを用いて実装されています。
以下はVista時代のVisual C++の流儀(前編)に掲載されているcounterクラスを以下に示します。
cpp
1#ifndef COUNTER_H__ 2 #define COUNTER_H__ 3 4 class counter { 5 private: 6 int value_; 7 public: 8 counter(); 9 void increment(); 10 int value() const; 11 }; 12 13 #endif
cpp
1#include "counter.h" 2 3 counter::counter() : value_(0) { 4 } 5 6 void counter::increment() { 7 ++value_; 8 } 9 10 int counter::value() const { 11 return value_; 12 }
それではcounterクラスを自動でラッピングしてくれるCppSharpによるC++/CLIのヘッダーファイルとソースファイルを生成されたソースコードを以下に示します。
cpp
1// ---------------------------------------------------------------------------- 2// <auto-generated> 3// This is autogenerated code by CppSharp. 4// Do not edit this file or all your changes will be lost after re-generation. 5// </auto-generated> 6// ---------------------------------------------------------------------------- 7#pragma once 8 9#include "CppSharp.h" 10#include <../counter.h> 11 12namespace CounterLib 13{ 14 ref class Counter; 15} 16 17namespace CounterLib 18{ 19 public ref class Counter : ICppInstance 20 { 21 public: 22 23 property ::counter* NativePtr; 24 property System::IntPtr __Instance 25 { 26 virtual System::IntPtr get(); 27 virtual void set(System::IntPtr instance); 28 } 29 30 Counter(::counter* native); 31 static Counter^ __CreateInstance(::System::IntPtr native); 32 Counter(); 33 34 Counter(CounterLib::Counter^ _0); 35 36 ~Counter(); 37 38 !Counter(); 39 40 property int Value 41 { 42 int get(); 43 } 44 45 void Increment(); 46 47 protected: 48 bool __ownsNativeInstance; 49 }; 50}
cpp
1// ---------------------------------------------------------------------------- 2// <auto-generated> 3// This is autogenerated code by CppSharp. 4// Do not edit this file or all your changes will be lost after re-generation. 5// </auto-generated> 6// ---------------------------------------------------------------------------- 7#include "CounterWrapper.h" 8 9using namespace System; 10using namespace System::Runtime::InteropServices; 11 12CounterLib::Counter::Counter(::counter* native) 13 : __ownsNativeInstance(false) 14{ 15 NativePtr = native; 16} 17 18CounterLib::Counter^ CounterLib::Counter::__CreateInstance(::System::IntPtr native) 19{ 20 return gcnew ::CounterLib::Counter((::counter*) native.ToPointer()); 21} 22 23CounterLib::Counter::~Counter() 24{ 25 delete NativePtr; 26} 27 28CounterLib::Counter::!Counter() 29{ 30 delete NativePtr; 31} 32 33CounterLib::Counter::Counter() 34{ 35 __ownsNativeInstance = true; 36 NativePtr = new ::counter(); 37} 38 39void CounterLib::Counter::Increment() 40{ 41 ((::counter*)NativePtr)->increment(); 42} 43 44CounterLib::Counter::Counter(CounterLib::Counter^ _0) 45{ 46 __ownsNativeInstance = true; 47 if (ReferenceEquals(_0, nullptr)) 48 throw gcnew ::System::ArgumentNullException("_0", "Cannot be null because it is a C++ reference (&)."); 49 auto &__arg0 = *(::counter*)_0->NativePtr; 50 NativePtr = new ::counter(__arg0); 51} 52 53System::IntPtr CounterLib::Counter::__Instance::get() 54{ 55 return System::IntPtr(NativePtr); 56} 57 58void CounterLib::Counter::__Instance::set(System::IntPtr object) 59{ 60 NativePtr = (::counter*)object.ToPointer(); 61} 62 63int CounterLib::Counter::Value::get() 64{ 65 auto __ret = ((::counter*)NativePtr)->value(); 66 return __ret; 67}
あとは「共通言語ランタイム サポート (/clr)」「ダイナミック ライブラリ (.dll)」の設定への変更とスタティックライブラリへのパスを設定してビルドすればC#からでもVB/F#からでもこのcounterクラスを呼び出すことができます。
ILSpyというツールを使ってCounterを解析すると以下のようなC#のコードが生成されています。
cs
1using System; 2using System.Runtime.ExceptionServices; 3using System.Runtime.InteropServices; 4 5namespace CounterLib 6{ 7 public class Counter : ICppInstance, IDisposable 8 { 9 private unsafe counter* <backing_store>NativePtr; 10 11 protected bool __ownsNativeInstance; 12 13 public int Value 14 { 15 get 16 { 17 return <Module>.counter.value(this.<backing_store>NativePtr); 18 } 19 } 20 21 public unsafe virtual IntPtr __Instance 22 { 23 get 24 { 25 IntPtr result = new IntPtr((void*)this.<backing_store>NativePtr); 26 return result; 27 } 28 set 29 { 30 this.<backing_store>NativePtr = (counter*)value.ToPointer(); 31 } 32 } 33 34 public unsafe counter* NativePtr 35 { 36 get 37 { 38 return this.<backing_store>NativePtr; 39 } 40 set 41 { 42 this.<backing_store>NativePtr = value; 43 } 44 } 45 46 public unsafe Counter(Counter _0) 47 { 48 this.__ownsNativeInstance = true; 49 if (object.ReferenceEquals(_0, null)) 50 { 51 throw new ArgumentNullException("_0", "Cannot be null because it is a C++ reference (&)."); 52 } 53 counter* ptr = _0.<backing_store>NativePtr; 54 counter* ptr2 = <Module>.@new(4u); 55 counter* ptr3; 56 if (ptr2 != null) 57 { 58 cpblk(ptr2, ptr, 4); 59 ptr3 = ptr2; 60 } 61 else 62 { 63 ptr3 = null; 64 } 65 this.<backing_store>NativePtr = ptr3; 66 } 67 68 public unsafe Counter() 69 { 70 this.__ownsNativeInstance = true; 71 counter* ptr = <Module>.@new(4u); 72 counter* ptr2; 73 try 74 { 75 if (ptr != null) 76 { 77 ptr2 = <Module>.counter.{ctor}(ptr); 78 } 79 else 80 { 81 ptr2 = 0; 82 } 83 } 84 catch 85 { 86 <Module>.delete((void*)ptr, 4u); 87 throw; 88 } 89 this.<backing_store>NativePtr = ptr2; 90 } 91 92 public unsafe Counter(counter* native) 93 { 94 this.__ownsNativeInstance = false; 95 base..ctor(); 96 this.<backing_store>NativePtr = native; 97 } 98 99 public unsafe static Counter __CreateInstance(IntPtr native) 100 { 101 return new Counter((counter*)native.ToPointer()); 102 } 103 104 private unsafe void ~Counter() 105 { 106 <Module>.delete((void*)this.<backing_store>NativePtr, 4u); 107 } 108 109 private unsafe void !Counter() 110 { 111 <Module>.delete((void*)this.<backing_store>NativePtr, 4u); 112 } 113 114 public void Increment() 115 { 116 <Module>.counter.increment(this.<backing_store>NativePtr); 117 } 118 119 [HandleProcessCorruptedStateExceptions] 120 protected unsafe virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool A_0) 121 { 122 if (A_0) 123 { 124 <Module>.delete((void*)this.<backing_store>NativePtr, 4u); 125 } 126 else 127 { 128 try 129 { 130 this.!Counter(); 131 } 132 finally 133 { 134 base.Finalize(); 135 } 136 } 137 } 138 139 public sealed override void Dispose() 140 { 141 this.Dispose(true); 142 GC.SuppressFinalize(this); 143 } 144 145 protected override void Finalize() 146 { 147 this.Dispose(false); 148 } 149 } 150}
投稿2018/03/27 00:00
編集2018/03/27 00:08総合スコア178
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
画像をサーバに投げて、サーバ側で処理して返すのが、ツラミは少なそう。
応答速度的には、ネイティブで処理したほうが早そうだけど。
投稿2018/03/26 08:25
総合スコア1984
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
C#からC++のdllを呼び出すことは可能です。
https://qiita.com/ask/items/ee2ff5b8706effc0c3d8
C#版OpenCVはイマイチ使いづらいという話を聞いたことがあります。(ソースなし)
C++側でOpenCVをいろいろ操作して、結果だけC#側に返すのがやりやすいと思います。
投稿2018/03/26 04:47
総合スコア7196
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。