Pixel Operating Performance Comparison of openCV Images

1. Test environment

1, test code (copy Mao's demo directly)

//--------------------------------------------------------[Procedure Description]-------------------------------------
//		Program description: Introduction to OpenCV3 Programming OpenCV2 Book Companion sample program 24
//		Program description: An example from an OpenCV2 book from a foreign country - 14 ways to traverse image pixels
//		IDE version for testing: Visual Studio 2010
//		OpenCV version for development and testing: 	 3.0 beta
//		December 2014 Revised by @Light Ink_ Hair Nebula
//------------------------------------------------------------------------------------------------


/*------------------------------------------------------------------------------------------*\
   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
\*------------------------------------------------------------------------------------------*/


//-------------------------------------[Header file, namespace contains part]-------------------------------------------------------------------------------------------------------------------------
//		Description: Contains header files and namespaces used by the program
//-------------------------------------------------------------------------------------------------
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;



//------------------------------------ - [Macro Definition Part]------------------------------------------------------------------------------------------------------------------------------------------
//		Description: Contains macro definitions used by programs
//-------------------------------------------------------------------------------------------------
#define NTESTS 14
#define NITERATIONS 20



//---------------------------------------------------[Method 1]----------------------------------------------------------------------------------------------------------------------------------------
//		Description: Utilization. ptr and []
//-------------------------------------------------------------------------------------------------
void colorReduce0(Mat &image, int div=64) {

	  int nl= image.rows; //Number of rows
	  int nc= image.cols * image.channels(); //Total number of elements per row
              
      for (int j=0; j<nl; j++) 
	  {

		  uchar* data= image.ptr<uchar>(j);

          for (int i=0; i<nc; i++) 
		  {
 
            //---------------- Start processing each pixel-------------------
                 
                  data[i]= data[i]/div*div + div/2;
 
            //------------------- End Pixel Processing-------------------------
 
            } //End of single line processing                  
      }
}

//-----------------------------------------[Method 2]--------------------------------------------------------------------------------------------------------------------------------------------------
//		Description: Utilization. ptr and * ++ 
//-------------------------------------------------------------------------------------------------
void colorReduce1(Mat &image, int div=64) {

	  int nl= image.rows; //Number of rows
	  int nc= image.cols * image.channels(); //Total number of elements per row
              
      for (int j=0; j<nl; j++) 
	  {

		  uchar* data= image.ptr<uchar>(j);

          for (int i=0; i<nc; i++) 
		  {
 
            //---------------- Start processing each pixel-------------------
                 
				 *data++= *data/div*div + div/2;
 
            //------------------- End Pixel Processing-------------------------
 
            } //End of single line processing              
      }
}

//-------------------------------------------------[Method 3]------------------------------------------------------------------------------------------------------------------------------------------
//		Description: Utilization. ptr and * + + and modular operations
//-------------------------------------------------------------------------------------------------
void colorReduce2(Mat &image, int div=64) {

	  int nl= image.rows; //Number of rows
	  int nc= image.cols * image.channels(); //Total number of elements per row
              
      for (int j=0; j<nl; j++) 
	  {

		  uchar* data= image.ptr<uchar>(j);

          for (int i=0; i<nc; i++) 
		  {
 
            //---------------- Start processing each pixel-------------------
       
			      int v= *data;
                  *data++= v - v%div + div/2;
 
            //------------------- End Pixel Processing-------------------------
 
            } //End of single line processing                   
      }
}

//--------------------------------------------------------------[Method 4]-------------------------------------
//		Description: Utilization. ptr and * + + and bitwise operations
//----------------------------------------------------------------------------------------------------
void colorReduce3(Mat &image, int div=64) {

	  int nl= image.rows; //Number of rows
	  int nc= image.cols * image.channels(); //Total number of elements per row
	  int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
	  //Mask 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++) {
 
            //------------------ Start processing each pixel---------------------
                 
            *data++= *data&mask + div/2;
 
            //------------------- End Pixel Processing-------------------------
            }  //End of single line processing            
      }
}


//--------------------------------------------------------------[Method 5]-----------------------------------------
//		Description: Using pointer arithmetic
//---------------------------------------------------------------------------------------------------
void colorReduce4(Mat &image, int div=64) {

	  int nl= image.rows; //Number of rows
	  int nc= image.cols * image.channels(); //Total number of elements per row
	  int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
	  int step= image.step; //Effective Width
	  //Mask value
	  uchar mask= 0xFF<<n; // e.g. For div=16, mask= 0xF0
              
      //Get a pointer to the image buffer
	  uchar *data= image.data;

      for (int j=0; j<nl; j++)
	  {

          for (int i=0; i<nc; i++) 
		  {
 
            //---------------- Start processing each pixel-------------------
                 
            *(data+i)= *data&mask + div/2;
 
            //------------------- End Pixel Processing-------------------------
 
            } //End of single line processing              

            data+= step;  // next line
      }
}

//-----------------------------------------------[Method 6]----------------------------------------------------------------------------------------------------------------------------------------------
//		Description: Utilization. ptr and * ++ as well as bitwise operations, images. Cols * image. Channels()
//-------------------------------------------------------------------------------------------------
void colorReduce5(Mat &image, int div=64) {

	  int nl= image.rows; //Number of rows
	  int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
	  //Mask value
	  uchar mask= 0xFF<<n; // e.g. 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++) 
		  {
 
            //---------------- Start processing each pixel-------------------
                 
            *data++= *data&mask + div/2;
 
            //------------------- End Pixel Processing-------------------------
 
            } //End of single line processing            
      }
}

// -------------------------------------------[Method Seven]----------------------------------------------------------------------------------------------------------------------------------------------
//		Description: Utilization. ptr and * + + and bitwise operations (continuous)
//-------------------------------------------------------------------------------------------------
void colorReduce6(Mat &image, int div=64) {

	  int nl= image.rows; //Number of rows
	  int nc= image.cols * image.channels(); //Total number of elements per row

	  if (image.isContinuous())  
	  {
		  //No Filled Pixels
		  nc= nc*nl; 
		  nl= 1;  // Is a one-dimensional column
	   }

	  int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
	  //Mask value
	  uchar mask= 0xFF<<n; // e.g. div=16, mask=0xF0
              
      for (int j=0; j<nl; j++) {

		  uchar* data= image.ptr<uchar>(j);

          for (int i=0; i<nc; i++) {
 
            //---------------- Start processing each pixel-------------------
                 
            *data++= *data&mask + div/2;
 
            //------------------- End Pixel Processing-------------------------
 
            } //End of single line processing                   
      }
}

//------------------------------------------------------[Method 8]-----------------------------------------------
//		Description: Utilization. ptr and * + + and bitwise operations (continuous+channels)
//-------------------------------------------------------------------------------------------------
void colorReduce7(Mat &image, int div=64) {

	  int nl= image.rows; //Number of rows
	  int nc= image.cols ; //Number of columns

	  if (image.isContinuous())  
	  {
		  //No Filled Pixels
		  nc= nc*nl; 
		  nl= 1;  // Is a one-dimensional array
	   }

	  int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
	  //Mask value
	  uchar mask= 0xFF<<n; // e.g. div=16, mask=0xF0
              
      for (int j=0; j<nl; j++) {

		  uchar* data= image.ptr<uchar>(j);

          for (int i=0; i<nc; i++) {
 
            //---------------- Start processing each pixel-------------------
                 
            *data++= *data&mask + div/2;
            *data++= *data&mask + div/2;
            *data++= *data&mask + div/2;
 
            //------------------- End Pixel Processing-------------------------
 
            } //End of single line processing                    
      }
}


// ---------------------------------------[Method 9]----------------------------------------------------------------------------------------------------------------------------------------------------
//		Description: Using Mat_ iterator
//-------------------------------------------------------------------------------------------------
void colorReduce8(Mat &image, int div=64) {

	  //Get Iterator
	  Mat_<Vec3b>::iterator it= image.begin<Vec3b>();
	  Mat_<Vec3b>::iterator itend= image.end<Vec3b>();

	  for ( ; it!= itend; ++it) {
        
		//---------------- Start processing 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 Pixel Processing-------------------------
	  }//End of single line processing  
}

