はじめに
- 本記事はOpenCV Advent Calendar 2022 の15日目の記事です。
- 14日目の記事は@osataさんによるOpenCVで面積を計算してみた on iOSです。是非お読み下さい。
- 周囲長のピクセル数だけ面積の誤差が発生するから、2.7%の誤差はまぁそんなところではないか、あとは画素数増やすのが良いのではという気がしますが、iPhoneだからカメラは変わらないんだよな
- その他の記事は目次をご覧ください。
- アドベントカレンダーが空いていたので、しょうもない記事で埋めます。
よみとく
- 今年は業務でPythonを
使わざるを得ず使い、opencv-python
もpip
でインストールしました。Python大嫌いなのに - インストールされたパッケージがどんなものか、ソースコードを読まずに紐解いてみましょう。
> pytyon
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 17:00:18) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
- 環境は以下のとおりです
- Windows 11
- Pythonは3.6.5
- OpenCVは4.6.0
- pipのパッケージはopencv-python 4.6.0.66
- さて、OpenCV内部の情報を見るためには
OPENCV_DUMP_CONFIG
変数を設定します。bash
とかなら簡単ですが、コマンドプロンプトでも可能です。
>set OPENCV_DUMP_CONFIG=1
>echo %OPENCV_DUMP_CONFIG%
1
-
OPENCV_DUMP_CONFIG
変数の中身は空っぽでなければ何でも大丈夫です。詳しくは何年か前の記事で書きました - さて、ここのあとPythonから
import cv2
をやってみましょう。
>python
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 17:00:18) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
OpenCV build configuration is:
General configuration for OpenCV 4.6.0 =====================================
Version control: 4.6.0
Platform:
Timestamp: 2022-06-07T10:17:42Z
Host: Windows 10.0.17763 AMD64
CMake: 3.22.5
CMake generator: Visual Studio 14 2015
CMake build tool: MSBuild.exe
MSVC: 1900
Configuration: Debug Release
CPU/HW features:
Baseline: SSE SSE2 SSE3
requested: SSE3
Dispatched code generation: SSE4_1 SSE4_2 FP16 AVX AVX2
requested: SSE4_1 SSE4_2 AVX FP16 AVX2 AVX512_SKX
SSE4_1 (16 files): + SSSE3 SSE4_1
SSE4_2 (1 files): + SSSE3 SSE4_1 POPCNT SSE4_2
FP16 (0 files): + SSSE3 SSE4_1 POPCNT SSE4_2 FP16 AVX
AVX (4 files): + SSSE3 SSE4_1 POPCNT SSE4_2 AVX
AVX2 (31 files): + SSSE3 SSE4_1 POPCNT SSE4_2 FP16 FMA3 AVX AVX2
C/C++:
Built as dynamic libs?: NO
C++ standard: 11
C++ Compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/x86_amd64/cl.exe (ver 19.0.24245.0)
C++ flags (Release): /DWIN32 /D_WINDOWS /W4 /GR /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS /Gy /bigobj /Oi /fp:precise /EHa /wd4127 /wd4251 /wd4324 /wd4275 /wd4512 /wd4589 /MP /MT /O2 /Ob2 /DNDEBUG
C++ flags (Debug): /DWIN32 /D_WINDOWS /W4 /GR /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS /Gy /bigobj /Oi /fp:precise /EHa /wd4127 /wd4251 /wd4324 /wd4275 /wd4512 /wd4589 /MP /MTd /Zi /Ob0 /Od /RTC1
C Compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/x86_amd64/cl.exe
C flags (Release): /DWIN32 /D_WINDOWS /W3 /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS /Gy /bigobj /Oi /fp:precise /MP /MT /O2 /Ob2 /DNDEBUG
C flags (Debug): /DWIN32 /D_WINDOWS /W3 /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS /Gy /bigobj /Oi /fp:precise /MP /MTd /Zi /Ob0 /Od /RTC1
Linker flags (Release): /machine:x64 /NODEFAULTLIB:atlthunk.lib /INCREMENTAL:NO /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:libcpmtd.lib /NODEFAULTLIB:msvcrtd.lib
Linker flags (Debug): /machine:x64 /NODEFAULTLIB:atlthunk.lib /debug /INCREMENTAL /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libcpmt.lib /NODEFAULTLIB:msvcrt.lib
ccache: NO
Precompiled headers: YES
Extra dependencies: wsock32 comctl32 gdi32 ole32 setupapi ws2_32
3rdparty dependencies: libprotobuf ade ittnotify libjpeg-turbo libwebp libpng libtiff libopenjp2 IlmImf zlib quirc ippiw ippicv
OpenCV modules:
To be built: calib3d core dnn features2d flann gapi highgui imgcodecs imgproc ml objdetect photo python3 stitching video videoio
Disabled: world
Disabled by dependency: -
Unavailable: java python2 ts
Applications: -
Documentation: NO
Non-free algorithms: NO
Windows RT support: NO
GUI: WIN32UI
Win32 UI: YES
VTK support: NO
Media I/O:
ZLib: build (ver 1.2.12)
JPEG: build-libjpeg-turbo (ver 2.1.2-62)
WEBP: build (ver encoder: 0x020f)
PNG: build (ver 1.6.37)
TIFF: build (ver 42 - 4.2.0)
JPEG 2000: build (ver 2.4.0)
OpenEXR: build (ver 2.3.0)
HDR: YES
SUNRASTER: YES
PXM: YES
PFM: YES
Video I/O:
DC1394: NO
FFMPEG: YES (prebuilt binaries)
avcodec: YES (58.134.100)
avformat: YES (58.76.100)
avutil: YES (56.70.100)
swscale: YES (5.9.100)
avresample: YES (4.0.0)
GStreamer: NO
DirectShow: YES
Media Foundation: YES
DXVA: YES
Parallel framework: Concurrency
Trace: YES (with Intel ITT)
Other third-party libraries:
Intel IPP: 2020.0.0 Gold [2020.0.0]
at: D:/a/opencv-python/opencv-python/_skbuild/win-amd64-3.6/cmake-build/3rdparty/ippicv/ippicv_win/icv
Intel IPP IW: sources (2020.0.0)
at: D:/a/opencv-python/opencv-python/_skbuild/win-amd64-3.6/cmake-build/3rdparty/ippicv/ippicv_win/iw
Lapack: NO
Eigen: NO
Custom HAL: NO
Protobuf: build (3.19.1)
OpenCL: YES (NVD3D11)
Include path: D:/a/opencv-python/opencv-python/opencv/3rdparty/include/opencl/1.2
Link libraries: Dynamic load
Python 3:
Interpreter: C:/hostedtoolcache/windows/Python/3.6.8/x64/python.exe (ver 3.6.8)
Libraries: C:/hostedtoolcache/windows/Python/3.6.8/x64/libs/python36.lib (ver 3.6.8)
numpy: C:/hostedtoolcache/windows/Python/3.6.8/x64/lib/site-packages/numpy/core/include (ver 1.13.3)
install path: python/cv2/python-3
Python (for build): C:/hostedtoolcache/windows/Python/2.7.18/x64/python.exe
Java:
ant: NO
JNI: C:/hostedtoolcache/windows/Java_Temurin-Hotspot_jdk/8.0.332-9/x64/include C:/hostedtoolcache/windows/Java_Temurin-Hotspot_jdk/8.0.332-9/x64/include/win32 C:/hostedtoolcache/windows/Java_Temurin-Hotspot_jdk/8.0.332-9/x64/include
Java wrappers: NO
Java tests: NO
Install to: D:/a/opencv-python/opencv-python/_skbuild/win-amd64-3.6/cmake-install
-----------------------------------------------------------------
>>>
- すごーく長いログが表示されました。これはOpenCVが初期化時に環境変数
OPENCV_DUMP_CONFIG
をチェックし、空でなければビルド時の情報を表示するように設定されています。-
cv2.getBuildInformation()
とやれば環境変数を設定しなくても情報が取れます
-
- さて、肝心のdispatchは中段ぐらいに書いてあります。
CPU/HW features:
Baseline: SSE SSE2 SSE3
requested: SSE3
Dispatched code generation: SSE4_1 SSE4_2 FP16 AVX AVX2
requested: SSE4_1 SSE4_2 AVX FP16 AVX2 AVX512_SKX
SSE4_1 (16 files): + SSSE3 SSE4_1
SSE4_2 (1 files): + SSSE3 SSE4_1 POPCNT SSE4_2
FP16 (0 files): + SSSE3 SSE4_1 POPCNT SSE4_2 FP16 AVX
AVX (4 files): + SSSE3 SSE4_1 POPCNT SSE4_2 AVX
AVX2 (31 files): + SSSE3 SSE4_1 POPCNT SSE4_2 FP16 FMA3 AVX AVX2
-
Baseline
: ここまでの情報はCPUでサポートされてる前提としています。- Intel製のCPUであれば、最近のハイエンドモデルであればだいたいAVX2までサポートしているのですが、それ以外のモデルですと一部SSE3止まりのものもあり、OpenCVのデフォルトのコンフィグではSSE3までがBaselineに設定されます。
-
opencv-python
はどうもデフォルトの設定でビルドしているようです。
-
requested
: このラインに書かれてるのがコンフィグ時に渡されたbaselineです。-
SSE
のSIMD命令はSSE
→SSE2
→SSE3
と制定されましたので、SSE3
が使えるHWの場合SSE
とSSE2
もサポートされるという前提のもと、前述のBaseline
の情報が構成されます。
-
-
Dispatched code generation
: ここにdispatch
される命令の種類が書かれます。SSE4.1、SSE4.2、AVX、AVX2、およびFP16ですね。- なお、こいつら命令は一部包含関係になっており、それが続く行に書かれています。
-
requested
: にはSSE4_1
、SSE4_2
、AVX
、FP16
、AVX2
、AVX512_SKX
の5つが書かれています。-
AVX512_SKX
はコンフィグで指定しましたが、おそらくコンパイラが対応していないため除外されました。
-
- 注目はFP16とAVXの行です。
FP16 (0 files): + SSSE3 SSE4_1 POPCNT SSE4_2 FP16 AVX
AVX (4 files): + SSSE3 SSE4_1 POPCNT SSE4_2 AVX
AVX2 (31 files): + SSSE3 SSE4_1 POPCNT SSE4_2 FP16 FMA3 AVX AVX2
- この行は左側に命令セット、右側にはその際に前提として有効化される命令セットがあります。
- FP16を有効にした場合、AVXも有効化されますが、AVXだけを有効化した場合はFP16は有効になりません。
- 同様にAVX2を有効にした場合はFP16、AVXに加えFMA3も有効になります。
- 不思議なのは
FP16 (0 files)
と、0になってるのは不思議です。ここはいくつのファイルでdispatchが有効になったか、ファイル数が表示されるのですが、なんで0なのか今度詳しく追ってみましょう。- (追記): 追ってみたので、後述します
To be built: calib3d core dnn features2d flann gapi highgui imgcodecs imgproc ml objdetect photo python3 stitching video videoio
- この行に書かれてるのはビルドされたモジュール群です。CUDA関連のモジュールも入ってないですし、そもそもcontribモジュールも入っていません。
- contribに含まれるモジュール(CUDA関連、aruco、freetypeやsfmなど)をpythonから使いたい場合はビルドする必要があります。
- なお、コメントで指摘されたように、opencv-contrib-pythonパッケージを使うことでビルドを迂回できる場合があります。
contribモジュールを使いたい場合はopencv-contrib-pythonパッケージを使えば良い場合もあると思います。
追記:) FP16のファイルが0個なのを深追いしてみたらやっぱり使われてなかった
- 前述の通り、dispatchの項目の
FP16
には(0 files)
と書かれています。 - このファイルのカウントはCMakeLists.txt にかかれている拡張命令を集計したものになります
CMakeLists.txt
ocv_add_dispatched_file(arithm SSE2 SSE4_1 AVX2 VSX3)
ocv_add_dispatched_file(convert SSE2 AVX2 VSX3)
ocv_add_dispatched_file(convert_scale SSE2 AVX2)
ocv_add_dispatched_file(count_non_zero SSE2 AVX2)
- これはcoreモジュールに記載されているオプションですが、たしかにFP16というキーワードはどこにも現れていません。
- 本来なら、
convert.dispatch.cpp
内でFP32(float)
←→FP16(half)
の変換が行われるため、ここにFP16と書いてあるべきですが、書いてありません。 - 一方で、
convert.simd.hpp
を見てみると、他の型の変換もこのファイル内で行われていることがわかります。
convert.simd.hpp
BinaryFunc getConvertFunc(int sdepth, int ddepth)
{
static BinaryFunc cvtTab[][8] =
{
{
(cvt8u), (cvt8s8u), (cvt16u8u),
(cvt16s8u), (cvt32s8u), (cvt32f8u),
(cvt64f8u), (cvt16f8u)
},
{
:
},
{
(cvt8u16f), (cvt8s16f), (cvt16u16f), (cvt16s16f),
(cvt32s16f), (cvt32f16f), (cvt64f16f), (cvt16u)
}
};
- この
getConvertFunc
には各型から各型への変換関数が並べられています。- 例えば
cvt16u8u
は、CV_16U
をCV_8U
へ、つまりunsigned short
をunsigned char
に変換します - そして他の変換には
AVX2
命令が使われています
- 例えば
- さて、ここで不思議なことが浮かび上がります「何故FP16が書いておらず、AVX2が指定されているのか?」
- こちらは実装の大部分が重複するためだと推測されます
- FP16以外の変換関数はSSE2で書かれているため、FP16を指定すると、その他の関数はSSE2での実装が採用されます
- このとき、FP16の変換関数は2つだけ、その他の変換は7種類の2乗で49種類あります。
- 49種類の実装は単純にバイナリのサイズを肥大化させるだけですので、おそらくFP16フラグの場合の実装をスキップしてAVX2版だけにしたのだと思います
- 一応デメリットとしてAVX2命令非対応でAVX命令とFP16命令だけに対応しているCPUでは、FP16を有効にできない1
- というわけで
(0 Files)
って表記が気になったので追ってみたら、思いの外入り組んだ実装になってました、という取止めのない話 - 追記ここまで
おわりに
- というわけで、突発的にopencv-pythonのビルド情報を読み解く記事を書いて投稿しました。
- 明日は@okm_6880さんの記事でタイトルは上下の有るサンプルにおける回転角の取得についてです。お楽しみに!
-
筆者の先代の私物ラップトップがまさにそうでした。そしてそのラップトップでこの
convertFP16
関数のPRを書いたのに巡り巡って、、、、 ↩