转载自官方教程 https://docs.opencv.org/master/db/da5/tutorial_how_to_scan_images.html
分为三种不同的访问方式:
1. 通过Mat的ptr指针的[]操作符号,按照数组的方式遍历--->效率最高
2. 通过迭代器 cv::MatIterator_进行访问--->效率次之,但是是安全的
3. 不通过ptr指针,直接通过Mat进行访问--->效率最低, 不适合遍历操作,常用于随机位置的访问, "The final method isn't recommended for scanning. It was made to acquire or modify somehow random elements in the image."
#include <opencv2/core.hpp>
#include <opencv2/core/utility.hpp>
#include "opencv2/imgcodecs.hpp"
#include <opencv2/highgui.hpp>
#include <iostream>
#include <sstream>
cv::Mat& ScanImageAndReduceC(cv::Mat& I, const uchar* const table);
cv::Mat& ScanImageAndReduceIterator(cv::Mat& I, const uchar* const table);
cv::Mat& ScanImageAndReduceRandomAccess(cv::Mat& I, const uchar* const table);
int main(int argc, char** argv)
{
std::string imageName( "../data/lei.jpeg" ); // by default
//cv::imread(imageName, cv::IMREAD_COLOR);
cv::Mat I = cv::imread(imageName, cv::IMREAD_GRAYSCALE);
cv::Mat J;
int dividewith = 8;
uchar table[256];
for(int i=0; i<256; ++i)
{
table[i] = (uchar)(dividewith * (table[i]/dividewith));
}
const int times = 100;
double t;
t = (double)cv::getTickCount();
for(int i=0; i<times; ++i)
{
cv::Mat clone_i = I.clone();
J = ScanImageAndReduceC(clone_i, table);
}
t = 1000*((double)cv::getTickCount() - t)/cv::getTickFrequency();
t /= times;
std::cout << "Time of reducing with the c operator [] (averaged for "
<< times << " runs):" << t << " milliseconds." << std::endl;
/***************************************/
t = (double)cv::getTickCount();
for(int i=0; i<times; ++i)
{
cv::Mat clone_i = I.clone();
J = ScanImageAndReduceIterator(clone_i, table);
}
t = 1000*((double)cv::getTickCount() - t)/cv::getTickFrequency();
t /= times;
std::cout << "Time of reducing with the iterator (averaged for "
<< times << " runs): " << t << " millseconds." << std::endl;
/***********************************************/
t = (double)cv::getTickCount();
for(int i=0; i<times; ++i)
{
cv::Mat clone_i = I.clone();
ScanImageAndReduceRandomAccess(clone_i, table);
}
t = 1000*((double)cv::getTickCount() - t)/cv::getTickFrequency();
t /= times;
std::cout << "Time of reducing with the random access (averagd for "
<< times << " runs): " << t << " millseconds" << std::endl;
cv::Mat lookUpTable(1,256, CV_8U);
uchar *p = lookUpTable.ptr();
for(int i=0; i<256; ++i)
{
p[i] = table[i];
}
t = (double)cv::getTickCount();
for(int i=0; i<times; ++i)
{
//调用LUT函数并通过查找表来进行"color space reduction"
cv::LUT(I, lookUpTable, J);
}
t = 1000 * ((double)cv::getTickCount() - t)/cv::getTickFrequency();
t /= times;
std::cout << "Time of reducing with the LUT function (averaged for "
<< times << " runs): " << t << " millseconds" << std::endl;
return 0;
}
cv::Mat& ScanImageAndReduceC(cv::Mat& I, const uchar* const table)
{
CV_Assert(I.depth() == CV_8U);
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;
}
cv::Mat& ScanImageAndReduceIterator(cv::Mat& I, const uchar* const table)
{
CV_Assert(I.depth() == CV_8U);
const int channels = I.channels();
switch(channels)
{
case 1:
{
cv::MatIterator_<uchar> it, end;
for(it=I.begin<uchar>(), end=I.end<uchar>(); it!=end; ++it)
{
*it = table[*it];
}
break;
}
case 3:
{
cv::MatIterator_<cv::Vec3b> it, end;
for(it=I.begin<cv::Vec3b>(), end=I.end<cv::Vec3b>(); it != end; ++it)
{
(*it)[0] = table[(*it)[0]];
(*it)[1] = table[(*it)[1]];
(*it)[2] = table[(*it)[2]];
}
}
}
return I;
}
cv::Mat& ScanImageAndReduceRandomAccess(cv::Mat& I, const uchar* const table)
{
CV_Assert(I.depth() == CV_8U);
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:
{
cv::Mat_<cv::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;
}