学习体会:
参考资料:《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
联系客服