Last active
April 29, 2022 06:01
-
-
Save kazuki-ma/8285876 to your computer and use it in GitHub Desktop.
test code for cv::Mat::forEach
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <opencv2/core.hpp> | |
typedef cv::Point3_<uint8_t> Pixel; | |
typedef cv::Mat_<Pixel> MatT; | |
const cv::Size SIZE_FULL_HD(1920, 1020); | |
void ShowResult(const std::string name, const double time) { | |
std::cout << cv::format("%40s | %20.10f", name.c_str(), time) << std::endl; | |
return; | |
} | |
void bench(const std::string func_name, void func(MatT&), const int time) { | |
MatT img(SIZE_FULL_HD); | |
img *= 0; | |
const uint64_t start = cv::getCPUTickCount(); | |
for (int count = 0; count < time; ++count) { | |
func(img); | |
} | |
const uint64_t end = cv::getCPUTickCount(); | |
const double time_elapsed = (end - start) / cv::getTickFrequency() / time; | |
ShowResult(func_name, time_elapsed); | |
} | |
inline void iterator_access(MatT& frame) { | |
auto it = frame.begin(); | |
for (auto &p : frame) { | |
p.x = 255; | |
} | |
} | |
inline void pointer_access(MatT& frame) { | |
auto p = reinterpret_cast<Pixel*>(frame.data); | |
const auto e = p + frame.cols * frame.rows; | |
while (p < e) | |
{ | |
p->x = 255; | |
++p; | |
} | |
} | |
inline void forEach_access(MatT& frame) { | |
auto mat = cv::Mat_<Pixel>(frame); | |
mat.forEach([&](Pixel &p, const void*) -> void{ | |
p.x = 255; | |
}); | |
} | |
#define BENCH(func_name) \ | |
bench(#func_name, func_name, times); | |
int main(const int an, const char* const* const as) | |
{ | |
#ifdef _DEBUG | |
const int times = 1; | |
#else | |
const int times = 1000; | |
#endif | |
BENCH(iterator_access); | |
BENCH(pointer_access); | |
BENCH(forEach_access); | |
} |
・画像は continuous (n行目の終わりと、n+1行目の初めがメモリ上隣にある)前提
・OpenCV 3.0 実装では、 forEach を使っただけで parallel になります。
が、一方で、最終的なマージ結果では、2.0 → 0.3 のような極端な高速化は無いかも……
(ループアンローリングをやめてしまったので)
基本的に、処理が重い Functor であれば、コア数に比例してスケールします。
(CPU⇔Memory の帯域がボトルネックの場合などを除く)
テンプレートの中で渡された functor を ParallelLoopBody でラップし、
cv::parallel_for_ 経由で実行しています。
functor を ParallelLoopBodyでラップする処理は、
コンパイラでインライン変換されることを期待して書いています。
そのため、コンパイラが、functor の実装を特定出来る場合(一番いいのは、その場で ラムダ式を渡す)、
functor はインライン展開されます。
(http://d.hatena.ne.jp/mickey24/20110211/stl_algorithms_and_functors)
最近のコンパイラは、関数ポインタ渡された場合でも、
取り得る値が1種類のみと分かれば、インライン展開してくれるらしいです。
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
my result