//-------------------------------------------[Method 10]--------------------------------------------------------------------------------------------------------------------------------------------------
//		Description: Using Mat_ iterator and bitwise operations
//-------------------------------------------------------------------------------------------------
void colorReduce9(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 value
	  uchar mask= 0xFF<<n; // e.g. div=16, mask=0xF0

	  // Get Iterator
	  Mat_<Vec3b>::iterator it= image.begin<Vec3b>();
	  Mat_<Vec3b>::iterator itend= image.end<Vec3b>();

	  //Scan all elements
	  for ( ; it!= itend; ++it) 
	  {
        
		//---------------- Start processing each pixel-------------------

        (*it)[0]= (*it)[0]&mask + div/2;
        (*it)[1]= (*it)[1]&mask + div/2;
        (*it)[2]= (*it)[2]&mask + div/2;

        //------------------- End Pixel Processing-------------------------
	  }//End of single line processing  
}

//------------------------------------------------------[Method 11]-------------------------------------------
//		Description: Using Mat Iterator_
//-------------------------------------------------------------------------------------------------
void colorReduce10(Mat &image, int div=64) {

	  //Get Iterator
	  Mat_<Vec3b> cimage= image;
	  Mat_<Vec3b>::iterator it=cimage.begin();
	  Mat_<Vec3b>::iterator itend=cimage.end();

	  for ( ; it!= itend; it++) { 
        
		//---------------- Start processing 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 Pixel Processing-------------------------
	  }
}

//----------------------------------------------------------[Method 12]-------------------------------------------
//		Note: Use dynamic address calculation with at
//-------------------------------------------------------------------------------------------------
void colorReduce11(Mat &image, int div=64) {

	  int nl= image.rows; //Number of rows
	  int nc= image.cols; //Number of columns
              
      for (int j=0; j<nl; j++) 
	  {
          for (int i=0; i<nc; i++) 
		  {
 
            //---------------- Start processing each pixel-------------------
                 
                  image.at<Vec3b>(j,i)[0]=	 image.at<Vec3b>(j,i)[0]/div*div + div/2;
                  image.at<Vec3b>(j,i)[1]=	 image.at<Vec3b>(j,i)[1]/div*div + div/2;
                  image.at<Vec3b>(j,i)[2]=	 image.at<Vec3b>(j,i)[2]/div*div + div/2;
 
            //------------------- End Pixel Processing-------------------------
 
            } //End of single line processing                 
      }
}

//--------------------------------------------------[Method 13]----------------------------------------------------------------------------------------------------------------------------- 
//		Description: Use the input and output of images
//-------------------------------------------------------------------------------------------------
void colorReduce12(const Mat &image, //input image
                 Mat &result,      // Output Image
                 int div=64) {

	  int nl= image.rows; //Number of rows
	  int nc= image.cols ; //Number of columns

	  //Prepare the initialized Mat for the output image
	  result.create(image.rows,image.cols,image.type());

	  //Create an image without a pixel fill
	  nc= nc*nl; 
	  nl= 1;  //Single-dimensional array

	  int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
	  //Mask value
	  uchar mask= 0xFF<<n; // e.g. 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++) {
 
            //---------------- Start processing each pixel-------------------
                 
            *data++= (*idata++)&mask + div/2;
            *data++= (*idata++)&mask + div/2;
            *data++= (*idata++)&mask + div/2;
 
            //------------------- End Pixel Processing-------------------------
 
          } //End of single line processing                   
      }
}

//------------------------------------------------------------[Method 14]------------------------------------- 
//		Description: Operator overloading
//-------------------------------------------------------------------------------------------------
void colorReduce13(Mat &image, int div=64) {
	
	  int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
	  //Mask value
	  uchar mask= 0xFF<<n; // e.g. div=16, mask=0xF0

	  //Color Restoration
	  image=(image&Scalar(mask,mask,mask))+Scalar(div/2,div/2,div/2);
}




//---------------------------------------[ShowHelpText() Function]-----------------------------------------
//		Description: Output some help information
//----------------------------------------------------------------------------------------------
void ShowHelpText()
{
	//Output Welcome Message and OpenCV Version
	printf("\n\n\t\t\t Thank you very much for purchasing the OpenCV3 Getting Started with Programming!\n");
	printf("\n\n\t\t\t This is the book OpenCV3 Version 24 companion sample program\n");
	printf("\n\n\t\t\t   Currently used OpenCV Version:" CV_VERSION );
	printf("\n\n  ----------------------------------------------------------------------------\n");

	printf("\n\n Access operation in progress, please wait...\n\n");
}




