📆
C++で2値化処理を高速化してOpenCVと比較してみた
C++で2値化処理を実装し、処理速度の比較を行いました。
今回はOpenCV標準実装(cv::threshold)と自作実装(分岐あり/分岐なし/LUT/SIMD + OpenMP)を比較します。
概要
画像の2値化処理は単純に見えますが、
実装方法によって 実行時間に大きな差が生じます。
本プロジェクトでは以下の実装を比較します
- 分岐あり(三項演算子)
- 分岐なし実装
- LUT (ルックアップテーブル)
- SIMD + OpenMP (自作)
- OpenCV (cv::threshold)
AVX2有効環境での実測結果を通して、
CPU最適化がどこまで効くのかを検証します。
実行環境
- CPU: Intel Core Ultra 7 265KF
- OS: Windows 11
- Compiler: MSVC 19.50
- Build: Release
- SIMD: AVX2
- Parallel: OpenMP
プロジェクト
ソースコードを含むプロジェクトはこちらにアップロードしました。
ビルド方法
1. vcpkgの準備
git clone https://github.com/microsoft/vcpkg.git C:/tools/vcpkg
cd C:/tools/vcpkg
bootstrap-vcpkg.bat
※ C:/tools/vcpkg は例です。
別の場所に置く場合は後述のCMAKE_TOOLCHAIN_FILEを変更してください。
2. リポジトリのクローン
git clone https://github.com/yourname/2BinProcessSpeedComp.git
cd 2BinProcessSpeedComp
3. CMake Presetを使用してビルド
Visual Studio を使う場合はリポジトリのルートフォルダを開き、
vcpkg-x64-release
を選択してビルドを開始してください。
※ 初回ビルド時にvcpkgが自動でOpenCVをインストールします。
※ .slnまたは.slnxファイルは作成されません(CMakeプロジェクトの正常な挙動です)
4. コマンドラインでビルドする場合
cmake -S . -B out/build/vcpkg-x64-release -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=C:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows
cmake --build out/build/vcpkg-x64-release
5. 実行
out/build/vcpkg-x64-release/2BinProcessSpeedComp/2BinProcessSpeedComp.exe
vcpkgが見つからない場合
CMAKE_TOOLCHAIN_FILEのパスを自分のvcpkgの場所に合わせて修正してください。
CMAKE_TOOLCHAIN_FILE not found
実行結果
AVX2 enabled
[分岐あり] 629256700 ns
[分岐なし] 646292400 ns
[LUT] 479005500 ns
[SIMD+OpenMP] 32230600 ns
[OpenCV] 45822200 ns
sink=623475
考察
SIMD+OpenMPが最速という結果になりました。
OpenCVが最も早いと思っていましたが、自作のほうが早かったのは意外でした。
OpenCVは汎用ライブラリとして多様な入力条件・型に対応するための処理が含まれています。
一方自作実装では条件を限定することで分岐や汎用処理を排除できたため、この差が性能に表れたものと推測します。
詳細はこちら
Discussion
↑に対して
↑が桁違いに遅いのは自動ベクター化が働いていないのが大きい気がします。
↑に対して
↑で1.3倍位になってるのも適正に最適化指示がされてればそんな差が出るはずがない気がして違和感あるのでコンパイラへの最適化指示を確認された上でコンパイラの出力コードを確認されると良いと思います。その辺りされないで「なんか速かった(遅かった)」という感想レベルで終わらせてしまうのはもったいないと思いますね。
コメントありがとうございます!
ご指摘の通り、分岐あり/なし/LUTについては自動ベクター化が効いていない可能性が高そうです。
今回の検証はアルゴリズムの差による比較でしたがコンパイラの最適化まで深堀すれば違った結果が見えてくるかもしれません。
次回はその観点でも検証してみたいです!