Azure FunctionsでOpenCVSharpを利用したアプリケーションを作ったときにハマったこと

Azure FunctionsでOpenCVSharpを利用した画像の加工を行おうとしたのですが、以下の点でうまく動作しませんでした。

最初の構成

OpenCV3.2 All-in-one package - bundles native OpenCV DLLs: .NET Framework wrapper for OpenCVを利用してx86またはx64でアプリケーションをビルドし、ローカル環境で正常に動作することを確認しました。

そこでAzureFunctionsへデプロイして実行したところ、以下の通りエラーが発生し動作しないことがわかりました。

Exception while executing function: IneiConvertFunction
Microsoft.Azure.WebJobs.Host.FunctionInvocationException : Exception while executing function: IneiConvertFunction ---> System.TypeInitializationException : The type initializer for 'OpenCvSharp.NativeMethods' threw an exception. ---> System.DllNotFoundException : Unable to load DLL 'OpenCvSharpExtern': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
   at OpenCvSharp.NativeMethods.redirectError(CvErrorCallback errCallback,IntPtr userdata,IntPtr& prevUserdata)
   at OpenCvSharp.NativeMethods.LoadLibraries(IEnumerable`1 additionalPaths)
   at OpenCvSharp.NativeMethods..cctor() 
   End of inner exception
   at OpenCvSharp.NativeMethods.imgcodecs_imread(String filename,Int32 flags)
   at OpenCvSharp.Mat..ctor(String fileName,ImreadModes flags)
   at ReportFunctions.IneiConvertUtils.IneiConverter.Convert(String filePath)
   at ReportFunctions.IneiConvertFunction.Run(Stream ineiFileBlob,String name,TraceWriter log)
   at lambda_method(Closure ,IneiConvertFunction ,Object[] )
   at Microsoft.Azure.WebJobs.Host.Executors.VoidMethodInvoker`2.InvokeAsync(TReflected instance,Object[] arguments)
   at async Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker`2.InvokeAsync[TReflected,TReturnValue](Object instance,Object[] arguments)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.InvokeAsync(IFunctionInvoker invoker,ParameterHelper parameterHelper,CancellationTokenSource timeoutTokenSource,CancellationTokenSource functionCancellationTokenSource,Boolean throwOnTimeout,TimeSpan timerInterval,IFunctionInstance instance)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at async Microsoft.Azur…

この時点ではデプロイする時に何かファイルが不足しているなどが原因かと思っていました。KuduのDebug Consoleでデプロイされたファイルなどを比較してみたのですが、特に不足しているファイルなどは見当たりませんでした。

とりあえず何か足りないらしい…

さて、とりあえずこの段階でAzureFunctionsの利用をやめてVMにでも環境を構築してお茶を濁そうかとも思ったのですが、せっかくここまで作ったのでもうちょっと調べてみようと思いました。

とりあえずデプロイされているファイルの一式は特に変わりないのでアプリケーションの実行環境に差異があるのではと思い、OpenCVShapの動作環境を確認しました。

shimat/opencvsharp: .NET Framework wrapper for OpenCV

OpenCV 3.2 Visual C++ 2015 Redistributable Package .NET Framework 2.0 or later / .NET Core / Mono

とりあえず、NuGetパッケージを利用しているのでOpenCV本体については考える必要はなさそうでした。またKuduのDebug Consoleでインストールされている.NET Frameworkのバージョンを確認しましたが以下の通り問題ないことがわかりました。

D:\home>dotnet --version
2.0.3

ということで、3つの前提条件の打ち2つは問題ないことがわかったのですが、最後のVisual C++ 2015 Redistributable Packageをどのように確認するかです。

Visual C++ 2015 Redistributable Packageはインストールされていない

ここからはGoogleでいろいろなキーワードで検索する以外にい方法が思いつきませんでした。そう、私はC++での開発経験はないのでこの辺はさっぱりわからないからです(´ω`)

