第二節記錄一下自己學習圖像遍歷的一點點代碼,摘自《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;
}