OpenCV2计算机视觉应用编程手册(自学版)初级三

OpenCV2计算机视觉应用编程手册(自学版)初级三

// 时间:2014年11月30日00:22:56

 //   例子:降低图像的颜色数目 256*256*256--->64*64*64

 

/******************************************************************************************

 本节列出来中访问图像各个像素的方法,有的方法执行速度快一些,有的会慢一些。

 采用指针的方法访问大的图像数据速度较快,如果用移位运算符代替乘除法运算速度会更加

 快一些。如果能够减少运算的次数,执行速度会增加一些。(废话好多)

 也可以使用迭代器进行访问,但是运行会慢一些,也可以使用.at的方式直接操作像素,但是

 执行效率不高,因为.at的操作方法一般应用于随机访问图像中的某些点。

 // 建议

 1--------------   在循环过程中,要避免本来能够提前计算的数据反复的计算,这可以节省很多时间

 int nc=image.cols*image.channels();

    ...

for(int i=0;i<nc;i++)

{

  ...

}

 

如果上面的这个循环过程换成

for(int i=0;i<image.cols*image.channels();i++)

{

  ..

}

    在下面这个循环中你需要反复计算每一行的元素总数,其运算速度比第一个降低80%

 

2----------------- 执行速度最快的算法:

 

 /***************************************************

 方法: 使用指针指针地址自加移位运算符判断图像有没有padded

   采用方法:       *data++= *data&mask + div/2;

                     *data++= *data&mask + div/2;

                     *data++= *data&mask + div/2;

   虽然采用这种方法计算步骤一样,但是这种方法执行效率较高

   这样可以减少循环的次数。

   在调试DM642的时候,程序优化一节也讲到了这种用法,

   不知道是不是C语言都是这样。      

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                   

      }

}

 3--------------- 判断一个程序运行时间长短的方法

    tinit= cv::getTickCount();//开始进行计时

   colorReduce10(image1);// 运行我们要测试的程序

   time = cv::getTickCount()-tinit;//停止计时

   time=time /cv::getTickFrequency();// us

   time=time*1000;//ms

 // 最后得到的这个time就是我们的程序实际运行了多长时间,时间单位是ms



**************************************************************************************/

#include "stdafx.h"  

#include<iostream>

#include <opencv2/opencv.hpp> 

using namespace std;// 使用STD

using namespace cv;// 使用名字空间

 

// using .ptr and []

/***************************************************

 方法0: 使用指针扫描图像

 使用:       *

  第一个地址对应的是图像的左上角对应的像素的地址,Opencv中颜色通道的排列是BGR

  和微软的RGB正好反过来了

 

****************************************************/

 

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                   

      }

}

 

/***************************************************

 方法1: 使用指针地址自加

 

       指针的地址自动增加

****************************************************/

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

      }

}

/***************************************************

 方法2: 使用指针地址自加

 

****************************************************/

 

 

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

      }

}

/***************************************************

 方法3: 使用指针地址自加移位操作

 

       使用移位操作运算

****************************************************/

 

 

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

      }

}

 

/***************************************************

 方法4: 使用指针扫描图像

 

       使用立即指针运算,调用step,使指针指向下一行

   的首地址

****************************************************/

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

      }

}

/***************************************************

 方法5: 使用指针地址自加移位操作

 

       指针自加移位操作符

****************************************************/

 

 

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

      }

}

/***************************************************

 方法6: 使用指针地址自加移位操作判断图像的每一行的像素有没有添加Padded

 

       指针的地址自动增加

****************************************************/

 

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

      // 判断图像的每一行的像素有没有添加Padded

  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                   

      }

}

/***************************************************

 方法7: 使用指针指针地址自加移位运算符判断图像有没有padded

   采用方法:       *data++= *data&mask + div/2;

                     *data++= *data&mask + div/2;

                     *data++= *data&mask + div/2;

   虽然采用这种方法计算步骤一样,但是这种方法执行效率较高

   这样可以减少循环的次数。

   在调试DM642的时候,程序优化一节也讲到了这种用法,

   不知道是不是C语言都是这样。

       

****************************************************/

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

      }

}

 

/***************************************************

 方法8: 使用迭代器扫描图像

   采用方法:  

   在面向对象编程中,循环访问的数据量较大的时候,都是使用

   迭代器的方法。

   注意:使用迭代器的主要目的是为了简化扫描的过程,使扫描

   尽可能少的出现错误,而并没有考虑到优化程序的运行过程,所

   以采用迭代器的方法运行速度会慢一些。

 

****************************************************/

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

  }

}

