第二節記錄一下自己學習圖像遍歷的一點點代碼,摘自《opencv2編程手冊》(張靜譯)
第一個代碼是最簡單的強行修改像素(添加椒鹽噪聲)
1 #include <opencv2/core/core.hpp> 2 #include <opencv2/highgui/highgui.hpp> 3 4 void salt(cv::Mat &image, int n) { 5 6 int i,j; 7 for (int k=0; k<n; k++) { 8 9 // rand() is the MFC random number generator 10 i= rand()%image.cols; 11 j= rand()%image.rows; 12 13 14 if (image.channels() == 1) { // gray-level image 15 16 image.at<uchar>(j,i)= 255; 17 18 } else if (image.channels() == 3) { // color image 19 20 image.at<cv::Vec3b>(j,i)[0]= 255; 21 image.at<cv::Vec3b>(j,i)[1]= 255; 22 image.at<cv::Vec3b>(j,i)[2]= 255; 23 } 24 } 25 } 26 27 int main() 28 { 29 srand(cv::getTickCount()); // init random number generator 30 31 cv::Mat image= cv::imread("../cat.jpg",0); 32 33 salt(image,3000); 34 35 cv::namedWindow("Image"); 36 cv::imshow("Image",image); 37 38 cv::imwrite("salted.bmp",image); 39 40 cv::waitKey(5000); 41 42 return 0; 43 }
書上的注釋為image.<unchar>(j,i)=255,將i行j列的數據變為白色。
第二個程序才開始真正的遍歷
1 #include <opencv2/core/core.hpp> 2 #include <opencv2/highgui/highgui.hpp> 3 4 void colorReduce0(cv::Mat &image, int div=64) { 5 6 int nl= image.rows; // 每行的像素數目 7 int nc= image.cols * image.channels(); // total number of elements per line 8 9 for (int j=0; j<nl; j++) { 10 11 uchar* data= image.ptr<uchar>(j);//此句返回j行的首地址 12 13 for (int i=0; i<nc; i++) { 14 15 // process each pixel --------------------- 16 17 data[i]= data[i]/div*div + div/2; 18 19 // end of pixel processing ---------------- 20 21 } // end of line 22 } 23 } 24 25 int main() 26 { 27 //srand(cv::getTickCount()); // init random number generator 28 29 cv::Mat image= cv::imread("../cat.jpg"); 30 31 colorReduce0(image); 32 33 cv::namedWindow("Image"); 34 cv::imshow("Image",image); 35 36 cv::imwrite("cat.jpg",image); 37 38 cv::waitKey(5000); 39 40 return 0; 41 }
這個程序寫的是對小貓的顏色進行縮減,效果如下
另,對像素的操作可以采用
*data++ =*data/div*div + div/2
來書寫
接下來,我就繼續看第二種顏色縮進的算法
1 void colorReduce1(cv::Mat &image, int div=64) { 2 3 int nl= image.rows; // number of lines 4 int nc= image.cols * image.channels(); // total number of elements per line 5 6 for (int j=0; j<nl; j++) { 7 8 uchar* data= image.ptr<uchar>(j); 9 10 for (int i=0; i<nc; i++) { 11 12 // process each pixel --------------------- 13 14 *data++= *data/div*div + div/2; 15 16 // end of pixel processing ---------------- 17 18 } // end of line 19 } 20 }
效果如下
到這裡我就整個人變傻了。兩個算法不是一樣的嗎- -,為什麼效果差別這麼大- -
算了,還是將人家給的代碼放出吧,希望有大神指正
#include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> // using .ptr and [] void colorReduce0(cv::Mat &image, int div=64) { int nl= image.rows; // number of lines int nc= image.cols * image.channels(); // total number of elements per line for (int j=0; j<nl; j++) { uchar* data= image.ptr<uchar>(j); for (int i=0; i<nc; i++) { // process each pixel --------------------- data[i]= data[i]/div*div + div/2; // end of pixel processing ---------------- } // end of line } } // using .ptr and * ++ void colorReduce1(cv::Mat &image, int div=64) { int nl= image.rows; // number of lines int nc= image.cols * image.channels(); // total number of elements per line for (int j=0; j<nl; j++) { uchar* data= image.ptr<uchar>(j); for (int i=0; i<nc; i++) { // process each pixel --------------------- *data++= *data/div*div + div/2; // end of pixel processing ---------------- } // end of line } } // using .ptr and * ++ and modulo void colorReduce2(cv::Mat &image, int div=64) { int nl= image.rows; // number of lines int nc= image.cols * image.channels(); // total number of elements per line for (int j=0; j<nl; j++) { uchar* data= image.ptr<uchar>(j); for (int i=0; i<nc; i++) { // process each pixel --------------------- int v= *data; *data++= v - v%div + div/2; // end of pixel processing ---------------- } // end of line } } // using .ptr and * ++ and bitwise void colorReduce3(cv::Mat &image, int div=64) { int nl= image.rows; // number of lines int nc= image.cols * image.channels(); // total number of elements per line int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); // mask used to round the pixel value uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 for (int j=0; j<nl; j++) { uchar* data= image.ptr<uchar>(j); for (int i=0; i<nc; i++) { // process each pixel --------------------- *data++= *data&mask + div/2; // end of pixel processing ---------------- } // end of line } } // direct pointer arithmetic void colorReduce4(cv::Mat &image, int div=64) { int nl= image.rows; // number of lines int nc= image.cols * image.channels(); // total number of elements per line int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); int step= image.step; // effective width // mask used to round the pixel value uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 // get the pointer to the image buffer uchar *data= image.data; for (int j=0; j<nl; j++) { for (int i=0; i<nc; i++) { // process each pixel --------------------- *(data+i)= *data&mask + div/2; // end of pixel processing ---------------- } // end of line data+= step; // next line } } // using .ptr and * ++ and bitwise with image.cols * image.channels() void colorReduce5(cv::Mat &image, int div=64) { int nl= image.rows; // number of lines int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); // mask used to round the pixel value uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 for (int j=0; j<nl; j++) { uchar* data= image.ptr<uchar>(j); for (int i=0; i<image.cols * image.channels(); i++) { // process each pixel --------------------- *data++= *data&mask + div/2; // end of pixel processing ---------------- } // end of line } } // using .ptr and * ++ and bitwise (continuous) void colorReduce6(cv::Mat &image, int div=64) { int nl= image.rows; // number of lines int nc= image.cols * image.channels(); // total number of elements per line if (image.isContinuous()) { // then no padded pixels nc= nc*nl; nl= 1; // it is now a 1D array } int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); // mask used to round the pixel value uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 for (int j=0; j<nl; j++) { uchar* data= image.ptr<uchar>(j); for (int i=0; i<nc; i++) { // process each pixel --------------------- *data++= *data&mask + div/2; // end of pixel processing ---------------- } // end of line } } // using .ptr and * ++ and bitwise (continuous+channels) void colorReduce7(cv::Mat &image, int div=64) { int nl= image.rows; // number of lines int nc= image.cols ; // number of columns if (image.isContinuous()) { // then no padded pixels nc= nc*nl; nl= 1; // it is now a 1D array } int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); // mask used to round the pixel value uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 for (int j=0; j<nl; j++) { uchar* data= image.ptr<uchar>(j); for (int i=0; i<nc; i++) { // process each pixel --------------------- *data++= *data&mask + div/2; *data++= *data&mask + div/2; *data++= *data&mask + div/2; // end of pixel processing ---------------- } // end of line } } // using Mat_ iterator void colorReduce8(cv::Mat &image, int div=64) { // get iterators cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>(); cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>(); for ( ; it!= itend; ++it) { // process each pixel --------------------- (*it)[0]= (*it)[0]/div*div + div/2; (*it)[1]= (*it)[1]/div*div + div/2; (*it)[2]= (*it)[2]/div*div + div/2; // end of pixel processing ---------------- } } // using Mat_ iterator and bitwise void colorReduce9(cv::Mat &image, int div=64) { // div must be a power of 2 int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); // mask used to round the pixel value uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 // get iterators cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>(); cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>(); // scan all pixels for ( ; it!= itend; ++it) { // process each pixel --------------------- (*it)[0]= (*it)[0]&mask + div/2; (*it)[1]= (*it)[1]&mask + div/2; (*it)[2]= (*it)[2]&mask + div/2; // end of pixel processing ---------------- } } // using MatIterator_ void colorReduce10(cv::Mat &image, int div=64) { // get iterators cv::Mat_<cv::Vec3b> cimage= image; cv::Mat_<cv::Vec3b>::iterator it=cimage.begin(); cv::Mat_<cv::Vec3b>::iterator itend=cimage.end(); for ( ; it!= itend; it++) { // process each pixel --------------------- (*it)[0]= (*it)[0]/div*div + div/2; (*it)[1]= (*it)[1]/div*div + div/2; (*it)[2]= (*it)[2]/div*div + div/2; // end of pixel processing ---------------- } } void colorReduce11(cv::Mat &image, int div=64) { int nl= image.rows; // number of lines int nc= image.cols; // number of columns for (int j=0; j<nl; j++) { for (int i=0; i<nc; i++) { // process each pixel --------------------- 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; // end of pixel processing ---------------- } // end of line } } // with input/ouput images void colorReduce12(const cv::Mat &image, // input image cv::Mat &result, // output image int div=64) { int nl= image.rows; // number of lines int nc= image.cols ; // number of columns // allocate output image if necessary result.create(image.rows,image.cols,image.type()); // created images have no padded pixels nc= nc*nl; nl= 1; // it is now a 1D array int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); // mask used to round the pixel value uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 for (int j=0; j<nl; j++) { uchar* data= result.ptr<uchar>(j); const uchar* idata= image.ptr<uchar>(j); for (int i=0; i<nc; i++) { // process each pixel --------------------- *data++= (*idata++)&mask + div/2; *data++= (*idata++)&mask + div/2; *data++= (*idata++)&mask + div/2; // end of pixel processing ---------------- } // end of line } } // using overloaded operators void colorReduce13(cv::Mat &image, int div=64) { int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); // mask used to round the pixel value uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 // perform color reduction image=(image&cv::Scalar(mask,mask,mask))+cv::Scalar(div/2,div/2,div/2); } #define NTESTS 14 #define NITERATIONS 20 int main() { int64 t[NTESTS],tinit; cv::Mat image1; cv::Mat image2; // timer values set to 0 for (int i=0; i<NTESTS; i++) t[i]= 0; // repeat the tests several times int n=NITERATIONS; for (int k=0; k<n; k++) { std::cout << k << " of " << n << std::endl; image1= cv::imread("../cat.jpg"); if (!image1.data) return 0; // using .ptr and [] tinit= cv::getTickCount(); colorReduce0(image1); t[0]+= cv::getTickCount()-tinit; image1= cv::imread("../cat.jpg"); // using .ptr and * ++ tinit= cv::getTickCount(); colorReduce1(image1); t[1]+= cv::getTickCount()-tinit; image1= cv::imread("../cat.jpg"); // using .ptr and * ++ and modulo tinit= cv::getTickCount(); colorReduce2(image1); t[2]+= cv::getTickCount()-tinit; image1= cv::imread("../cat.jpg"); // using .ptr and * ++ and bitwise tinit= cv::getTickCount(); colorReduce3(image1); t[3]+= cv::getTickCount()-tinit; image1= cv::imread("../cat.jpg"); // using direct pointer arithmetic tinit= cv::getTickCount(); colorReduce4(image1); t[4]+= cv::getTickCount()-tinit; image1= cv::imread("../cat.jpg"); // using .ptr and * ++ and bitwise with image.cols * image.channels() tinit= cv::getTickCount(); colorReduce5(image1); t[5]+= cv::getTickCount()-tinit; image1= cv::imread("../cat.jpg"); // using .ptr and * ++ and bitwise (continuous) tinit= cv::getTickCount(); colorReduce6(image1); t[6]+= cv::getTickCount()-tinit; image1= cv::imread("../cat.jpg"); // using .ptr and * ++ and bitwise (continuous+channels) tinit= cv::getTickCount(); colorReduce7(image1); t[7]+= cv::getTickCount()-tinit; image1= cv::imread("../cat.jpg"); // using Mat_ iterator tinit= cv::getTickCount(); colorReduce8(image1); t[8]+= cv::getTickCount()-tinit; image1= cv::imread("../cat.jpg"); // using Mat_ iterator and bitwise tinit= cv::getTickCount(); colorReduce9(image1); t[9]+= cv::getTickCount()-tinit; image1= cv::imread("../cat.jpg"); // using Mat_ iterator tinit= cv::getTickCount(); colorReduce10(image1); t[10]+= cv::getTickCount()-tinit; image1= cv::imread("../cat.jpg"); // using at tinit= cv::getTickCount(); colorReduce11(image1); t[11]+= cv::getTickCount()-tinit; image1= cv::imread("../cat.jpg"); // using input/output images tinit= cv::getTickCount(); cv::Mat result; colorReduce12(image1, result); t[12]+= cv::getTickCount()-tinit; image2= result; image1= cv::imread("../cat.jpg"); // using input/output images tinit= cv::getTickCount(); colorReduce13(image1); t[13]+= cv::getTickCount()-tinit; //------------------------------ } cv::namedWindow("Result"); cv::imshow("Result",image2); cv::namedWindow("Image Result"); cv::imshow("Image Result",image1); // print average execution time 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 direct pointer arithmetic =" << 1000.*t[4]/cv::getTickFrequency()/n << "ms" << std::endl; std::cout << "using .ptr and * ++ and bitwise with image.cols * image.channels() =" << 1000.*t[5]/cv::getTickFrequency()/n << "ms" << std::endl; std::cout << "using .ptr and * ++ and bitwise (continuous) =" << 1000.*t[6]/cv::getTickFrequency()/n << "ms" << std::endl; std::cout << "using .ptr and * ++ and bitwise (continuous+channels) =" << 1000.*t[7]/cv::getTickFrequency()/n << "ms" << std::endl; std::cout << "using Mat_ iterator =" << 1000.*t[8]/cv::getTickFrequency()/n << "ms" << std::endl; std::cout << "using Mat_ iterator and bitwise =" << 1000.*t[9]/cv::getTickFrequency()/n << "ms" << std::endl; std::cout << "using MatIterator_ =" << 1000.*t[10]/cv::getTickFrequency()/n << "ms" << std::endl; std::cout << "using at =" << 1000.*t[11]/cv::getTickFrequency()/n << "ms" << std::endl; std::cout << "using input/output images =" << 1000.*t[12]/cv::getTickFrequency()/n << "ms" << std::endl; std::cout << "using overloaded operators =" << 1000.*t[13]/cv::getTickFrequency()/n << "ms" << std::endl; cv::waitKey(); return 0; }