學習體會:ios
/*************************************************************** * * 內容摘要:本例採用8種方法對圖像Mat的像素進行掃描,並對像素點的像 * 素進行壓縮,壓縮間隔爲div=64,並比較掃描及壓縮的效率,效 * 率最高的是採用.ptr及減小循環次數來遍歷圖像,並採用位操 * 做來對圖像像素進行壓縮。 * 做 者:Jacky Liu * 完成日期:2012.8.10 * 參考資料:《OpenCV 2 computer Vision Application Programming * cookbook》 * ***************************************************************/ #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> //利用.ptr和數組下標進行圖像像素遍歷 void colorReduce0(cv::Mat &image, int div = 64) { int nl = image.rows; int nc = image.cols * image.channels(); //遍歷圖像的每一個像素 for(int j=0; j<nl ;++j) { uchar *data = image.ptr<uchar>(j); for(int i=0; i<nc; ++i) { data[i] = data[i]/div*div+div/2; //減小圖像中顏色總數的關鍵算法:if div = 64, then the total number of colors is 4x4x4;整數除法時,是向下取整。 } } } //利用.ptr和 *++ 進行圖像像素遍歷 void colorReduce1(cv::Mat &image, int div = 64) { int nl = image.rows; int nc = image.cols * image.channels(); //遍歷圖像的每一個像素 for(int j=0; j<nl ;++j) { uchar *data = image.ptr<uchar>(j); for(int i=0; i<nc; ++i) { *data++ = *data/div*div + div/2; } } } //利用.ptr和數組下標進行圖像像素遍歷,取模運算用於減小圖像顏色總數 void colorReduce2(cv::Mat &image, int div = 64) { int nl = image.rows; int nc = image.cols * image.channels(); //遍歷圖像的每一個像素 for(int j=0; j<nl ;++j) { uchar *data = image.ptr<uchar>(j); for(int i=0; i<nc; ++i) { data[i] = data[i]-data[i]%div +div/2; //利用取模運算,速度變慢,由於要讀每一個像素兩次 } } } //利用.ptr和數組下標進行圖像像素遍歷,位操做運算用於減小圖像顏色總數 void colorReduce3(cv::Mat &image, int div = 64) { int nl = image.rows; int nc = image.cols * image.channels(); int n = static_cast<int>(log(static_cast<double>(div))/log(2.0)); //div=64, n=6 uchar mask = 0xFF<<n; //e.g. div=64, mask=0xC0 //遍歷圖像的每一個像素 for(int j=0; j<nl ;++j) { uchar *data = image.ptr<uchar>(j); for(int i=0; i<nc; ++i) { *data++ = *data&mask + div/2; } } } //形參傳入const conference,故輸入圖像不會被修改;利用.ptr和數組下標進行圖像像素遍歷 void colorReduce4(const cv::Mat &image, cv::Mat &result,int div = 64) { int nl = image.rows; int nc = image.cols * image.channels(); result.create(image.rows,image.cols,image.type()); //遍歷圖像的每一個像素 for(int j=0; j<nl ;++j) { const uchar *data_in = image.ptr<uchar>(j); uchar *data_out = result.ptr<uchar>(j); for(int i=0; i<nc; ++i) { data_out[i] = data_in[i]/div*div+div/2; //減小圖像中顏色總數的關鍵算法:if div = 64, then the total number of colors is 4x4x4;整數除法時,是向下取整。 } } } //利用.ptr和數組下標進行圖像像素遍歷,並將nc放入for循環中(比較糟糕的作法) void colorReduce5(cv::Mat &image, int div = 64) { int nl = image.rows; //遍歷圖像的每一個像素 for(int j=0; j<nl ;++j) { uchar *data = image.ptr<uchar>(j); for(int i=0; i<image.cols * image.channels(); ++i) { data[i] = data[i]/div*div+div/2; //減小圖像中顏色總數的關鍵算法:if div = 64, then the total number of colors is 4x4x4;整數除法時,是向下取整。 } } } //利用迭代器 cv::Mat iterator 進行圖像像素遍歷 void colorReduce6(cv::Mat &image, int div = 64) { cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>(); //因爲利用圖像迭代器處理圖像像素,所以返回類型必須在編譯時知道 cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>(); for(;it != itend; ++it) { (*it)[0] = (*it)[0]/div*div+div/2; //利用operator[]處理每一個通道的像素 (*it)[1] = (*it)[1]/div*div+div/2; (*it)[2] = (*it)[2]/div*div+div/2; } } //利用.at<cv::Vec3b>(j,i)進行圖像像素遍歷 void colorReduce7(cv::Mat &image, int div = 64) { int nl = image.rows; int nc = image.cols; //遍歷圖像的每一個像素 for(int j=0; j<nl ;++j) { for(int i=0; i<nc; ++i) { image.at<cv::Vec3b>(j,i)[0] = image.at<cv::Vec3b>(j,i)[0]/div*div + div/2; image.at<cv::Vec3b>(j,i)[1] = image.at<cv::Vec3b>(j,i)[1]/div*div + div/2; image.at<cv::Vec3b>(j,i)[2] = image.at<cv::Vec3b>(j,i)[2]/div*div + div/2; } } } //減小循環次數,進行圖像像素遍歷,調用函數較少,效率最高。 void colorReduce8(cv::Mat &image, int div = 64) { int nl = image.rows; int nc = image.cols; //判斷是不是連續圖像,便是否有像素填充 if(image.isContinuous()) { nc = nc*nl; nl = 1; } int n = static_cast<int>(log(static_cast<double>(div))/log(2.0)); uchar mask = 0xFF<<n; //遍歷圖像的每一個像素 for(int j=0; j<nl ;++j) { uchar *data = image.ptr<uchar>(j); for(int i=0; i<nc; ++i) { *data++ = *data & mask +div/2; *data++ = *data & mask +div/2; *data++ = *data & mask +div/2; } } } const int NumTests = 9; //測試算法的數量 const int NumIteration = 20; //迭代次數 int main(int argc, char* argv[]) { int64 t[NumTests],tinit; cv::Mat image1; cv::Mat image2; //數組初始化 int i=0; while(i<NumTests) { t[i++] = 0; } int n = NumIteration; //迭代n次,取平均數 for(int i=0; i<n; ++i) { image1 = cv::imread("../boldt.jpg"); if(!image1.data) { std::cout<<"read image failue!"<<std::endl; return -1; } // using .ptr and [] tinit = cv::getTickCount(); colorReduce0(image1); t[0] += cv::getTickCount() - tinit; // using .ptr and *++ image1 = cv::imread("../boldt.jpg"); tinit = cv::getTickCount(); colorReduce1(image1); t[1] += cv::getTickCount() - tinit; // using .ptr and [] and modulo image1 = cv::imread("../boldt.jpg"); tinit = cv::getTickCount(); colorReduce2(image1); t[2] += cv::getTickCount() - tinit; // using .ptr and *++ and bitwise image1 = cv::imread("../boldt.jpg"); tinit = cv::getTickCount(); colorReduce3(image1); t[3] += cv::getTickCount() - tinit; //using input and output image image1 = cv::imread("../boldt.jpg"); tinit = cv::getTickCount(); colorReduce4(image1,image2); t[4] += cv::getTickCount() - tinit; // using .ptr and [] with image.cols * image.channels() image1 = cv::imread("../boldt.jpg"); tinit = cv::getTickCount(); colorReduce5(image1); t[5] += cv::getTickCount() - tinit; // using .ptr and *++ and iterator image1 = cv::imread("../boldt.jpg"); tinit = cv::getTickCount(); colorReduce6(image1); t[6] += cv::getTickCount() - tinit; //using at image1 = cv::imread("../boldt.jpg"); tinit = cv::getTickCount(); colorReduce7(image1); t[7] += cv::getTickCount() - tinit; //using .ptr and * ++ and bitwise (continuous+channels) image1 = cv::imread("../boldt.jpg"); tinit = cv::getTickCount(); colorReduce8(image1); t[8] += cv::getTickCount() - tinit; } cv::namedWindow("Result"); cv::imshow("Result",image1); cv::namedWindow("Result Image"); cv::imshow("Result Image",image2); std::cout<<std::endl<<"-------------------------------------------------------------------------"<<std::endl<<std::endl; std::cout<<"using .ptr and [] = "<<1000*t[0]/cv::getTickFrequency()/n<<"ms"<<std::endl; std::cout<<"using .ptr and *++ = "<<1000*t[1]/cv::getTickFrequency()/n<<"ms"<<std::endl; std::cout<<"using .ptr and [] and modulo = "<<1000*t[2]/cv::getTickFrequency()/n<<"ms"<<std::endl; std::cout<<"using .ptr and *++ and bitwise = "<<1000*t[3]/cv::getTickFrequency()/n<<"ms"<<std::endl; std::cout<<"using input and output image = "<<1000*t[4]/cv::getTickFrequency()/n<<"ms"<<std::endl; std::cout<<"using .ptr and [] with image.cols * image.channels() = "<<1000*t[5]/cv::getTickFrequency()/n<<"ms"<<std::endl; std::cout<<"using .ptr and *++ and iterator = "<<1000*t[6]/cv::getTickFrequency()/n<<"ms"<<std::endl; std::cout<<"using at = "<<1000*t[7]/cv::getTickFrequency()/n<<"ms"<<std::endl; std::cout<<"using .ptr and * ++ and bitwise (continuous+channels) = "<<1000*t[8]/cv::getTickFrequency()/n<<"ms"<<std::endl; std::cout<<std::endl<<"-------------------------------------------------------------------------"<<std::endl<<std::endl; cv::waitKey(); return 0; }