/***************************************************

 方法9: 使用迭代器扫描图像+移位操作(代替除法运算)

   采用方法:  

   在面向对象编程中,循环访问的数据量较大的时候,都是使用

   迭代器的方法。

 

****************************************************/

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

  }

}

/***************************************************

 方法10: 使用迭代器模板

   采用方法:  

   在面向对象编程中,循环访问的数据量较大的时候,都是使用

   迭代器的方法。但是迭代器的执行速率好像不是很好,没接触过

 

****************************************************/

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

  }

}

/***************************************************

 方法11: 使用at方法访问图像的像素

 注意:

     使用at的方法循环扫描大的数据块的时候,效率是比较低的

 at一般用在随机访问图像中某个像素点,而不是访问大的数据块。

 

****************************************************/

 

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                   

      }

}

/***************************************************

 方法12:

 

     在函数中包含了输入和输出。这个地方会多占用一部分时间

 多占用的时间是因为opencv需要给输出result分配内存空间

****************************************************/

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

      }

}

/***************************************************

 方法13:

使用运算符重载操作。这个地方Opencv+进行了运算符重载

这使得我们可以直接对两个矩阵相加。

大多数的C++ 操作符都被重载了

****************************************************/

// 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 //为了保证计算的时间准确,我们对上面这14个程序循环运行了20次,然后求平均

int n=NITERATIONS;

for (int k=0; k<n; k++) {

 

std::cout << k << " of " << n << std::endl; 

 

image1= cv::imread("F:\\house.jpg");

    if (!image1.data)

   return 0; 

 

// using .ptr and []

    tinit= cv::getTickCount();

colorReduce0(image1);

t[0]+= cv::getTickCount()-tinit;

 

 

 

image1= cv::imread("F:\\house.jpg");

// using .ptr and * ++ 

    tinit= cv::getTickCount();

colorReduce1(image1);

t[1]+= cv::getTickCount()-tinit;

 

image1= cv::imread("F:\\house.jpg");

// using .ptr and * ++ and modulo

    tinit= cv::getTickCount();

   colorReduce2(image1);

   t[2]+= cv::getTickCount()-tinit;

 

    image1= cv::imread("F:\\house.jpg");

// using .ptr and * ++ and bitwise

    tinit= cv::getTickCount();

colorReduce3(image1);

t[3]+= cv::getTickCount()-tinit;

 

image1= cv::imread("F:\\house.jpg");

// using direct pointer arithmetic

    tinit= cv::getTickCount();

colorReduce4(image1);

t[4]+= cv::getTickCount()-tinit;

 

image1= cv::imread("F:\\house.jpg");

// using .ptr and * ++ and bitwise with image.cols * image.channels()

    tinit= cv::getTickCount();

colorReduce5(image1);

t[5]+= cv::getTickCount()-tinit;

 

image1= cv::imread("F:\\house.jpg");

// using .ptr and * ++ and bitwise (continuous)

    tinit= cv::getTickCount();

colorReduce6(image1);

t[6]+= cv::getTickCount()-tinit;

 

image1= cv::imread("F:\\house.jpg");

// using .ptr and * ++ and bitwise (continuous+channels)

    tinit= cv::getTickCount();

colorReduce7(image1);

t[7]+= cv::getTickCount()-tinit;

 

image1= cv::imread("F:\\house.jpg");

// using Mat_ iterator

    tinit= cv::getTickCount();

colorReduce8(image1);

t[8]+= cv::getTickCount()-tinit;

 

image1= cv::imread("F:\\house.jpg");

// using Mat_ iterator and bitwise

    tinit= cv::getTickCount();

colorReduce9(image1);

t[9]+= cv::getTickCount()-tinit;

 

image1= cv::imread("F:\\house.jpg");

// using Mat_ iterator 

    tinit= cv::getTickCount();

colorReduce10(image1);

t[10]+= cv::getTickCount()-tinit;

 

image1= cv::imread("F:\\house.jpg");

// using at 

    tinit= cv::getTickCount();

colorReduce11(image1);

t[11]+= cv::getTickCount()-tinit;

image1= cv::imread("F:\\house.jpg");

// using input/output images 

    tinit= cv::getTickCount();

cv::Mat result;

colorReduce12(image1, result);

t[12]+= cv::getTickCount()-tinit;

 

image2= result;

image1= cv::imread("F:\\house.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;

}

 运行结果:

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值