使用LUT(lookup table)检索表的方法,提高color reduce时对像素读取的速度。

实现对Mat对象中数据的读取,并计算color reduce的速度。

方法一:使用Mat的ptr()遍历行(row),效率较高,使用时需要小心细节

 #include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <sstream> using namespace std;
using namespace cv; static void help(){
cout
<< "Author: BJTShang" << endl
<< "2016-12-22, CityU" << endl
<< "Use: " << "./1222_LUP imageName divideWith [G]" << endl
<<endl;
} Mat& ScanImageAndReduceC(Mat& I, const uchar* table);
Mat& ScanImageAndReduceIterator(Mat& I, const uchar* table); int main(int argc, char** argv){
help();
if(argc<){
cout << "Not enough parameters!" << endl;
return -;
} Mat I;
char* imageName = argv[];
if(argc== && !strcmp(argv[],"G")){
I = imread(imageName, CV_LOAD_IMAGE_GRAYSCALE);
}else{
I = imread(imageName, CV_LOAD_IMAGE_COLOR);
} if(!I.data){
cout << "The image" << imageName << " has no data!";
return -;
} int divideWith = ;
stringstream s;
s << argv[];
s >> divideWith;
if(!s || !divideWith){
cout << "Invalid divideWith, input again (positive integer)!" << endl;
return -;
} // use this table to search for (by simple assignment) reduced intensity,
// instead of calculating for each pixel, which is computational high-cost
uchar table[];
for(int i=; i < ; ++i){
table[i] = uchar((i/divideWith)*divideWith);
} int64 t0 = getTickCount();
Mat J = I.clone();
J = ScanImageAndReduceC(J, table);
double t = (double)(getTickCount() - t0)/getTickFrequency();
cout << "Elapse time = " << t* << " ms" <<endl; namedWindow("before", CV_WINDOW_AUTOSIZE);
namedWindow("after color reduce by LUT", CV_WINDOW_AUTOSIZE);
imshow("before", I);
imshow("after color reduce by LUT", J);
waitKey();
return ;
} Mat& ScanImageAndReduceC(Mat& I, const uchar* table){
CV_Assert(I.depth() == CV_8U);
const int channels = I.channels(); int nRows = I.rows;
int nCols = I.cols*channels; if (I.isContinuous()){
nCols *= nRows;
nRows = ;
} uchar* p = NULL;
for(size_t i=; i<nRows; ++i){
p = I.ptr<uchar>(i);
for(size_t j=; j<nCols; ++j){
p[j] = table[p[j]];
}
}
// Mat结构的ptr()方法,返回指向Mat每一行的头元素指针
// Mat结构的data属性,返回指向元素的指针,p++指针自加到下一块元素地址。
// 如果Mat中元素连续,才可以使用*p++取出所有元素值;若Mat中元素不连续,*p++取出第二行开始肯定错误!
// uchar* p = I.data;
// for(size_t i = 0; i < nRows*nCols; ++i){
// *p++ = table[*p];
// }
return I;
}

结果:

如果使用*p++的方法,结果不同:

这种方法,需要自己考虑图像每一行之间的gap,以及元素类型(uchar和float32f的不同)。效率较高,但不小心会出问题。

方法二:通过MatIterator类安全地访问Mat结构

效果相同,但是运行时间会变长几倍(我的电脑上大约是3倍)

 Mat& ScanImageAndReduceIterator(Mat& I, const uchar* table){
CV_Assert(I.depth() == CV_8U);
int channels = I.channels(); switch(channels){
case :
{
MatIterator_<uchar> it,end;
for(it = I.begin<uchar>(), end = I.end<uchar>(); it!=end; ++it)
*it = table[*it];
break;
}
case :
{
MatIterator_<Vec3b> it, end;
for(it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it!=end; ++it){
(*it)[] = table[(*it)[]];
(*it)[] = table[(*it)[]];
(*it)[] = table[(*it)[]];
}
break;
}
}
return I;
}

对于3通道彩色图像,需要指定迭代器中元素类型为short vector: <Vec3b>。如果指定为uchar,迭代器器将只会扫描B蓝色通道;当然,这里的情况因为使用了[]操作符访问short vector中的sub colomun, 编译就通不过。。。

方法三:最容易理解,但是最不推荐的是使用Mat的at()方法

 Mat& ScanImageAndReduceRandomAccsee(Mat& I, const uchar* table){
CV_Assert(I.depth() == CV_8U); const int channels = I.channels();
switch(channels){
case :
{
for(int i=; i<I.rows; ++i)
for(int j=; j<I.cols; ++j)
I.at<uchar>(i,j) = table[I.at<uchar>(i,j)];
break;
}
case :
{
Mat_<Vec3b> _I = I; // this was used to check the data (3 channels), as well as to use [] operator to access different channels
for(int i=; i<I.rows; ++i)
for(int j=; j<I.cols; ++j){
_I(i,j)[] = table[_I(i,j)[]]; // equal to _I.at(i,j*3) = table[_I.at(i,j*3)]
_I(i,j)[] = table[_I(i,j)[]]; // equal to _I.at(i,J*3+1) = table[_I.at(i,j*3+1)]
_I(i,j)[] = table[_I(i,j)[]]; // equal to _I.at(i,j*3+2) = table[_I.at(i,j*3+2)]
}
I = _I;
break;
}
}
return I;
}

