Last active
November 2, 2018 09:03
-
-
Save kezunlin/8a8f1be7c0e101ce3f0e16e529288afc to your computer and use it in GitHub Desktop.
opencv mat for loop
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 <stdio.h> | |
#include <iostream> | |
#pragma warning( disable: 4819 ) | |
#pragma warning( disable: 4244 ) | |
#pragma warning( disable: 4267 ) | |
#include "opencv2/core.hpp" | |
#include "opencv2/imgproc.hpp" | |
#include "opencv2/features2d.hpp" | |
#include "opencv2/highgui.hpp" | |
#include "opencv2/calib3d.hpp" | |
#include <boost/date_time/posix_time/posix_time.hpp> | |
using namespace std; | |
using namespace cv; | |
//#define SAVE_IMAGE | |
uchar color_space_reduction(uchar pixel) | |
{ | |
/* | |
0-9 ===>0 | |
10-19===>10 | |
20-29===>20 | |
... | |
240-249===>24 | |
250-255===>25 | |
map from 256*256*256===>26*26*26 | |
*/ | |
int divideWith = 10; | |
uchar new_pixel = (pixel / divideWith)*divideWith; | |
return new_pixel; | |
} | |
void get_color_table() | |
{ | |
// cache color value in table[256] | |
int divideWith = 10; | |
uchar table[256]; | |
for (int i = 0; i < 256; ++i) | |
table[i] = divideWith* (i / divideWith); | |
} | |
// C ptr []: faster but not safe | |
Mat& ScanImageAndReduce_Cptr(Mat& I, const uchar* const table) | |
{ | |
// accept only char type matrices | |
CV_Assert(I.depth() != sizeof(uchar)); | |
int channels = I.channels(); | |
int nRows = I.rows; | |
int nCols = I.cols* channels; | |
if (I.isContinuous()) | |
{ | |
nCols *= nRows; | |
nRows = 1; | |
} | |
int i, j; | |
uchar* p; | |
for (i = 0; i < nRows; ++i) | |
{ | |
p = I.ptr<uchar>(i); | |
for (j = 0; j < nCols; ++j) | |
{ | |
p[j] = table[p[j]]; | |
} | |
} | |
return I; | |
} | |
// C ptr ++: faster but not safe | |
Mat& ScanImageAndReduce_Cptr2(Mat& I, const uchar* const table) | |
{ | |
// accept only char type matrices | |
CV_Assert(I.depth() != sizeof(uchar)); | |
int channels = I.channels(); | |
int nRows = I.rows; | |
int nCols = I.cols* channels; | |
if (I.isContinuous()) | |
{ | |
nCols *= nRows; | |
nRows = 1; | |
} | |
uchar* start = I.ptr<uchar>(0); // same as I.ptr<uchar>(0,0) | |
uchar* end = start + nRows * nCols; | |
for (uchar* p=start; p < end; ++p) | |
{ | |
*p = table[*p]; | |
} | |
return I; | |
} | |
// at<uchar>(i,j): random access, slow | |
Mat& ScanImageAndReduce_atRandomAccess(Mat& I, const uchar* const table) | |
{ | |
// accept only char type matrices | |
CV_Assert(I.depth() != sizeof(uchar)); | |
const int channels = I.channels(); | |
switch (channels) | |
{ | |
case 1: | |
{ | |
for (int i = 0; i < I.rows; ++i) | |
for (int j = 0; j < I.cols; ++j) | |
I.at<uchar>(i, j) = table[I.at<uchar>(i, j)]; | |
break; | |
} | |
case 3: | |
{ | |
Mat_<Vec3b> _I = I; | |
for (int i = 0; i < I.rows; ++i) | |
for (int j = 0; j < I.cols; ++j) | |
{ | |
_I(i, j)[0] = table[_I(i, j)[0]]; | |
_I(i, j)[1] = table[_I(i, j)[1]]; | |
_I(i, j)[2] = table[_I(i, j)[2]]; | |
} | |
I = _I; | |
break; | |
} | |
} | |
return I; | |
} | |
// MatIterator_<uchar>: safe but slow | |
Mat& ScanImageAndReduce_Iterator(Mat& I, const uchar* const table) | |
{ | |
// accept only char type matrices | |
CV_Assert(I.depth() != sizeof(uchar)); | |
const int channels = I.channels(); | |
switch (channels) | |
{ | |
case 1: | |
{ | |
MatIterator_<uchar> it, end; | |
for (it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it) | |
*it = table[*it]; | |
break; | |
} | |
case 3: | |
{ | |
MatIterator_<Vec3b> it, end; | |
for (it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it) | |
{ | |
(*it)[0] = table[(*it)[0]]; | |
(*it)[1] = table[(*it)[1]]; | |
(*it)[2] = table[(*it)[2]]; | |
} | |
} | |
} | |
return I; | |
} | |
// LUT | |
Mat& ScanImageAndReduce_LUT(Mat& I, const uchar* const table) | |
{ | |
Mat lookUpTable(1, 256, CV_8U); | |
uchar* p = lookUpTable.data; | |
for (int i = 0; i < 256; ++i) | |
p[i] = table[i]; | |
cv::LUT(I, lookUpTable, I); | |
return I; | |
} | |
#pragma region forEach | |
// Parallel execution with function object. | |
struct ForEachOperator | |
{ | |
uchar m_table[256]; | |
ForEachOperator(const uchar* const table) | |
{ | |
for (size_t i = 0; i < 256; i++) | |
{ | |
m_table[i] = table[i]; | |
} | |
} | |
void operator ()(uchar& p, const int * position) const | |
{ | |
// Perform a simple operation | |
p = m_table[p]; | |
} | |
}; | |
// forEach use multiple processors, very fast | |
Mat& ScanImageAndReduce_forEach(Mat& I, const uchar* const table) | |
{ | |
I.forEach<uchar>(ForEachOperator(table)); | |
return I; | |
} | |
// forEach lambda use multiple processors, very fast (lambda slower than ForEachOperator) | |
Mat& ScanImageAndReduce_forEach_with_lambda(Mat& I, const uchar* const table) | |
{ | |
I.forEach<uchar> | |
( | |
[=](uchar &p, const int * position) -> void | |
{ | |
p = table[p]; | |
} | |
); | |
return I; | |
} | |
#pragma endregion | |
void test_cptr(Mat& image, const uchar* const table, int times) | |
{ | |
int64_t total_cost = 0; | |
for (size_t i = 0; i < times; i++) | |
{ | |
boost::posix_time::ptime pt1 = boost::posix_time::microsec_clock::local_time(); | |
image = ScanImageAndReduce_Cptr(image, table); | |
boost::posix_time::ptime pt2 = boost::posix_time::microsec_clock::local_time(); | |
int64_t cost = (pt2 - pt1).total_milliseconds(); | |
total_cost += cost; | |
#ifdef SAVE_IMAGE | |
cv::imwrite("./1_cptr.jpg", image); | |
#endif // SAVE_IMAGE | |
} | |
std::cout << "[1 Cptr] times=" << times << ", total_cost=" << total_cost << " ms, avg_cost=" << total_cost / (times*1.0) << " ms \n"; | |
} | |
void test_cptr2(Mat& image, const uchar* const table, int times) | |
{ | |
int64_t total_cost = 0; | |
for (size_t i = 0; i < times; i++) | |
{ | |
boost::posix_time::ptime pt1 = boost::posix_time::microsec_clock::local_time(); | |
image = ScanImageAndReduce_Cptr2(image, table); | |
boost::posix_time::ptime pt2 = boost::posix_time::microsec_clock::local_time(); | |
int64_t cost = (pt2 - pt1).total_milliseconds(); | |
total_cost += cost; | |
#ifdef SAVE_IMAGE | |
cv::imwrite("./1_cptr2.jpg", image); | |
#endif // SAVE_IMAGE | |
} | |
std::cout << "[1 Cptr2] times=" << times << ", total_cost=" << total_cost << " ms, avg_cost=" << total_cost / (times*1.0) << " ms \n"; | |
} | |
void test_at_random_access(Mat& image, const uchar* const table, int times) | |
{ | |
int64_t total_cost = 0; | |
for (size_t i = 0; i < times; i++) | |
{ | |
boost::posix_time::ptime pt1 = boost::posix_time::microsec_clock::local_time(); | |
image = ScanImageAndReduce_atRandomAccess(image, table); | |
boost::posix_time::ptime pt2 = boost::posix_time::microsec_clock::local_time(); | |
int64_t cost = (pt2 - pt1).total_milliseconds(); | |
total_cost += cost; | |
#ifdef SAVE_IMAGE | |
cv::imwrite("./1_at_random.jpg", image); | |
#endif // SAVE_IMAGE | |
} | |
std::cout << "[2 atRandom] times=" << times << ", total_cost=" << total_cost << " ms, avg_cost=" << total_cost / (times*1.0) << " ms \n"; | |
} | |
void test_iterator(Mat& image, const uchar* const table, int times) | |
{ | |
int64_t total_cost = 0; | |
for (size_t i = 0; i < times; i++) | |
{ | |
boost::posix_time::ptime pt1 = boost::posix_time::microsec_clock::local_time(); | |
image = ScanImageAndReduce_Iterator(image, table); | |
boost::posix_time::ptime pt2 = boost::posix_time::microsec_clock::local_time(); | |
int64_t cost = (pt2 - pt1).total_milliseconds(); | |
total_cost += cost; | |
#ifdef SAVE_IMAGE | |
cv::imwrite("./1_iterator.jpg", image); | |
#endif // SAVE_IMAGE | |
} | |
std::cout << "[3 Iterator] times=" << times << ", total_cost=" << total_cost << " ms, avg_cost=" << total_cost / (times*1.0) << " ms \n"; | |
} | |
void test_lut(Mat& image, const uchar* const table, int times) | |
{ | |
Mat lookUpTable(1, 256, CV_8U); | |
uchar* p = lookUpTable.data; | |
for (int i = 0; i < 256; ++i) | |
p[i] = table[i]; | |
int64_t total_cost = 0; | |
for (size_t i = 0; i < times; i++) | |
{ | |
boost::posix_time::ptime pt1 = boost::posix_time::microsec_clock::local_time(); | |
cv::LUT(image, lookUpTable, image); // LUT | |
boost::posix_time::ptime pt2 = boost::posix_time::microsec_clock::local_time(); | |
int64_t cost = (pt2 - pt1).total_milliseconds(); | |
total_cost += cost; | |
#ifdef SAVE_IMAGE | |
cv::imwrite("./1_lut.jpg", image); | |
#endif // SAVE_IMAGE | |
} | |
std::cout << "[4 LUT] times=" << times << ", total_cost=" << total_cost << " ms, avg_cost=" << total_cost / (times*1.0) << " ms \n"; | |
} | |
void test_for_each(Mat& image, const uchar* const table, int times) | |
{ | |
int64_t total_cost = 0; | |
for (size_t i = 0; i < times; i++) | |
{ | |
boost::posix_time::ptime pt1 = boost::posix_time::microsec_clock::local_time(); | |
image = ScanImageAndReduce_forEach(image, table); | |
boost::posix_time::ptime pt2 = boost::posix_time::microsec_clock::local_time(); | |
int64_t cost = (pt2 - pt1).total_milliseconds(); | |
total_cost += cost; | |
#ifdef SAVE_IMAGE | |
cv::imwrite("./1_foreach.jpg", image); | |
#endif // SAVE_IMAGE | |
} | |
std::cout << "[5 forEach] times=" << times << ", total_cost=" << total_cost << " ms, avg_cost=" << total_cost / (times*1.0) << " ms \n"; | |
} | |
void test_for_each_with_lambda(Mat& image, const uchar* const table, int times) | |
{ | |
int64_t total_cost = 0; | |
for (size_t i = 0; i < times; i++) | |
{ | |
boost::posix_time::ptime pt1 = boost::posix_time::microsec_clock::local_time(); | |
image = ScanImageAndReduce_forEach_with_lambda(image, table); | |
boost::posix_time::ptime pt2 = boost::posix_time::microsec_clock::local_time(); | |
int64_t cost = (pt2 - pt1).total_milliseconds(); | |
total_cost += cost; | |
#ifdef SAVE_IMAGE | |
cv::imwrite("./1_foreach_with_lambda.jpg", image); | |
#endif // SAVE_IMAGE | |
} | |
std::cout << "[5 forEach lambda] times=" << times << ", total_cost=" << total_cost << " ms, avg_cost=" << total_cost / (times*1.0) << " ms \n"; | |
} | |
int main(int argc, char const *argv[]) | |
{ | |
// table | |
int divideWith = 52; | |
uchar table[256]; | |
for (int i = 0; i < 256; ++i) | |
table[i] = divideWith* (i / divideWith); | |
// image | |
Mat image = cv::imread("./1.jpg", 0); | |
//cv::imshow("image", image); | |
//cv::waitKey(0); | |
std::cout << image.size() << std::endl; | |
if (image.isContinuous()) | |
{ | |
std::cout << " image is continuous. \n"; | |
} | |
bool no_foreach = true; | |
if (no_foreach) | |
{ | |
int times = 5000; | |
test_cptr(image, table, times); // ptr[i] | |
test_cptr2(image, table, times); // ptr++ | |
test_at_random_access(image, table, times); | |
test_iterator(image, table, times); | |
test_lut(image, table, times); | |
} | |
else { | |
int times = 20000; | |
test_for_each(image, table, times); | |
test_for_each_with_lambda(image, table, times); | |
} | |
std::cout << "Press enter to exit \n"; | |
char c; | |
cin >> c; | |
return 0; | |
} | |
/* | |
[2048 x 1024] | |
image is continuous. | |
[1 Cptr] times=5000, total_cost=988 ms, avg_cost=0.1976 ms | |
[1 Cptr2] times=5000, total_cost=1704 ms, avg_cost=0.3408 ms | |
[2 atRandom] times=5000, total_cost=9611 ms, avg_cost=1.9222 ms | |
[3 Iterator] times=5000, total_cost=20195 ms, avg_cost=4.039 ms | |
[4 LUT] times=5000, total_cost=899 ms, avg_cost=0.1798 ms | |
[1 Cptr] times=10000, total_cost=2425 ms, avg_cost=0.2425 ms | |
[1 Cptr2] times=10000, total_cost=3391 ms, avg_cost=0.3391 ms | |
[2 atRandom] times=10000, total_cost=20024 ms, avg_cost=2.0024 ms | |
[3 Iterator] times=10000, total_cost=39980 ms, avg_cost=3.998 ms | |
[4 LUT] times=10000, total_cost=103 ms, avg_cost=0.0103 ms | |
[5 forEach] times=200000, total_cost=199 ms, avg_cost=0.000995 ms | |
[5 forEach lambda] times=200000, total_cost=521 ms, avg_cost=0.002605 ms | |
[5 forEach] times=20000, total_cost=17 ms, avg_cost=0.00085 ms | |
[5 forEach lambda] times=20000, total_cost=23 ms, avg_cost=0.00115 ms | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment