Introduction

OpenCVSharp は関係ないと思うけど、念のため。
単純に IP カメラをキャプチャするコードを書いており、.NET 6 を指定していたのに気づいて .NET 8 に変更して実行したところ例外が発生。
.NET 6 の時とコードは同一で動いていたコードが動かなくなった。

再現コードは下記。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using NLog;
using OpenCvSharp;

namespace Demo
{

internal sealed class Program
{

#region Fields

private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

#endregion

#region Methods

private static void Main(string[] args)
{
using var frame = new Mat();
}

#endregion

}

}

.NET 8 でビルドし、実行した時のエラーは下記。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/usr/share/dotnet/sdk/8.0.401/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.targets(284,5): warning NETSDK1206: Found version-specific or distribution-specific runtime identifier(s): ubuntu.20.04-x64. Affected libraries: OpenCvSharp4_.runtime.ubuntu.20.04-x64. In .NET 8.0 and higher, assets for version-specific and distribution-specific runtime identifiers will not be found by default. See https://aka.ms/dotnet/rid-usage for details. [/home/t-takeuchi/Work/Demo/ComputerVision/OpenCV/C#/01_NetworkCapture/sources/Demo/Demo.csproj]
Unhandled exception. System.TypeInitializationException: The type initializer for 'OpenCvSharp.Internal.NativeMethods' threw an exception.
---> System.DllNotFoundException: Unable to load shared library 'OpenCvSharpExtern' or one of its dependencies. In order to help diagnose loading problems, consider using a tool like strace. If you're using glibc, consider setting the LD_DEBUG environment variable:
/usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.8/OpenCvSharpExtern.so: cannot open shared object file: No such file or directory
/usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.8/libOpenCvSharpExtern.so: cannot open shared object file: No such file or directory
/usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.8/OpenCvSharpExtern: cannot open shared object file: No such file or directory
/usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.8/libOpenCvSharpExtern: cannot open shared object file: No such file or directory

at OpenCvSharp.Internal.NativeMethods.redirectError(CvErrorCallback errCallback, IntPtr userdata, IntPtr& prevUserdata)
at OpenCvSharp.Internal.ExceptionHandler.RegisterExceptionCallback()
at OpenCvSharp.Internal.NativeMethods.LoadLibraries(IEnumerable`1 additionalPaths)
at OpenCvSharp.Internal.NativeMethods..cctor()
--- End of inner exception stack trace ---
at OpenCvSharp.Internal.NativeMethods.core_Mat_new1(IntPtr& returnValue)
at OpenCvSharp.Mat..ctor()
at Demo.Program.Main(String[] args) in /home/t-takeuchi/Work/Demo/ComputerVision/OpenCV/C#/01_NetworkCapture/sources/Demo/Program.cs:line 26

How to resolve?

RID の使用 に記載がある。

RID を使用するには、どのような RID があるのか知る必要があります。 最新の完全なバージョンについては、dotnet/runtime リポジトリの PortableRuntimeIdentifierGraph.json を参照してください。
‘移植可能’ とみなされる RID、つまり特定のバージョンや OS ディストリビューションに関連付けられていない RID が推奨される選択肢です。 これは、プラットフォーム固有のアプリケーションの構築と、RID 固有のアセットを含む NuGet パッケージの作成の両方にポータブル RID を使用する必要があることを意味します。
.NET 8 以降、.NET SDK およびランタイムの既定の動作では、バージョン固有およびディストリビューション固有ではない RID のみが考慮されます。 復元およびビルドする場合、SDK は小さいポータブル RID グラフを使用します。 RuntimeInformation.RuntimeIdentifier は、ランタイムが構築されたプラットフォーム を返します。 実行時に、.NET は既知のポータブル RID セットを使用して RID 固有のアセットを検索します。 実行時に無視される可能性がある RID 固有のアセットを含むアプリケーションをビルドする場合、SDK は警告 NETSDK1206 を発行します。

問題は、使っている OpenCvSharp のパッケージに問題があった。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NLog" Version="5.0.0" />
<PackageReference Include="OpenCvSharp4" Version="4.9.0.20240103" />
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.9.0.20240103" />
<PackageReference Include="OpenCvSharp4_.runtime.ubuntu.20.04-x64" Version="4.9.0.20240103" />
</ItemGroup>

<ItemGroup>
<None Update="NLog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>

前述の OS ディストリビューション というのが答えで、 OpenCvSharp4_.runtime.ubuntu.20.04-x64 のような、特定の OS ディストリビューション (ここでは ubuntu.20.04) を使うのがまずいということ。
この問題を解決するには

まず、前者はプロジェクトファイルに下記を追加する。

1
2
3
<ItemGroup>
<RuntimeHostConfigurationOption Include="System.Runtime.Loader.UseRidGraph" Value="true" />
</ItemGroup>

これで実行時にエラーが表示されなくなる。

後者については

1
2
- <PackageReference Include="OpenCvSharp4_.runtime.ubuntu.22.04-x64" Version="4.9.0.20240103" />
+ <PackageReference Include="OpenCvSharp4.runtime.linux-x64" Version="4.10.0.20240717" />

のゆうにすれば、上手くいくかと思ったが、結果的にはうまくいかなかった。
NETSDK1206 の警告は消えたが、実行時エラー。
libIlmImf-2_5.so.25 が存在しないせいだが、問題が起きた環境が Ubuntu 20.04 のため、 libIlmImf を含むパッケージである libopenexr がバージョン 24 であり対応できない。

前者の方法で対応することができたので、事なきを得たが…しかたない。