四種Opencv的元素訪問方式時間對比
- 指針訪問方式和 at 方式沒有多大差別
- 最快的訪問方式是使用 最新的 forEach 可以調用多核並行
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
#define OPENCV_ORIGINAL 0
#define OPENCV_BLOG 1
// Define a pixel
typedef Point3_<uchar> Pixel;
// A complicated threshold is defined so
// a non-trivial amount of computation
// is done at each pixel.
void complicatedThreshold(Pixel &pixel)
{
if (pow(double(pixel.x) / 10, 2.5) > 100)
{
pixel.x = 255;
pixel.y = 255;
pixel.z = 255;
}
else
{
pixel.x = 0;
pixel.y = 0;
pixel.z = 0;
}
}
int main()
{
#if OPENCV_ORIGINAL
Mat image(1920, 1080, CV_8UC3);
typedef cv::Point3_<uchar> Pixel;
// first. raw pointer access.
for (int r = 0; r < image.rows; ++r)
{
Pixel* ptr = image.ptr<Pixel>(r, 0);
const Pixel* ptr_end = ptr + image.cols;
for (; ptr != ptr_end; ++ptr)
{
ptr->x = 255;
}
}
// Using MatIterator. (Simple but there are a Iterator's overhead)
for (Pixel &p : cv::Mat_<Pixel>(image))
{
p.x = 255;
}
// Parallel execution with function object.
struct Operator
{
void operator ()(Pixel &pixel, const int * position)
{
pixel.x = 255;
}
};
image.forEach<Pixel>(Operator());
// Parallel execution using C++11 lambda.
image.forEach<Pixel>([](Pixel &p, const int * position) -> void
{
p.x = 255;
});
#endif // OPENCV_ORIGINAL
cv::Mat image = cv::imread("D:/testpic/1-1304031A126.jpg");
#if OPENCV_BLOG
//1. 第一種訪問情況
double t = (double)getTickCount();
// Naive pixel access
// Loop over all rows
for (size_t i = 0; i < 10; i++)
{
for (int r = 0; r < image.rows; r++)
{
// Loop over all columns
for (int c = 0; c < image.cols; c++)
{
// Obtain pixel at (r, c)
Pixel pixel = image.at<Pixel>(r, c);
// Apply complicatedTreshold
complicatedThreshold(pixel);
// Put result back
image.at<Pixel>(r, c) = pixel;
}
}
}
t = (double)getTickCount() - t;
std::cout << "Naive pixel access time = " << t*1000. / cv::getTickFrequency() << std::endl;
//2. 第二種訪問情況
t = (double)getTickCount();
// Using pointer arithmetic
// Get pointer to first pixel
for (size_t i = 0; i < 10; i++)
{
Pixel* pixel = image.ptr<Pixel>(0, 0);
// Mat objects created using the create method are stored
// in one continous memory block.
const Pixel* endPixel = pixel + image.cols * image.rows;
// Loop over all pixels
for (; pixel != endPixel; pixel++)
{
complicatedThreshold(*pixel);
}
}
t = (double)getTickCount() - t;
std::cout << "Using pointer arithmetic = " << t*1000. / cv::getTickFrequency() << std::endl;
//3. 第三種訪問情況
t = (double)getTickCount();
// Parallel execution with function object.
struct Operator
{
void operator ()(Pixel &pixel, const int * position) const
{
// Perform a simple threshold operation
complicatedThreshold(pixel);
}
};
for (size_t i = 0; i < 10; i++)
{
// Call forEach
image.forEach<Pixel>(Operator());
}
t = (double)getTickCount() - t;
std::cout << "Parallel execution with function object. = " << t*1000. / cv::getTickFrequency() << std::endl;
//4. 第四種訪問情況
//Some of you are looking at Method 3, shaking your head in disgust and shouting, “lambda, Lambda, LAMBDA!”
t = (double)getTickCount();
for (size_t i = 0; i < 10; i++)
{
image.forEach<Pixel>
(
[](Pixel &pixel, const int * position) -> void
{
complicatedThreshold(pixel);
}
);
}
t = (double)getTickCount() - t;
std::cout << "lambda = " << t*1000. / cv::getTickFrequency() << std::endl;
#endif // OPENCV_BLOG
return system("pause");
}
Reference
http://www.learnopencv.com/parallel-pixel-access-in-opencv-using-foreach/