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

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

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

  1. #include <opencv2/core/core.hpp>
  2. #include <opencv2/highgui/highgui.hpp>
  3. #include <iostream>
  4. #include <sstream>
  5.  
  6. using namespace std;
  7. using namespace cv;
  8.  
  9. static void help(){
  10. cout
  11. << "Author: BJTShang" << endl
  12. << "2016-12-22, CityU" << endl
  13. << "Use: " << "./1222_LUP imageName divideWith [G]" << endl
  14. <<endl;
  15. }
  16.  
  17. Mat& ScanImageAndReduceC(Mat& I, const uchar* table);
  18. Mat& ScanImageAndReduceIterator(Mat& I, const uchar* table);
  19.  
  20. int main(int argc, char** argv){
  21. help();
  22. if(argc<){
  23. cout << "Not enough parameters!" << endl;
  24. return -;
  25. }
  26.  
  27. Mat I;
  28. char* imageName = argv[];
  29. if(argc== && !strcmp(argv[],"G")){
  30. I = imread(imageName, CV_LOAD_IMAGE_GRAYSCALE);
  31. }else{
  32. I = imread(imageName, CV_LOAD_IMAGE_COLOR);
  33. }
  34.  
  35. if(!I.data){
  36. cout << "The image" << imageName << " has no data!";
  37. return -;
  38. }
  39.  
  40. int divideWith = ;
  41. stringstream s;
  42. s << argv[];
  43. s >> divideWith;
  44. if(!s || !divideWith){
  45. cout << "Invalid divideWith, input again (positive integer)!" << endl;
  46. return -;
  47. }
  48.  
  49. // use this table to search for (by simple assignment) reduced intensity,
  50. // instead of calculating for each pixel, which is computational high-cost
  51. uchar table[];
  52. for(int i=; i < ; ++i){
  53. table[i] = uchar((i/divideWith)*divideWith);
  54. }
  55.  
  56. int64 t0 = getTickCount();
  57. Mat J = I.clone();
  58. J = ScanImageAndReduceC(J, table);
  59. double t = (double)(getTickCount() - t0)/getTickFrequency();
  60. cout << "Elapse time = " << t* << " ms" <<endl;
  61.  
  62. namedWindow("before", CV_WINDOW_AUTOSIZE);
  63. namedWindow("after color reduce by LUT", CV_WINDOW_AUTOSIZE);
  64. imshow("before", I);
  65. imshow("after color reduce by LUT", J);
  66. waitKey();
  67. return ;
  68. }
  69.  
  70. Mat& ScanImageAndReduceC(Mat& I, const uchar* table){
  71. CV_Assert(I.depth() == CV_8U);
  72. const int channels = I.channels();
  73.  
  74. int nRows = I.rows;
  75. int nCols = I.cols*channels;
  76.  
  77. if (I.isContinuous()){
  78. nCols *= nRows;
  79. nRows = ;
  80. }
  81.  
  82. uchar* p = NULL;
  83. for(size_t i=; i<nRows; ++i){
  84. p = I.ptr<uchar>(i);
  85. for(size_t j=; j<nCols; ++j){
  86. p[j] = table[p[j]];
  87. }
  88. }
  89. // Mat结构的ptr()方法,返回指向Mat每一行的头元素指针
  90. // Mat结构的data属性,返回指向元素的指针,p++指针自加到下一块元素地址。
  91. // 如果Mat中元素连续,才可以使用*p++取出所有元素值;若Mat中元素不连续,*p++取出第二行开始肯定错误!
  92. // uchar* p = I.data;
  93. // for(size_t i = 0; i < nRows*nCols; ++i){
  94. // *p++ = table[*p];
  95. // }
  96. return I;
  97. }

