打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
OpenCV学习C++接口:图像遍历+像素压缩

学习体会:

  1. 当Mat为多通道时,如3通道,如果我们将其内容输出到终端,则可以看出其列数为Mat::colsn倍,当然nMat的通道数。虽是如此,但是Mat::cols的数值并没有随之改变。
  2. 当复制一副图像时,利用函数cv::Mat::clone(),则将在内存中重新开辟一段新的内存存放复制的图像(图像数据也将全部复制),而如果利用cv::Mat::copyTo()复制图像,则不会在内存中开辟一段新的内存块,同时也不会复制图像数据,复制前后的图像的指针指向同一个内存块。使用的时候需注意两个函数的区别。
  3. 为了避免函数参数传递时出现复制情况,函数的形参多采用传递reference,如cv::Mat &image,传递输入图像的引用,不过这样函数可能会对输入图像进行修改,并反映到输出结果上;如果想避免修改输入图像,则函数形参可传递const reference,这样输入图像不会被修改,同时可以创建一个输出图像Mat,将函数处理的结果保存到输出图像Mat中,例如:void colorReduce4(const cv::Mat &image, cv::Mat &result,int div = 64)。
  4. 采用迭代器iterator来遍历图像像素,可简化过程,比较安全,不过效率较低;如果想避免修改输入图像实例cv::Mat,可采用const_iterator
  5. 遍历图像时,不要采用.at()方式,这种效率最低。
  6. 进行图像像素压缩时,利用位操作的算法效率最高,其次是利用整数除法中向下取整,效率最低的是取模运算。
  7. 设计函数时,需要检查计算效率来提高程序的性能,不过以牺牲程序的可读性来提高代码执行的效率并不是一个明智的选择。
  8. 执行效率情况见程序运行结果。