//-----------------------------------------[main() function]----------------------------------------------------------------------------------------------------------------------------------------------
//		Description: Entry function for console applications, where our programs start
//-------------------------------------------------------------------------------------------------
int main( )
{
	int64 t[NTESTS],tinit;
	Mat image0;
	Mat image1;
	Mat image2;

	system("color 4F");

	ShowHelpText();

	image0= imread("1.png");
	if (!image0.data)
		return 0; 

	//Time value set to 0
	for (int i=0; i<NTESTS; i++)
		t[i]= 0;


	// Multiple Repeat Tests
	int n=NITERATIONS;
	for (int k=0; k<n; k++)
	{
		cout << k << " of " << n << endl; 

		image1= imread("1.png");
		//[Method 1] Utilization. ptr and []
	    tinit= getTickCount();
		colorReduce0(image1);
		t[0]+= getTickCount()-tinit;

		//[Method 2] Utilization. ptr and * ++ 
		image1= imread("1.png");
	    tinit= getTickCount();
		colorReduce1(image1);
		t[1]+= getTickCount()-tinit;

		//[Method 3] Utilization. ptr and * + + and modular operations
		image1= imread("1.png");
	    tinit= getTickCount();
		colorReduce2(image1);
		t[2]+= getTickCount()-tinit;

		//[Method 4] Utilization. ptr and * + + and bitwise operations
		image1= imread("1.png");
	    tinit= getTickCount();
		colorReduce3(image1);
		t[3]+= getTickCount()-tinit;

		//[Method 5] Arithmetic operations using pointers
		image1= imread("1.png");
	    tinit= getTickCount();
		colorReduce4(image1);
		t[4]+= getTickCount()-tinit;

		//[Method 6] Utilization. ptr and * ++ as well as bitwise operations, images. Cols * image. Channels()
		image1= imread("1.png");
	    tinit= getTickCount();
		colorReduce5(image1);
		t[5]+= getTickCount()-tinit;

		//[Method 7] Utilization. ptr and * + + and bitwise operations (continuous)
		image1= imread("1.png");
	    tinit= getTickCount();
		colorReduce6(image1);
		t[6]+= getTickCount()-tinit;

		//[Method 8] Utilization. ptr and * + + and bitwise operations (continuous+channels)
		image1= imread("1.png");
	    tinit= getTickCount();
		colorReduce7(image1);
		t[7]+= getTickCount()-tinit;

		//[Method 9] Using Mat_ iterator
		image1= imread("1.png");
	    tinit= getTickCount();
		colorReduce8(image1);
		t[8]+= getTickCount()-tinit;

		//[Method 10] Using Mat_ iterator and bitwise operations
		image1= imread("1.png");
	    tinit= getTickCount();
		colorReduce9(image1);
		t[9]+= getTickCount()-tinit;

		//[Method 11] Using Mat Iterator_
		image1= imread("1.png");
	    tinit= getTickCount();
		colorReduce10(image1);
		t[10]+= getTickCount()-tinit;

		//[Method 12] Using dynamic address calculation with at
		image1= imread("1.png");
	    tinit= getTickCount();
		colorReduce11(image1);
		t[11]+= getTickCount()-tinit;

		//[Method 13] Using the input and output of images
		image1= imread("1.png");
	    tinit= getTickCount();
		Mat result;
		colorReduce12(image1, result);
		t[12]+= getTickCount()-tinit;
		image2= result;
		
		//[Method 14] Overload using operators
		image1= imread("1.png");
	    tinit= getTickCount();
		colorReduce13(image1);
		t[13]+= getTickCount()-tinit;

		//------------------------------
	}
	 //Output Image   
	imshow("original image",image0);
	imshow("Result",image2);
	imshow("Image Results",image1);

	// Output Average Execution Time
	cout << endl << "-------------------------------------------" << endl << endl;
	cout << "\n[Method 1) Utilization.ptr and []The method takes time " << 1000.*t[0]/getTickFrequency()/n << "ms" << endl;
	cout << "\n[Method 2) Utilization .ptr and * ++ The method takes time" << 1000.*t[1]/getTickFrequency()/n << "ms" << endl;
	cout << "\n[Method 3) Utilization.ptr and * ++ And the method of modular operation takes time" << 1000.*t[2]/getTickFrequency()/n << "ms" << endl;
	cout << "\n[Method 4) Utilization.ptr and * ++ And bitwise methods take time" << 1000.*t[3]/getTickFrequency()/n << "ms" << endl;
	cout << "\n[Method 5) The time spent using pointer arithmetic is" << 1000.*t[4]/getTickFrequency()/n << "ms" << endl;
	cout << "\n[Method 6) Utilization .ptr and * ++And bitwise operations, channels()The method takes time" << 1000.*t[5]/getTickFrequency()/n << "ms" << endl;
	cout << "\n[Method 7) Utilization.ptr and * ++ And bitwise operations(continuous)The method takes time" << 1000.*t[6]/getTickFrequency()/n << "ms" << endl;
	cout << "\n[Method 8) Utilization .ptr and * ++ And bitwise operations (continuous+channels)The method takes time" << 1000.*t[7]/getTickFrequency()/n << "ms" << endl;
	cout << "\n[Method 9) Utilization Mat_ iterator The method takes time" << 1000.*t[8]/getTickFrequency()/n << "ms" << endl;
	cout << "\n[Method 10) Utilization Mat_ iterator And bitwise operations take time" << 1000.*t[9]/getTickFrequency()/n << "ms" << endl;
	cout << "\n[Method 11) Utilization Mat Iterator_The method takes time" << 1000.*t[10]/getTickFrequency()/n << "ms" << endl;	
	cout << "\n[Method 12) Using dynamic address calculation cooperation at The method takes time" << 1000.*t[11]/getTickFrequency()/n << "ms" << endl;	
	cout << "\n[Method 13) The time required to use the input and output methods of images is" << 1000.*t[12]/getTickFrequency()/n << "ms" << endl;	
	cout << "\n[Method 14) The time spent using operator overloaded methods is" << 1000.*t[13]/getTickFrequency()/n << "ms" << endl;	
	
	waitKey();
	return 0;
}