とはいえ、10分位アレヤコレヤと調べたところ以下のサイトに辿り着きました。

Visual C++ Redistributable Packages for Visual Studio Azure App Service – benjamin perkins

Azure Functionsは Azure App Serviceで動作しているので多分同じようにすれば調べられるだろうと思い早速試してみることにしました。

// Visual C++ Redistributable Packages for Visual Studio 2015
// x64
D:\home>reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Dependencies\{d992c12e-cab2-426f-bde3-fb8c53950b0d} "
ERROR: The system was unable to find the specified registry key or value.

// x86
D:\home>reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Dependencies\{e2803110-78b3-4664-a479-3611a381656a}"
ERROR: 
The system was unable to find the specified registry key or value.

// Visual C++ Redistributable Packages for Visual Studio 2013
// x64
D:\home>reg query "HKLM\SOFTWARE\Classes\Installer\Dependencies\{050d4fc8-5d48-4b8f-8972-47c82c46020f}"

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Dependencies\{050d4fc8-5d48-4b8f-8972-47c82c46020f}
    (Default)    REG_SZ    {050d4fc8-5d48-4b8f-8972-47c82c46020f}
    Version    REG_SZ    12.0.30501.0
    DisplayName    REG_SZ    Microsoft Visual C++ 2013 Redistributable (x64) - 12.0.30501

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Dependencies\{050d4fc8-5d48-4b8f-8972-47c82c46020f}\Dependents

// x86
D:\home>reg query "HKLM\SOFTWARE\Classes\Installer\Dependencies\{f65db027-aff3-4070-886a-0d87064aabb1}"

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Dependencies\{f65db027-aff3-4070-886a-0d87064aabb1}
    (Default)    REG_SZ    {f65db027-aff3-4070-886a-0d87064aabb1}
    Version    REG_SZ    12.0.30501.0
    DisplayName    REG_SZ    Microsoft Visual C++ 2013 Redistributable (x86) - 12.0.30501

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Dependencies\{f65db027-aff3-4070-886a-0d87064aabb1}\Dependents

どうやらVisual C++ Redistributable Packages for Visual Studio 2015についてはインストールされておらずVisual C++ Redistributable Packages for Visual Studio 2013であればインストールされているようです。

OpenCVSharp2.4を利用する

ここまででとりあえず現状のままだとOpenCVSharp3をAzure Functionsで動作させるのは無理そうだということになります。いや、ひょっとしたらVisual C++ Redistributable Packages for Visual Studio 2015をインストールするような方法があるのかもしれませんが、ちょっとわかりませんでした。

そこで、Visual C++ Redistributable Packages for Visual Studio 2013で動作するOpenCVSharpのバージョンを確認したところ2.4.10であれば動作することがわかりました。

shimat/opencvsharp_2410: .NET Framework wrapper for OpenCV 2.4.10

OpenCV 2.4.10 Visual C++ 2013 Redistributable Package .NET Framework 2.0 or later / Mono

これまで作っていたものを少し修正する必要がありますが、環境面ではこのバージョンで動作させることができそうだということがわかりました。

最終的に…

最終的にOpenCVSharp2.4.10を利用してAzure FunctionsでOpenCVを利用した画像加工処理を実装することができました。やりたいことが非常に単純なことで、Azure Storage のBlobContainerにファイルがアップロードされたら処理をしたいというだけだったので、この方法は最適でした。

Azure Functionsについては昨日始めて触ったのですが、一日位で一つの処理を動かすことができて満足しています。責務が明確な小さな処理は積極的に利用していこうかなと思いました。

Azureテクノロジ入門 2018

Azureテクノロジ入門 2018

  • 作者: 久森達郎、真壁徹、大田昌幸、藤本浩介、佐藤直生、安納順一、松崎剛、高添修,日本マイクロソフト株式会社
  • 出版社/メーカー: 日経BP社
  • 発売日: 2017/11/17
  • メディア: 単行本
  • この商品を含むブログを見る