结果:

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

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

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

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

  1. Mat& ScanImageAndReduceIterator(Mat& I, const uchar* table){
  2. CV_Assert(I.depth() == CV_8U);
  3. int channels = I.channels();
  4.  
  5. switch(channels){
  6. case :
  7. {
  8. MatIterator_<uchar> it,end;
  9. for(it = I.begin<uchar>(), end = I.end<uchar>(); it!=end; ++it)
  10. *it = table[*it];
  11. break;
  12. }
  13. case :
  14. {
  15. MatIterator_<Vec3b> it, end;
  16. for(it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it!=end; ++it){
  17. (*it)[] = table[(*it)[]];
  18. (*it)[] = table[(*it)[]];
  19. (*it)[] = table[(*it)[]];
  20. }
  21. break;
  22. }
  23. }
  24. return I;
  25. }

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

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

  1. Mat& ScanImageAndReduceRandomAccsee(Mat& I, const uchar* table){
  2. CV_Assert(I.depth() == CV_8U);
  3.  
  4. const int channels = I.channels();
  5. switch(channels){
  6. case :
  7. {
  8. for(int i=; i<I.rows; ++i)
  9. for(int j=; j<I.cols; ++j)
  10. I.at<uchar>(i,j) = table[I.at<uchar>(i,j)];
  11. break;
  12. }
  13. case :
  14. {
  15. Mat_<Vec3b> _I = I; // this was used to check the data (3 channels), as well as to use [] operator to access different channels
  16. for(int i=; i<I.rows; ++i)
  17. for(int j=; j<I.cols; ++j){
  18. _I(i,j)[] = table[_I(i,j)[]]; // equal to _I.at(i,j*3) = table[_I.at(i,j*3)]
  19. _I(i,j)[] = table[_I(i,j)[]]; // equal to _I.at(i,J*3+1) = table[_I.at(i,j*3+1)]
  20. _I(i,j)[] = table[_I(i,j)[]]; // equal to _I.at(i,j*3+2) = table[_I.at(i,j*3+2)]
  21. }
  22. I = _I;
  23. break;
  24. }
  25. }
  26. return I;
  27. }

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

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

  1. Mat lookUpTable(, , CV_8U);
  2. uchar* p = lookUpTable.data;
  3. for(int i=; i<; i++)
  4. p[i] = table[i];
  5. 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. EL表达式

    跳转传到: : 相当于(接值放值): --------------------------- --------------------------------- ------------------- ...

  2. kettle中含有参数传递的定时任务

    (1)新建一个作业(新建->作业),并在控制面板右键: (2)设置一个命令参数: (3)把作业的参数传递给转换: (4)在转换中右键设置转换属性: (5)接收作业中设置的传递参数: (6)参数的 ...

  3. NodeJS使用formidable实现文件上传

    最近自学了一下NodeJS,然后做了一个小demo,实现歌曲的添加.修改.播放和删除的功能,其中自然要实现音乐和图片的上传功能.于是上网查找资料,找到了一个formidable插件,该插件可以很好的实 ...

  4. MVC 数据验证

    MVC 数据验证 前一篇说了MVC数据验证的例子,这次来详细说说各种各样的验证注解.System.ComponentModel.DataAnnotations 一.基础特性 一.Required 必填 ...

  5. html5标签知多少

    此文为前段时间团队研究会出品,与小伙伴兮兮圆一起研究的成果,意外地上了公司km的今日推荐,今日挪过来,为新开张的博客先暖暖场吧. 一.常用标签 <header>.<footer> ...

  6. 踢出非法Linux用户

    非法添加用户及非法进去的远程操作用户! 01.非法用户闯入系统 最简单的办法就是用 w 命令来检查. 如果确认有非法用户出现在系统内,可以立即 kill 用户相关进程. kill  -9  `lsof ...

  7. webBrowser1

    HTMLDocument类的引用 using mshtml;

  8. 前端性能优化---yahoo军规

    一.尽可能减少HTTP请求数 二.使用CDN(内容分发网络) 三.添加Expire/Cache-Control头 四.启用Gzip压缩 五.将CSS放在页面最上面 六.将Script放在页面最下面 七 ...

  9. java中IO流小解

    下面这张图列出了java中一些处理流: java中根据操作对象的不同可以分为:字节流和字符流. 首先我们先表示一下什么叫节点流和处理流: 节点流:可以从或向一个特定的地方(节点)读写数据.如FileR ...

  10. BZOJ 3931: [CQOI2015]网络吞吐量

    3931: [CQOI2015]网络吞吐量 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1555  Solved: 637[Submit][Stat ...