参考资料:《OpenCV 2 Computer Vision Application Programming Cookbook》

 

  1 /***************************************************************  2 *  3 *    内容摘要:本例采用8种方法对图像Mat的像素进行扫描,并对像素点的像  4 *            素进行压缩,压缩间隔为div=64,并比较扫描及压缩的效率,效  5 *            率最高的是采用.ptr及减少循环次数来遍历图像,并采用位操  6 *            作来对图像像素进行压缩。  7 *   作    者:Jacky Liu  8 *   完成日期:2012.8.10  9 *   参考资料:《OpenCV 2 computer Vision Application Programming 10 *              cookbook》 11 * 12 ***************************************************************/ 13 #include <opencv2/core/core.hpp> 14 #include <opencv2/imgproc/imgproc.hpp> 15 #include <opencv2/highgui/highgui.hpp> 16 #include <iostream> 17  18  19 //利用.ptr和数组下标进行图像像素遍历 20 void colorReduce0(cv::Mat &image, int div = 64) 21 { 22     int nl = image.rows; 23     int nc = image.cols * image.channels(); 24      25     //遍历图像的每个像素 26     for(int j=0; j<nl ;++j) 27     { 28         uchar *data = image.ptr<uchar>(j); 29         for(int i=0; i<nc; ++i) 30         { 31             data[i] = data[i]/div*div+div/2;     //减少图像中颜色总数的关键算法:if div = 64, then the total number of colors is 4x4x4;整数除法时,是向下取整。 32         } 33     } 34 } 35  36  37 //利用.ptr和 *++ 进行图像像素遍历 38 void colorReduce1(cv::Mat &image, int div = 64) 39 { 40     int nl = image.rows; 41     int nc = image.cols * image.channels(); 42      43     //遍历图像的每个像素 44     for(int j=0; j<nl ;++j) 45     { 46         uchar *data = image.ptr<uchar>(j); 47         for(int i=0; i<nc; ++i) 48         { 49             *data++ = *data/div*div + div/2; 50         } 51     } 52 } 53  54  55 //利用.ptr和数组下标进行图像像素遍历,取模运算用于减少图像颜色总数 56 void colorReduce2(cv::Mat &image, int div = 64) 57 { 58     int nl = image.rows; 59     int nc = image.cols * image.channels(); 60      61     //遍历图像的每个像素 62     for(int j=0; j<nl ;++j) 63     { 64         uchar *data = image.ptr<uchar>(j); 65         for(int i=0; i<nc; ++i) 66         { 67             data[i] = data[i]-data[i]%div +div/2;  //利用取模运算,速度变慢,因为要读每个像素两次 68         } 69     } 70 } 71  72 //利用.ptr和数组下标进行图像像素遍历,位操作运算用于减少图像颜色总数 73 void colorReduce3(cv::Mat &image, int div = 64) 74 { 75     int nl = image.rows; 76     int nc = image.cols * image.channels(); 77  78     int n = static_cast<int>(log(static_cast<double>(div))/log(2.0));   //div=64, n=6 79     uchar mask = 0xFF<<n;                                            //e.g. div=64, mask=0xC0 80      81     //遍历图像的每个像素 82     for(int j=0; j<nl ;++j) 83     { 84         uchar *data = image.ptr<uchar>(j); 85         for(int i=0; i<nc; ++i) 86         { 87             *data++ = *data&mask + div/2; 88         } 89     } 90 } 91  92 //形参传入const conference,故输入图像不会被修改;利用.ptr和数组下标进行图像像素遍历 93 void colorReduce4(const cv::Mat &image, cv::Mat &result,int div = 64) 94 { 95     int nl = image.rows; 96     int nc = image.cols * image.channels(); 97  98     result.create(image.rows,image.cols,image.type()); 99     100     //遍历图像的每个像素101     for(int j=0; j<nl ;++j)102     {103         const uchar *data_in = image.ptr<uchar>(j);104         uchar *data_out = result.ptr<uchar>(j);105         for(int i=0; i<nc; ++i)106         {107             data_out[i] = data_in[i]/div*div+div/2;     //减少图像中颜色总数的关键算法:if div = 64, then the total number of colors is 4x4x4;整数除法时,是向下取整。108         }109     }110 }111 112 //利用.ptr和数组下标进行图像像素遍历,并将nc放入for循环中(比较糟糕的做法)113 void colorReduce5(cv::Mat &image, int div = 64)114 {115     int nl = image.rows;116     117     //遍历图像的每个像素118     for(int j=0; j<nl ;++j)119     {120         uchar *data = image.ptr<uchar>(j);121         for(int i=0; i<image.cols * image.channels(); ++i)122         {123             data[i] = data[i]/div*div+div/2;     //减少图像中颜色总数的关键算法:if div = 64, then the total number of colors is 4x4x4;整数除法时,是向下取整。124         }125     }126 }127 128 //利用迭代器 cv::Mat iterator 进行图像像素遍历129 void colorReduce6(cv::Mat &image, int div = 64)130 {131     cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>();    //由于利用图像迭代器处理图像像素,因此返回类型必须在编译时知道132     cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>();133 134     for(;it != itend; ++it)135     {136         (*it)[0] = (*it)[0]/div*div+div/2;        //利用operator[]处理每个通道的像素137         (*it)[1] = (*it)[1]/div*div+div/2;138         (*it)[2] = (*it)[2]/div*div+div/2;139     }140 }141 142 //利用.at<cv::Vec3b>(j,i)进行图像像素遍历143 void colorReduce7(cv::Mat &image, int div = 64)144 {145     int nl = image.rows;146     int nc = image.cols;147     148     //遍历图像的每个像素149     for(int j=0; j<nl ;++j)150     {151         for(int i=0; i<nc; ++i)152         {153             image.at<cv::Vec3b>(j,i)[0] = image.at<cv::Vec3b>(j,i)[0]/div*div + div/2;154             image.at<cv::Vec3b>(j,i)[1] = image.at<cv::Vec3b>(j,i)[1]/div*div + div/2;155             image.at<cv::Vec3b>(j,i)[2] = image.at<cv::Vec3b>(j,i)[2]/div*div + div/2;156         }157     }158 }159 160 //减少循环次数,进行图像像素遍历,调用函数较少,效率最高。161 void colorReduce8(cv::Mat &image, int div = 64)162 {163     int nl = image.rows;164     int nc = image.cols;165 166     //判断是否是连续图像,即是否有像素填充167     if(image.isContinuous())168     {169         nc = nc*nl;170         nl = 1;171     }172 173     int n = static_cast<int>(log(static_cast<double>(div))/log(2.0));174     uchar mask = 0xFF<<n;175     176     //遍历图像的每个像素177     for(int j=0; j<nl ;++j)178     {179         uchar *data = image.ptr<uchar>(j);180         for(int i=0; i<nc; ++i)181         {182             *data++ = *data & mask +div/2;183             *data++ = *data & mask +div/2;184             *data++ = *data & mask +div/2;185         }186     }187 }188 189 const int NumTests = 9;        //测试算法的数量190 const int NumIteration = 20;   //迭代次数191 192 int main(int argc, char* argv[])193 {194     int64 t[NumTests],tinit;195     cv::Mat image1;196     cv::Mat image2;197     198     //数组初始化199     int i=0;200     while(i<NumTests)201     {202         t[i++] = 0;203     }204 205     int n = NumIteration;206     207     //迭代n次,取平均数208     for(int i=0; i<n; ++i)209     {210         image1 = cv::imread("../boldt.jpg");211 212         if(!image1.data)213         {214             std::cout<<"read image failue!"<<std::endl;215             return -1;216         }217 218         // using .ptr and []219         tinit = cv::getTickCount();220         colorReduce0(image1);221         t[0] += cv::getTickCount() - tinit;222         223         // using .ptr and *++224         image1 = cv::imread("../boldt.jpg");225         tinit = cv::getTickCount();226         colorReduce1(image1);227         t[1] += cv::getTickCount()  - tinit;228         229         // using .ptr and [] and modulo230         image1 = cv::imread("../boldt.jpg");231         tinit = cv::getTickCount();232         colorReduce2(image1);233         t[2] += cv::getTickCount()  - tinit;234         235         // using .ptr and *++ and bitwise236         image1 = cv::imread("../boldt.jpg");237         tinit = cv::getTickCount();238         colorReduce3(image1);239         t[3] += cv::getTickCount()  - tinit;240 241         //using input and output image242         image1 = cv::imread("../boldt.jpg");243         tinit = cv::getTickCount();244         colorReduce4(image1,image2);245         t[4] += cv::getTickCount()  - tinit;246         247         // using .ptr and [] with image.cols * image.channels()248         image1 = cv::imread("../boldt.jpg");249         tinit = cv::getTickCount();250         colorReduce5(image1);251         t[5] += cv::getTickCount()  - tinit;252         253         // using .ptr and *++ and iterator254         image1 = cv::imread("../boldt.jpg");255         tinit = cv::getTickCount();256         colorReduce6(image1);257         t[6] += cv::getTickCount()  - tinit;258         259         //using at260         image1 = cv::imread("../boldt.jpg");261         tinit = cv::getTickCount();262         colorReduce7(image1);263         t[7] += cv::getTickCount()  - tinit;264 265         //using .ptr and * ++ and bitwise (continuous+channels)266         image1 = cv::imread("../boldt.jpg");267         tinit = cv::getTickCount();268         colorReduce8(image1);269         t[8] += cv::getTickCount()  - tinit;270     }271 272     cv::namedWindow("Result");273     cv::imshow("Result",image1);274     cv::namedWindow("Result Image");275     cv::imshow("Result Image",image2);276 277     std::cout<<std::endl<<"-------------------------------------------------------------------------"<<std::endl<<std::endl;278     std::cout<<"using .ptr and [] = "<<1000*t[0]/cv::getTickFrequency()/n<<"ms"<<std::endl;279     std::cout<<"using .ptr and *++ = "<<1000*t[1]/cv::getTickFrequency()/n<<"ms"<<std::endl;280     std::cout<<"using .ptr and [] and modulo = "<<1000*t[2]/cv::getTickFrequency()/n<<"ms"<<std::endl;281     std::cout<<"using .ptr and *++ and bitwise = "<<1000*t[3]/cv::getTickFrequency()/n<<"ms"<<std::endl;282     std::cout<<"using input and output image = "<<1000*t[4]/cv::getTickFrequency()/n<<"ms"<<std::endl;283     std::cout<<"using .ptr and [] with image.cols * image.channels() = "<<1000*t[5]/cv::getTickFrequency()/n<<"ms"<<std::endl;284     std::cout<<"using .ptr and *++ and iterator = "<<1000*t[6]/cv::getTickFrequency()/n<<"ms"<<std::endl;285     std::cout<<"using at = "<<1000*t[7]/cv::getTickFrequency()/n<<"ms"<<std::endl;286     std::cout<<"using .ptr and * ++ and bitwise (continuous+channels) = "<<1000*t[8]/cv::getTickFrequency()/n<<"ms"<<std::endl;287     std::cout<<std::endl<<"-------------------------------------------------------------------------"<<std::endl<<std::endl;288     cv::waitKey();289     return 0;290 }

 

运行结果图:

转自:http://www.cnblogs.com/liu-jun/archive/2012/08/12/JackyLiu.html

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
OpenCV成长之路(2):图像的遍历 - 博客 - 伯乐在线
视觉SLAM——OpenCV之Mat结构详解 数据成员和构造函数 创建Mat方法 遍历Mat方法
5. OpenCV图像分割-watershed
局部二值模式(LBP)中间过程的可视化
【从零学习OpenCV 4】图像中添加椒盐噪声
OpenCV常见的优化方法和技巧总结
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服