#include <opencv2\opencv.hpp>
using namespace std;
using namespace cv;
void ScanImgaeAndReduceC(Mat &src, const uchar * const table, Mat &dst);
void ScanImageAndReduceIterator(Mat &src, const uchar * const table, Mat &dst);
void ScanImageAndReduceRandomAccess(Mat &src, const uchar * const table, Mat &dst);
void UseLUTFun(Mat &src, const uchar * const table, Mat &dst);
int main()
{
Mat src = imread("C:\\Users\\dell\\Desktop\\xin1.jpg", 1);
if (src.empty())
{
cout << "source image load failed." << endl;
return -1;
}
int dividewidth = 10;
//create look up table
uchar table[256];
for (int i = 0; i < 256; i++)
table[i] = (uchar)((i / dividewidth) * dividewidth);
Mat dst1;
ScanImgaeAndReduceC(src, table, dst1);
Mat dst2;
ScanImageAndReduceIterator(src, table, dst2);
Mat dst3;
ScanImageAndReduceRandomAccess(src, table, dst3);
Mat dst4;
UseLUTFun(src, table, dst4);
waitKey(0);
return 0;
}
//The efficient way to scan image
void ScanImgaeAndReduceC(Mat &src, const uchar * const table, Mat &dst)
{
double t = (double)getTickCount();
//accept only uchar type matrixs
CV_Assert(src.depth() == CV_8U);
cout << src.depth() << " " << sizeof(uchar) << endl;
int channels = src.channels();
int nRows = src.rows;
int nCols = src.cols * channels;
if (src.isContinuous())
{
nCols = nRows * nCols;
nRows = 1;
}
Mat I(src.size(), src.type());
for (int i = 0; i < nRows; i++)
{
uchar *pSrc = src.ptr<uchar>(i);
uchar *pI = I.ptr<uchar>(i);
for (int j = 0; j < nCols; j++)
pI[j] = table[pSrc[j]];
}
dst = I.clone();
double tt = ((double)getTickCount() - t) / getTickFrequency();
cout << "The efficient way cost time : " << tt << "s." << endl;
}
//The iterator(safe) method to scan image
void ScanImageAndReduceIterator(Mat &src, const uchar * const table, Mat &dst)
{
double t = (double)getTickCount();
CV_Assert(src.depth() == CV_8U);
int nchannels = src.channels();
Mat I = src.clone();
switch (nchannels)
{
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]];
}
}
}
dst = I.clone();
double tt = ((double)getTickCount() - t) / getTickFrequency();
cout << "The iterator(safe) method cost time : " << tt << "s." << endl;
}
//On the fly address calculation with reference returning
void ScanImageAndReduceRandomAccess(Mat &src, const uchar * const table, Mat &dst)
{
double t = (double)getTickCount();
CV_Assert(src.depth() == CV_8U);
int nchannels = src.channels();
Mat I = src.clone();
switch (nchannels)
{
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;
}
}
dst = I.clone();
double tt = ((double)getTickCount() - t) / getTickFrequency();
cout << "On the fly address calculation cost time : " << tt << "s." << endl;
}
//Use LUT function
void UseLUTFun(Mat &src, const uchar * const table, Mat &dst)
{
CV_Assert(src.depth() == CV_8U);
Mat LoopUpTable(1, 256, CV_8U);
uchar *p = LoopUpTable.data;
for (int i = 0; i < 256; i++)
p[i] = table[i];
double t = (double)getTickCount();
LUT(src, LoopUpTable, dst);
double tt = ((double)getTickCount() - t) / getTickFrequency();
cout << "Use LUT function cost time : " << tt << "s." << endl;
}
注意,教程原版中CV_Assert(src.depth() != sizeof(uchar));这句话有误,输出观察一下,src.depth() = 0,表示的是CV_8U,而sizeof(uchar) = 1,表示uchar类型占1位,这个判断只能表示如果src.depth()!=1(CV_8S),断言就不会启用。src.depth()!=1,有可能是CV_16U、CV_32S等,并不能保证一定是CV_8U。看来即使是官方教程,也有可能出现错误。