Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3 | PointedEar | 1 | /*------------------------------------------------------------------------------------------*\ |
2 | This file contains material supporting chapter 2 of the cookbook: |
||
3 | Computer Vision Programming using the OpenCV Library. |
||
4 | by Robert Laganiere, Packt Publishing, 2011. |
||
5 | |||
6 | This program is free software; permission is hereby granted to use, copy, modify, |
||
7 | and distribute this source code, or portions thereof, for any purpose, without fee, |
||
8 | subject to the restriction that the copyright notice may not be removed |
||
9 | or altered from any source or altered source distribution. |
||
10 | The software is released on an as-is basis and without any warranties of any kind. |
||
11 | In particular, the software is not guaranteed to be fault-tolerant or free from failure. |
||
12 | The author disclaims all warranties with regard to this software, any use, |
||
13 | and any consequent failure, is purely the responsibility of the user. |
||
14 | |||
15 | Copyright (C) 2010-2011 Robert Laganiere, www.laganiere.name |
||
16 | \*------------------------------------------------------------------------------------------*/ |
||
17 | |||
18 | #include <iostream> |
||
19 | |||
20 | #include <opencv2/core/core.hpp> |
||
21 | #include <opencv2/highgui/highgui.hpp> |
||
22 | |||
23 | // using .ptr and [] |
||
24 | void colorReduce0(cv::Mat &image, int div=64) { |
||
25 | |||
26 | int nl= image.rows; // number of lines |
||
27 | int nc= image.cols * image.channels(); // total number of elements per line |
||
28 | |||
29 | for (int j=0; j<nl; j++) { |
||
30 | |||
31 | uchar* data= image.ptr<uchar>(j); |
||
32 | |||
33 | for (int i=0; i<nc; i++) { |
||
34 | |||
35 | // process each pixel --------------------- |
||
36 | |||
37 | data[i]= data[i]/div*div + div/2; |
||
38 | |||
39 | // end of pixel processing ---------------- |
||
40 | |||
41 | } // end of line |
||
42 | } |
||
43 | } |
||
44 | |||
45 | // using .ptr and * ++ |
||
46 | void colorReduce1(cv::Mat &image, int div=64) { |
||
47 | |||
48 | int nl= image.rows; // number of lines |
||
49 | int nc= image.cols * image.channels(); // total number of elements per line |
||
50 | |||
51 | for (int j=0; j<nl; j++) { |
||
52 | |||
53 | uchar* data= image.ptr<uchar>(j); |
||
54 | |||
55 | for (int i=0; i<nc; i++) { |
||
56 | |||
57 | // process each pixel --------------------- |
||
58 | |||
59 | *data++= *data/div*div + div/2; |
||
60 | |||
61 | // end of pixel processing ---------------- |
||
62 | |||
63 | } // end of line |
||
64 | } |
||
65 | } |
||
66 | |||
67 | // using .ptr and * ++ and modulo |
||
68 | void colorReduce2(cv::Mat &image, int div=64) { |
||
69 | |||
70 | int nl= image.rows; // number of lines |
||
71 | int nc= image.cols * image.channels(); // total number of elements per line |
||
72 | |||
73 | for (int j=0; j<nl; j++) { |
||
74 | |||
75 | uchar* data= image.ptr<uchar>(j); |
||
76 | |||
77 | for (int i=0; i<nc; i++) { |
||
78 | |||
79 | // process each pixel --------------------- |
||
80 | |||
81 | int v= *data; |
||
82 | *data++= v - v%div + div/2; |
||
83 | |||
84 | // end of pixel processing ---------------- |
||
85 | |||
86 | } // end of line |
||
87 | } |
||
88 | } |
||
89 | |||
90 | // using .ptr and * ++ and bitwise |
||
91 | void colorReduce3(cv::Mat &image, int div=64) { |
||
92 | |||
93 | int nl= image.rows; // number of lines |
||
94 | int nc= image.cols * image.channels(); // total number of elements per line |
||
95 | int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); |
||
96 | // mask used to round the pixel value |
||
97 | uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 |
||
98 | |||
99 | for (int j=0; j<nl; j++) { |
||
100 | |||
101 | uchar* data= image.ptr<uchar>(j); |
||
102 | |||
103 | for (int i=0; i<nc; i++) { |
||
104 | |||
105 | // process each pixel --------------------- |
||
106 | |||
107 | *data++= *data&mask + div/2; |
||
108 | |||
109 | // end of pixel processing ---------------- |
||
110 | |||
111 | } // end of line |
||
112 | } |
||
113 | } |
||
114 | |||
115 | |||
116 | // direct pointer arithmetic |
||
117 | void colorReduce4(cv::Mat &image, int div=64) { |
||
118 | |||
119 | int nl= image.rows; // number of lines |
||
120 | int nc= image.cols * image.channels(); // total number of elements per line |
||
121 | int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); |
||
122 | int step= image.step; // effective width |
||
123 | // mask used to round the pixel value |
||
124 | uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 |
||
125 | |||
126 | // get the pointer to the image buffer |
||
127 | uchar *data= image.data; |
||
128 | |||
129 | for (int j=0; j<nl; j++) { |
||
130 | |||
131 | for (int i=0; i<nc; i++) { |
||
132 | |||
133 | // process each pixel --------------------- |
||
134 | |||
135 | *(data+i)= *data&mask + div/2; |
||
136 | |||
137 | // end of pixel processing ---------------- |
||
138 | |||
139 | } // end of line |
||
140 | |||
141 | data+= step; // next line |
||
142 | } |
||
143 | } |
||
144 | |||
145 | // using .ptr and * ++ and bitwise with image.cols * image.channels() |
||
146 | void colorReduce5(cv::Mat &image, int div=64) { |
||
147 | |||
148 | int nl= image.rows; // number of lines |
||
149 | int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); |
||
150 | // mask used to round the pixel value |
||
151 | uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 |
||
152 | |||
153 | for (int j=0; j<nl; j++) { |
||
154 | |||
155 | uchar* data= image.ptr<uchar>(j); |
||
156 | |||
157 | for (int i=0; i<image.cols * image.channels(); i++) { |
||
158 | |||
159 | // process each pixel --------------------- |
||
160 | |||
161 | *data++= *data&mask + div/2; |
||
162 | |||
163 | // end of pixel processing ---------------- |
||
164 | |||
165 | } // end of line |
||
166 | } |
||
167 | } |
||
168 | |||
169 | // using .ptr and * ++ and bitwise (continuous) |
||
170 | void colorReduce6(cv::Mat &image, int div=64) { |
||
171 | |||
172 | int nl= image.rows; // number of lines |
||
173 | int nc= image.cols * image.channels(); // total number of elements per line |
||
174 | |||
175 | if (image.isContinuous()) { |
||
176 | // then no padded pixels |
||
177 | nc= nc*nl; |
||
178 | nl= 1; // it is now a 1D array |
||
179 | } |
||
180 | |||
181 | int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); |
||
182 | // mask used to round the pixel value |
||
183 | uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 |
||
184 | |||
185 | for (int j=0; j<nl; j++) { |
||
186 | |||
187 | uchar* data= image.ptr<uchar>(j); |
||
188 | |||
189 | for (int i=0; i<nc; i++) { |
||
190 | |||
191 | // process each pixel --------------------- |
||
192 | |||
193 | *data++= *data&mask + div/2; |
||
194 | |||
195 | // end of pixel processing ---------------- |
||
196 | |||
197 | } // end of line |
||
198 | } |
||
199 | } |
||
200 | |||
201 | // using .ptr and * ++ and bitwise (continuous+channels) |
||
202 | void colorReduce7(cv::Mat &image, int div=64) { |
||
203 | |||
204 | int nl= image.rows; // number of lines |
||
205 | int nc= image.cols ; // number of columns |
||
206 | |||
207 | if (image.isContinuous()) { |
||
208 | // then no padded pixels |
||
209 | nc= nc*nl; |
||
210 | nl= 1; // it is now a 1D array |
||
211 | } |
||
212 | |||
213 | int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); |
||
214 | // mask used to round the pixel value |
||
215 | uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 |
||
216 | |||
217 | for (int j=0; j<nl; j++) { |
||
218 | |||
219 | uchar* data= image.ptr<uchar>(j); |
||
220 | |||
221 | for (int i=0; i<nc; i++) { |
||
222 | |||
223 | // process each pixel --------------------- |
||
224 | |||
225 | *data++= *data&mask + div/2; |
||
226 | *data++= *data&mask + div/2; |
||
227 | *data++= *data&mask + div/2; |
||
228 | |||
229 | // end of pixel processing ---------------- |
||
230 | |||
231 | } // end of line |
||
232 | } |
||
233 | } |
||
234 | |||
235 | |||
236 | // using Mat_ iterator |
||
237 | void colorReduce8(cv::Mat &image, int div=64) { |
||
238 | |||
239 | // get iterators |
||
240 | cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>(); |
||
241 | cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>(); |
||
242 | |||
243 | for ( ; it!= itend; ++it) { |
||
244 | |||
245 | // process each pixel --------------------- |
||
246 | |||
247 | (*it)[0]= (*it)[0]/div*div + div/2; |
||
248 | (*it)[1]= (*it)[1]/div*div + div/2; |
||
249 | (*it)[2]= (*it)[2]/div*div + div/2; |
||
250 | |||
251 | // end of pixel processing ---------------- |
||
252 | } |
||
253 | } |
||
254 | |||
255 | // using Mat_ iterator and bitwise |
||
256 | void colorReduce9(cv::Mat &image, int div=64) { |
||
257 | |||
258 | // div must be a power of 2 |
||
259 | int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); |
||
260 | // mask used to round the pixel value |
||
261 | uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 |
||
262 | |||
263 | // get iterators |
||
264 | cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>(); |
||
265 | cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>(); |
||
266 | |||
267 | // scan all pixels |
||
268 | for ( ; it!= itend; ++it) { |
||
269 | |||
270 | // process each pixel --------------------- |
||
271 | |||
272 | (*it)[0]= (*it)[0]&mask + div/2; |
||
273 | (*it)[1]= (*it)[1]&mask + div/2; |
||
274 | (*it)[2]= (*it)[2]&mask + div/2; |
||
275 | |||
276 | // end of pixel processing ---------------- |
||
277 | } |
||
278 | } |
||
279 | |||
280 | // using MatIterator_ |
||
281 | void colorReduce10(cv::Mat &image, int div=64) { |
||
282 | |||
283 | // get iterators |
||
284 | cv::Mat_<cv::Vec3b> cimage= image; |
||
285 | cv::Mat_<cv::Vec3b>::iterator it=cimage.begin(); |
||
286 | cv::Mat_<cv::Vec3b>::iterator itend=cimage.end(); |
||
287 | |||
288 | for ( ; it!= itend; it++) { |
||
289 | |||
290 | // process each pixel --------------------- |
||
291 | |||
292 | (*it)[0]= (*it)[0]/div*div + div/2; |
||
293 | (*it)[1]= (*it)[1]/div*div + div/2; |
||
294 | (*it)[2]= (*it)[2]/div*div + div/2; |
||
295 | |||
296 | // end of pixel processing ---------------- |
||
297 | } |
||
298 | } |
||
299 | |||
300 | |||
301 | void colorReduce11(cv::Mat &image, int div=64) { |
||
302 | |||
303 | int nl= image.rows; // number of lines |
||
304 | int nc= image.cols; // number of columns |
||
305 | |||
306 | for (int j=0; j<nl; j++) { |
||
307 | for (int i=0; i<nc; i++) { |
||
308 | |||
309 | // process each pixel --------------------- |
||
310 | |||
311 | image.at<cv::Vec3b>(j,i)[0]= image.at<cv::Vec3b>(j,i)[0]/div*div + div/2; |
||
312 | image.at<cv::Vec3b>(j,i)[1]= image.at<cv::Vec3b>(j,i)[1]/div*div + div/2; |
||
313 | image.at<cv::Vec3b>(j,i)[2]= image.at<cv::Vec3b>(j,i)[2]/div*div + div/2; |
||
314 | |||
315 | // end of pixel processing ---------------- |
||
316 | |||
317 | } // end of line |
||
318 | } |
||
319 | } |
||
320 | |||
321 | // with input/ouput images |
||
322 | void colorReduce12(const cv::Mat &image, // input image |
||
323 | cv::Mat &result, // output image |
||
324 | int div=64) { |
||
325 | |||
326 | int nl= image.rows; // number of lines |
||
327 | int nc= image.cols ; // number of columns |
||
328 | |||
329 | // allocate output image if necessary |
||
330 | result.create(image.rows,image.cols,image.type()); |
||
331 | |||
332 | // created images have no padded pixels |
||
333 | nc= nc*nl; |
||
334 | nl= 1; // it is now a 1D array |
||
335 | |||
336 | int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); |
||
337 | // mask used to round the pixel value |
||
338 | uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 |
||
339 | |||
340 | for (int j=0; j<nl; j++) { |
||
341 | |||
342 | uchar* data= result.ptr<uchar>(j); |
||
343 | const uchar* idata= image.ptr<uchar>(j); |
||
344 | |||
345 | for (int i=0; i<nc; i++) { |
||
346 | |||
347 | // process each pixel --------------------- |
||
348 | |||
349 | *data++= (*idata++)&mask + div/2; |
||
350 | *data++= (*idata++)&mask + div/2; |
||
351 | *data++= (*idata++)&mask + div/2; |
||
352 | |||
353 | // end of pixel processing ---------------- |
||
354 | |||
355 | } // end of line |
||
356 | } |
||
357 | } |
||
358 | |||
359 | // using overloaded operators |
||
360 | void colorReduce13(cv::Mat &image, int div=64) { |
||
361 | |||
362 | int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); |
||
363 | // mask used to round the pixel value |
||
364 | uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 |
||
365 | |||
366 | // perform color reduction |
||
367 | image=(image&cv::Scalar(mask,mask,mask))+cv::Scalar(div/2,div/2,div/2); |
||
368 | } |
||
369 | |||
370 | |||
371 | #define NTESTS 14 |
||
372 | #define NITERATIONS 20 |
||
373 | |||
374 | int main() |
||
375 | { |
||
376 | int64 t[NTESTS],tinit; |
||
377 | cv::Mat image1; |
||
378 | cv::Mat image2; |
||
379 | |||
380 | // timer values set to 0 |
||
381 | for (int i=0; i<NTESTS; i++) |
||
382 | t[i]= 0; |
||
383 | |||
384 | // repeat the tests several times |
||
385 | int n=NITERATIONS; |
||
386 | for (int k=0; k<n; k++) { |
||
387 | |||
388 | std::cout << k << " of " << n << std::endl; |
||
389 | |||
390 | image1= cv::imread("../image.jpg"); |
||
391 | if (!image1.data) |
||
392 | return 0; |
||
393 | |||
394 | // using .ptr and [] |
||
395 | tinit= cv::getTickCount(); |
||
396 | colorReduce0(image1); |
||
397 | t[0]+= cv::getTickCount()-tinit; |
||
398 | |||
399 | image1= cv::imread("../image.jpg"); |
||
400 | // using .ptr and * ++ |
||
401 | tinit= cv::getTickCount(); |
||
402 | colorReduce1(image1); |
||
403 | t[1]+= cv::getTickCount()-tinit; |
||
404 | |||
405 | image1= cv::imread("../image.jpg"); |
||
406 | // using .ptr and * ++ and modulo |
||
407 | tinit= cv::getTickCount(); |
||
408 | colorReduce2(image1); |
||
409 | t[2]+= cv::getTickCount()-tinit; |
||
410 | |||
411 | image1= cv::imread("../image.jpg"); |
||
412 | // using .ptr and * ++ and bitwise |
||
413 | tinit= cv::getTickCount(); |
||
414 | colorReduce3(image1); |
||
415 | t[3]+= cv::getTickCount()-tinit; |
||
416 | |||
417 | image1= cv::imread("../image.jpg"); |
||
418 | // using direct pointer arithmetic |
||
419 | tinit= cv::getTickCount(); |
||
420 | colorReduce4(image1); |
||
421 | t[4]+= cv::getTickCount()-tinit; |
||
422 | |||
423 | image1= cv::imread("../image.jpg"); |
||
424 | // using .ptr and * ++ and bitwise with image.cols * image.channels() |
||
425 | tinit= cv::getTickCount(); |
||
426 | colorReduce5(image1); |
||
427 | t[5]+= cv::getTickCount()-tinit; |
||
428 | |||
429 | image1= cv::imread("../image.jpg"); |
||
430 | // using .ptr and * ++ and bitwise (continuous) |
||
431 | tinit= cv::getTickCount(); |
||
432 | colorReduce6(image1); |
||
433 | t[6]+= cv::getTickCount()-tinit; |
||
434 | |||
435 | image1= cv::imread("../image.jpg"); |
||
436 | // using .ptr and * ++ and bitwise (continuous+channels) |
||
437 | tinit= cv::getTickCount(); |
||
438 | colorReduce7(image1); |
||
439 | t[7]+= cv::getTickCount()-tinit; |
||
440 | |||
441 | image1= cv::imread("../image.jpg"); |
||
442 | // using Mat_ iterator |
||
443 | tinit= cv::getTickCount(); |
||
444 | colorReduce8(image1); |
||
445 | t[8]+= cv::getTickCount()-tinit; |
||
446 | |||
447 | image1= cv::imread("../image.jpg"); |
||
448 | // using Mat_ iterator and bitwise |
||
449 | tinit= cv::getTickCount(); |
||
450 | colorReduce9(image1); |
||
451 | t[9]+= cv::getTickCount()-tinit; |
||
452 | |||
453 | image1= cv::imread("../image.jpg"); |
||
454 | // using Mat_ iterator |
||
455 | tinit= cv::getTickCount(); |
||
456 | colorReduce10(image1); |
||
457 | t[10]+= cv::getTickCount()-tinit; |
||
458 | |||
459 | image1= cv::imread("../image.jpg"); |
||
460 | // using at |
||
461 | tinit= cv::getTickCount(); |
||
462 | colorReduce11(image1); |
||
463 | t[11]+= cv::getTickCount()-tinit; |
||
464 | |||
465 | image1= cv::imread("../image.jpg"); |
||
466 | // using input/output images |
||
467 | tinit= cv::getTickCount(); |
||
468 | cv::Mat result; |
||
469 | colorReduce12(image1, result); |
||
470 | t[12]+= cv::getTickCount()-tinit; |
||
471 | |||
472 | image2= result; |
||
473 | |||
474 | image1= cv::imread("../image.jpg"); |
||
475 | // using input/output images |
||
476 | tinit= cv::getTickCount(); |
||
477 | colorReduce13(image1); |
||
478 | t[13]+= cv::getTickCount()-tinit; |
||
479 | |||
480 | //------------------------------ |
||
481 | } |
||
482 | |||
483 | cv::namedWindow("Result"); |
||
484 | cv::imshow("Result",image2); |
||
485 | cv::namedWindow("Image Result"); |
||
486 | cv::imshow("Image Result",image1); |
||
487 | |||
488 | // print average execution time |
||
489 | std::cout << std::endl << "-------------------------------------------" << std::endl << std::endl; |
||
490 | std::cout << "using .ptr and [] =" << 1000.*t[0]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
491 | std::cout << "using .ptr and * ++ =" << 1000.*t[1]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
492 | std::cout << "using .ptr and * ++ and modulo =" << 1000.*t[2]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
493 | std::cout << "using .ptr and * ++ and bitwise =" << 1000.*t[3]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
494 | std::cout << "using direct pointer arithmetic =" << 1000.*t[4]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
495 | std::cout << "using .ptr and * ++ and bitwise with image.cols * image.channels() =" << 1000.*t[5]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
496 | std::cout << "using .ptr and * ++ and bitwise (continuous) =" << 1000.*t[6]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
497 | std::cout << "using .ptr and * ++ and bitwise (continuous+channels) =" << 1000.*t[7]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
498 | std::cout << "using Mat_ iterator =" << 1000.*t[8]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
499 | std::cout << "using Mat_ iterator and bitwise =" << 1000.*t[9]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
500 | std::cout << "using MatIterator_ =" << 1000.*t[10]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
501 | std::cout << "using at =" << 1000.*t[11]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
502 | std::cout << "using input/output images =" << 1000.*t[12]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
503 | std::cout << "using overloaded operators =" << 1000.*t[13]/cv::getTickFrequency()/n << "ms" << std::endl; |
||
504 | |||
505 | cv::waitKey(); |
||
506 | return 0; |
||
507 | } |