Skip to content

Instantly share code, notes, and snippets.

@kezunlin
Last active November 2, 2018 09:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kezunlin/8a8f1be7c0e101ce3f0e16e529288afc to your computer and use it in GitHub Desktop.
Save kezunlin/8a8f1be7c0e101ce3f0e16e529288afc to your computer and use it in GitHub Desktop.
opencv mat for loop
#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