效率和安全的使用MatIterator类差不多,想访问矩阵中特定位置的元素使用这种方法是比较合适的。

最后,OpenCV封装了LUT的color reduce方法。平常直接使用即可,效率比较高。

   Mat lookUpTable(, , CV_8U);
uchar* p = lookUpTable.data;
for(int i=; i<; i++)
p[i] = table[i];
LUT(I,lookUpTable,J);

读取图像,LUT以及计算耗时的更多相关文章

  1. Exif.js 读取图像的元数据

    Exif.js 提供了 JavaScript 读取图像的原始数据的功能扩展,例如:拍照方向.相机设备型号.拍摄时间.ISO 感光度.GPS 地理位置等数据. 注意事项: EXIF 数据主要来自拍摄的照 ...

  2. GDAL库——读取图像并提取基本信息

    GDAL库是一个跨平台的栅格地理数据格式库,包括读取.写入.转换.处理各种栅格数据格式(有些特定的格式对一些操作如写入等不支持).它使用了一个单一的抽象数据模型就支持了大多数的栅格数据.这里有GDAL ...

  3. 图像相似度计算之哈希值方法OpenCV实现

    http://blog.csdn.net/fengbingchun/article/details/42153261 图像相似度计算之哈希值方法OpenCV实现 2014-12-25 21:27 29 ...

  4. PS图像菜单下计算命令

    PS图像菜单下计算命令通过通道的混合模式得到的选区非常精细,从而调色的时候过度非常好.功能十分强大.   下面用计算命令中的"相加"和"减去"模式做实例解析,这 ...

  5. OpenCV2:第三章 读取图像

    一.简介 将图像文件读入内存,可以用cv::imread()函数 二.读取图像 Mat imread(const string& filename,int flags=1); Mat: 如果读 ...

  6. python3读取图像并可视化的方法(PIL/Pillow、opencv/cv2)

    原图: 使用TensorFlow做图像处理的时候,会对图像进行一些可视化的操作.下面,就来列举一些我知道的图像读取并可视化的方法. 1. Pillow模块 1.1 Pillow模块的前生 Pillow ...

  7. 基于gtk的imshow:用stb_image读取图像并用gtk显示

    在前面一篇,已经能够基于gtk读取图像并显示.更前面的一篇:基于GDI的imshow:使用stb_image读取图像并修正绘制,通过stb_image读取图像并通过GDI显示图像,实现了一个imsho ...

  8. OpenCV读取图像问题:OpenCV(3.4.3) D:\Build\OpenCV\opencv-size.width0 && size.height0 in function 'cvimshow'

    版权声明:本文为博主原创文章,转载 请注明出处:https://blog.csdn.net/sc2079/article/details/83280067 - 问题与解决 最近正在学OpenCV,发现 ...

  9. opencv学习之读取图像-imread函数

    序 想要完整全面地学习opencv,仅凭阅读samples的示例源码是不够的.毕竟opencv是一个拥有非常多函数的程序库,所以在每学习一个函数时,芒果觉得有必要记录下来,分享给有需要的同学.于是,就 ...

随机推荐

  1. Caffe Python MemoryDataLayer Segmentation Fault

    转载请注明出处,楼燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/ 因为利用Pyhon来做数据的预处理比较方便,因此在data_l ...

  2. Java动态代理

    代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关 ...

  3. Lite Your Android English

    https://litesuits.com/ 一些话   简约的背后,往往是复杂 还原面向对象应有的体验,让应对繁多业务所增加的,并未增加. 展开设计理念 Lite每个项目仅几十KB,这相当于你项目中 ...

  4. CODE[VS]4633Mz树链剖分练习

    Description 给定一棵结点数为n的树,初始点权均为0,有依次q个操作,每次操作有三个参数a,b,c,当a=1时,表示给b号结点到c号结点路径上的所有点(包括b,c,下同)权值都增加1,当a= ...

  5. Linux系统下输出某进程内存占用信息的c程序实现

    在实际工作中有时需要程序打印出某个进程的内存占用情况以作参考, 下面介绍一种通过Linux下的伪文件系统/proc 计算某进程内存占用的程序实现方法. 首先, 为什么会有所谓的 伪文件 呢. Linu ...

  6. JavaScript的two-sum问题解法

    一个很常见的问题,找出一个数组中和为给定值的两个数的下标.为了简单一般会注明解只有一个之类的. 最容易想到的方法是循环遍历,这里就不说了. 在JS中比较优雅的方式是利用JS的对象作为hash的方式: ...

  7. [LeetCode] Duplicate Emails 重复的邮箱

    Write a SQL query to find all duplicate emails in a table named Person. +----+---------+ | Id | Emai ...

  8. 混合使用UITabBarController和UINavigationController

    混合使用这两个控件的好处是我们可以在NavigationBar添加更多的东西,如标题,按钮等.让用户能够获得更多的信息. UITabBarController的属性ViewControllers接受以 ...

  9. MySQL字符串函数substring:字符串截取

    MySQL 字符串截取函数:left(), right(), substring(), substring_index().还有 mid(), substr().其中,mid(), substr() ...

  10. Android Hook技术

    原文:http://blog.csdn.net/u011068702/article/details/53208825 附:Android Hook 全面入侵监听器 第一步.先爆项目demo照片,代码 ...