2. Test environment

debug and release

2. EXPERIMENTAL RESULTS

debug

[Method 1] Utilization. The ptr and [] methods took 2.13719ms
[Method 2] Utilization. The ptr and * ++ methods took 2.15145 MS
[Method 3] Utilization. The ptr and *++ and modulo methods take 2.43551ms
[Method 4] Utilization. ptr and * ++ and bit manipulation methods take 1.57605ms
[Method 5] The time spent using pointer arithmetic operation is 1.37929 MS
[Method 6] Utilization. The ptr and * ++ and bitwise operations, channels() methods, take 12.1ms
[Method 7] Utilization. The ptr and * ++ and continuous methods take 1.53903ms
[Method 8] Utilization. The ptr and * ++ and continuous + channels methods take 1.43114ms
[Method 9] Using Mat_ The iterator's method took 57.5071ms
[Method 10] Using Mat_ iterator and bitwise operation methods take 51.401ms
[Method 11] Using Mat Iterator_ The method took 79.1194ms
[Method 12] Using dynamic address calculation with at method takes 100.264ms
[Method 13] The time required to use the input and output methods of images is 1.43578ms
[Method 14] The method using operator overload took 13.788ms

release

[Method 1] Utilization. The ptr and [] methods took 0.320915ms
[Method 2] Utilization. The ptr and * ++ methods took 0.33472ms
[Method 3] Utilization. ptr and *++ and modular methods take 0.40099ms
[Method 4] Utilization. ptr and *++ and bit manipulation methods take 0.048485ms
[Method 5] The time spent using pointer arithmetic is 0.26262 MS
[Method 6] Utilization. The ptr and * ++ and bitwise operations, channels() methods, take 0.528075ms
[Method 7] Utilization. The ptr and * ++ and continuous methods take 0.04556ms
[Method 8] Utilization. The ptr and * ++ and continuous + channels methods take 0.21111ms
[Method 9] Using Mat_ The iterator's method took 0.533575ms
[Method 10] Using Mat_ iterator and bitwise operation methods take 0.517735ms
[Method 11] Using Mat Iterator_ The method took 0.59938ms
[Method 12] The time spent using dynamic address calculation with at method is 0.56409ms
[Method 13] The time required to use the input and output methods of images is 0.2284ms
[Method 14] The method using operator overload took 9.66469ms

3. Analysis

1, release is better than debug optimization

2. Method 5, 8, 13 is efficient and can be used as a reference when writing code experiments.

Keywords: OpenCV AI Computer Vision

Added by ghornet on Tue, 04 Jan 2022 20:18:01 +0200