1.目的:
如何遍历图像中的每一个像素
openCV矩阵的值是如何存储
如何测试所实现的算法的性能
查找表是什么,为什么要用查找表
2.测试用例
(1)颜色缩减:将现有的颜色空间值除以某个输入值,以获取较少的颜色数。
(2)构建查找表
for(int i=0; i<256; i++){
//大小为256的查找表
table[i] = (divideWidth*(i/divideWidth));
}
(3)计算运行时间
//getTickCountCPU自某个事件开始以来所用的周期
double startTime = (double)getTickCount();
//getTickFrequency获取CPU一秒钟所用的CPU始终周期数
double totalTime = (double)(getTickCount() - startTime)/getTickFrequency();
3.图像矩阵存储方式
(1)单通道灰度图像
(2)多通道彩色图像
PS:对于RGB图像,其存储顺序是BGR而不是RGB。因为内存足够大,可实现连续存储,因此,图像中的各行就能一行一行地连接起来,形成一个长行。连续存储有助于提升图像扫描速度,我们可以使用 isContinuous() 来去判断矩阵是否是连续存储的。
4.高效遍历图像
(1)高效方法
Mat& ScanImageAndReduceC(Mat& I, const uchar* table){
CV_Assert(I.depth()!=sizeof(uchar));
int channels = I.channels();
int cols = I.cols*channels;
int rows = I.rows;
if(I.isContinuous()){
//图片连续存储则转化为一维矩阵
cols = rows*cols;
rows = 1;
}
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
I.ptr<uchar>(i)[j] = table[I.ptr<uchar>(i)[j]];
}
}
return(I);
}
(2)迭代法
//待测试
(3)相关返回值的On-the-fly地址计算
Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar* table){
CV_Assert(I.depth()!=sizeof(uchar));
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):
for(int i=0; i<I.rows; i++){
for(int j=0; j<I.cols*channels; j++){
I.ptr<uchar>(i)[j] = table[I.ptr<uchar>(i)[j]];
I.ptr<uchar>(i)[j] = table[I.ptr<uchar>(i)[j]];
I.ptr<uchar>(i)[j] = table[I.ptr<uchar>(i)[j]];
}
}
break;
}
return(I);
}
(4)LUT核心函数方法
Mat& ScanImageAndReduceLUT(Mat& I, uchar*table){
CV_Assert(I.depth()!=sizeof(uchar));
Mat lookUpTable(1,256,CV_8U);
uchar* p = lookUpTable.ptr();
for(int i=0; i<256; i++){
p[i] = table[i];
}
cout << "table=" << endl << lookUpTable << endl;
//LUT函数参数解释
/*
第一个参数:输入矩阵
第二个参数:查询表
第三个参数:输出矩阵
*/
LUT(I,lookUpTable,I);
return(I);
}
参考文献
1.http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials