はじめに
- 本記事はOpenCV Advent Calendar 2021 の9日目の記事です
- 昨日はsuo-takefumiさんの100行で作るARでした。
- 凹みや穴を重畳するのは良いデモでしたね
- 本日の記事はOpenCV使用時やビルド時に出てくるエラーメッセージについてです。
- OpenCVは、意味不明なエラーに遭遇することがあります。
- 公式のGithubのissueを眺めていると、明後日な投稿が多数あるのですが、そのうち「一目で原因がわかる」メッセージ達を集めてみました。
ビルド編
c++: internal compiler error: Segmentation fault (program cc1plus)
- 原因:ビルドマシンのメモリ量が足りない
- 対策:もっとメモリを積むか、
-j 1
を明示的につける - x86マシンだと潤沢にメモリを詰めるが、Raspberry Pi/Jetsonなどの組み込みボードだとメモリが枯渇することがたまに起きる。
- 「メッセージの通りコンパイラのバグだ!」「OpenCVのバグだ!」と騒ぐ人をたくさん見てきたけれど、メッセージの意図をちゃんと読む必要がある
- 通常、コンパイル時間を短くするために並列ビルドを行い、
-j 4
などして4コアで並列してビルドすることがある - このとき、メモリ使用量は並列処理数分だけ多く利用することになる
- また、OpenCV内の一部のソースコードたちも、マクロを多用していたりすると、単体のコンパイルでもメモリ使用量が跳ね上がったりする。
- メモリの使用量が逼迫している場合、GCC内でSegmentation faultが起きたり、カーネルにプロセスをkillされたりする
- 通常、コンパイル時間を短くするために並列ビルドを行い、
- という訳で、前述の対策に行き着く。
- また、
ccache
を使うのも、並列ビルドを可能にしながらもメモリ使用量を抑える良い手段(その代わりストレージが必要になる)
Duplicated modules NAMES has been found
- メッセージ文中のNAMESには特定のモジュールの名前が入る
- 原因:contrib付きでビルドする際に、本体側が3.4系列、contrib側がmasterだと発生する
- 対策:本体側、contrib側で同じブランチをチェックアウトする
- opencv_contribは、いわばOpenCVの2軍とも言うべき存在でまだ荒削りなmoduleだったり使用頻度の低いmoduleがcontribに格納される
- ときに、contribから本体は「昇格」があったり、逆の「降格」があったりする。その際、本体側とcontrib側でbranchの整合性が取れてないと、同じ名前のmoduleが両方に存在してしまう
- 結果、前述のエラーメッセージが以下のように発生する
core
> cudaarithm
> cudabgsegm
> cudacodec
: (以下続く)
- 3.4系列まではCUDA関連のモジュールは本体側にあったが、4系列でcontribに送られた。
- このため、このエラーで目にするモジュール名はCUDA関連のモジュールであろう。
- ただし、エラーが特徴的なので、すぐに見抜けるはず
fatal error: boostdesc_bgm.i: No such file or directory
- make時に発生する
- 原因:https通信に問題あり
-
xfeatures2d
モジュールのcmake時に、バックグラウンドでソースコード(分類器)のダウンロードが行われる - このとき、CMake内製の通信モジュールでhttps通信が行われる
- https通信に失敗しうる原因は主に2つ
- 1つはビルド時の環境がproxyなどを利用しており、一部のhttpsサイトを遮断している場合
- もう1つは、ソースコードからcmakeをビルドして、その際cmakeのbootstrapオプションに
--system-curl
をつけ忘れた場合 - いずれの場合もhttps通信に失敗し、ファイルがダウンロードされない。
- そしてダウンロードされてないファイルを参照するため、前述のエラーが発生する
- OpenCVのバグではないので、自身のネットワーク環境を調べよう
- なんでこういう仕組みになってるのかはわからないけれど、もしかしたらライセンス関係でこうなってるのやもしれぬ(未調査)
nvcc fatal Unsupported gpu architecture compute_xx
- 末尾の
xx
には数字が入る - 原因:CUDAのバージョンが希望のCCをサポートしていない
- 対策:新しいGPUを使いたいなら新しいCUDAにする。
Error generating /xxx/modules/core/CMakeFiles/cuda_compile_1.dir/src/cuda/./cuda_compile_1_generated_gpu_mat.cu.o
- 原因:ディスク容量不足
- 対処方法:/tmp/パーティションが載ってるディスクの容量を空ける
- CUDA関連のコードは/tmp/以下に一時的なファイルを生成する
- このファイルはときにGBオーダーのサイズになることがある
- Jetson Nanoを始めとして、SDカードの容量をケチったりしてると、/tmp/ のパーティションがいっぱいになることも多々見かける。
Required baseline optimization is not supported: VFPV3
- 原因:Aarch64上でのビルドで、
-DCPU_BASELINE=VFPV3
をつけている - 対処方法:
CPU_BASELINE
オプションは空にする -
CPU_BASELINE
オプションはCMake時に渡す - Aarch64で使えるオプションは現在(2021/12/1時点, OpenCV 3.4.16, 4.5.3)使えるのは
NEON
とFP16
のみ。- Armv7 では
VFPV3
も使えたが、VFPV3
はNEON
のサブセットとでも言うべき拡張であり、NEON
がAarch64 (Armv8)で標準命令セットに含まれた以上、VFPV3
だけ個別に指定する意味は無い - もっと言えば、
FP16
命令も標準命令に含まれているので、Aarch64はCPU_BASELINE
オプションを使う場面は無い - ただ、Apple M1を始め、オイシイ拡張命令がどんどんアクセスできるようになってるので、いずれOpenCVで拡張命令を使った実装がされる可能性が高い。
- なので、
CPU_BASELINE
オプションを指定して意味がある日が来るかもしれない。
- Armv7 では
実行時編
unresolved external "__declspec(dllimport) bool cv::__termination in DllMain"
- 筆者の過去記事参照
- 原因はOpenCV 4.0.0固有の既知のバグ
- OpenCV 4.0.0だけで起きる。3系列では起きないし、4.0.1ではFIXが含まれている
- 迂回策として、
cmake -DOPENCV_SKIP_DLLMAIN_GENERATION=ON ...
というようにOPENCV_SKIP_DLLMAIN_GENERATION
オプションを使う方法もある - このページに書いてある現象のうち、この現象だけはOpenCVのバグである。あとは環境か使い方の問題であることに注意。
OpenCL error CL_OUT_OF_RESOURCES (-5) during call: clEnqueueNDRangeKernel
- 環境によってはわんさかと遭遇するメッセージ
- これは
error
という文言を含んでいるが、エラーではない。OpenCLから出てくるメッセージ - 具体的には、使用しているOpenCLデバイスに対して、可能な容量以上の計算を投げると、OpenCL側でエラーを挙げる。このときコンソールに表示される画面が前述のメッセージ
- 一方で、OpenCV内ではOpenCL実行がコケた場合、自動的にCPU実装に切り替える1ので、見た目にはエラーに見えない。
OpenCV Error: Assertion failed (size.width>0 && size.height>0)
- 原因:ファイルのオープンに失敗している
- 解説:OpenCVでは、ファイル名を間違えていたり、存在しないファイルをオープンしようとしたり、またはパーミッションでオープンできなかった場合など、正しくファイルを開けなくても、実行時エラーを「投げない」
- 代わりに、ユーザはファイルが正しくオープンできたかどうか、
.empty()
メソッドを使って確認することを求められる - ファイルのオープンに失敗して、空っぽの
Mat
であることを確認せずにOpenCVのAPIに投げると、前述のような、様々な実行時エラーが投げられます。 - 直接の起因とエラーメッセージが対応してないのでわかりにくいですが、原因はファイルのオープンです。
- また、APIによって、Assertionが様々ですので、前述のメッセージ以外のメッセージが出ることがあります。気をつけましょう。
番外編
野良ビルドを多用した場合
- タイトルと趣旨が反するのですが、「不思議なことが起きたときの原因」の話です。
- 当時私が突き当たった環境はWindows 7、MSVC2015、OpenCVは3.0かそのあたりの話だったと思います。
- 現象としてはアクセス違反、確保した領域外にアクセスしていました。
- が、状況をよくよく調べると、「画像をopenしてロードする際、コンストラクタを通らずにいきなりallocateされてないメモリ領域に書き込もうとしてアクセス違反」という意味不明な状況でした。
- また、
imread
関数にわたすパラメータに依らずアクセス違反が発生しており、果たして原因は何なのか、途方にくれていました。
- 紐解けば簡単な話で、ビルド時に使ったlibファイルと、実行時に読み込まれるdllファイルが、違うバージョンだったのです
- 厳密にはバージョンはマイナーバージョンまで一致していたのですが、微妙なビルドオプションが違いました。
- 下手にマイナーバージョンが合っていたため、明示的にエラーが発生せず、関数callがへんてこな場所から開始していたためでした。
- 野良ビルド、気をつけましょう。
さいごに
- OpenCVのエラーメッセージは残念ながらお世辞にもわかりやすいとは言えません。
- このページにたどり着いた人が少しでも時間の無駄を減らせれば、と思います
- 明日は@fukushima1981先生の投稿で、執筆時点でのタイトルは「OpenCVによる特異値分解と最小二乗法」です。楽しみですね!
-
唯一
rgbd
モジュールのKinect Fusion関係のコードは、本エラーを正しくハンドリングしない。ぴえん。 ↩