Subversion Repositories OpenCV2-Cookbook

Rev

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
}