Subversion Repositories OpenCV2-Cookbook

Rev

View as "text/plain" | Blame | Last modification | View Log | RSS feed

1
/*------------------------------------------------------------------------------------------*\
   This file contains material supporting chapter 2 of the cookbook:  
   Computer Vision Programming using the OpenCV Library.
   by Robert Laganiere, Packt Publishing, 2011.

   This program is free software; permission is hereby granted to use, copy, modify,
   and distribute this source code, or portions thereof, for any purpose, without fee,
   subject to the restriction that the copyright notice may not be removed
   or altered from any source or altered source distribution.
   The software is released on an as-is basis and without any warranties of any kind.
   In particular, the software is not guaranteed to be fault-tolerant or free from failure.
   The author disclaims all warranties with regard to this software, any use,
   and any consequent failure, is purely the responsibility of the user.
 
   Copyright (C) 2010-2011 Robert Laganiere, www.laganiere.name
\*------------------------------------------------------------------------------------------*/


#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("../image.jpg");
            if (!image1.data)
                   return 0;

                // using .ptr and []
            tinit= cv::getTickCount();
                colorReduce0(image1);
                t[0]+= cv::getTickCount()-tinit;

                image1= cv::imread("../image.jpg");
                // using .ptr and * ++
            tinit= cv::getTickCount();
                colorReduce1(image1);
                t[1]+= cv::getTickCount()-tinit;

                image1= cv::imread("../image.jpg");
                // using .ptr and * ++ and modulo
            tinit= cv::getTickCount();
                colorReduce2(image1);
                t[2]+= cv::getTickCount()-tinit;

                image1= cv::imread("../image.jpg");
                // using .ptr and * ++ and bitwise
            tinit= cv::getTickCount();
                colorReduce3(image1);
                t[3]+= cv::getTickCount()-tinit;

                image1= cv::imread("../image.jpg");
                // using direct pointer arithmetic
            tinit= cv::getTickCount();
                colorReduce4(image1);
                t[4]+= cv::getTickCount()-tinit;

                image1= cv::imread("../image.jpg");
                // using .ptr and * ++ and bitwise with image.cols * image.channels()
            tinit= cv::getTickCount();
                colorReduce5(image1);
                t[5]+= cv::getTickCount()-tinit;

                image1= cv::imread("../image.jpg");
                // using .ptr and * ++ and bitwise (continuous)
            tinit= cv::getTickCount();
                colorReduce6(image1);
                t[6]+= cv::getTickCount()-tinit;

                image1= cv::imread("../image.jpg");
                // using .ptr and * ++ and bitwise (continuous+channels)
            tinit= cv::getTickCount();
                colorReduce7(image1);
                t[7]+= cv::getTickCount()-tinit;

                image1= cv::imread("../image.jpg");
                // using Mat_ iterator
            tinit= cv::getTickCount();
                colorReduce8(image1);
                t[8]+= cv::getTickCount()-tinit;

                image1= cv::imread("../image.jpg");
                // using Mat_ iterator and bitwise
            tinit= cv::getTickCount();
                colorReduce9(image1);
                t[9]+= cv::getTickCount()-tinit;

                image1= cv::imread("../image.jpg");
                // using Mat_ iterator
            tinit= cv::getTickCount();
                colorReduce10(image1);
                t[10]+= cv::getTickCount()-tinit;

                image1= cv::imread("../image.jpg");
                // using at
            tinit= cv::getTickCount();
                colorReduce11(image1);
                t[11]+= cv::getTickCount()-tinit;
               
                image1= cv::imread("../image.jpg");
                // using input/output images
            tinit= cv::getTickCount();
                cv::Mat result;
                colorReduce12(image1, result);
                t[12]+= cv::getTickCount()-tinit;

                image2= result;
               
                image1= cv::imread("../image.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;
}