zoukankan      html  css  js  c++  java
  • 【OpenCV】访问Mat中每个像素的值

    转载:http://blog.csdn.net/xiaowei_cqu/article/details/19839019

    Color Reduce

    使用经典的 Reduce Color的例子,即对图像中的像素表达进行量化。如常见的RGB24图像有256×256×256中颜色,通过Reduce Color将每个通道的像素减少8倍至256/8=32种,则图像只有32×32×32种颜色。假设量化减少的倍数是N,则代码实现时就是简单的 value/N*N,通常我们会再加上N/2以得到相邻的N的倍数的中间值,最后图像被量化为(256/N)×(256/N)×(256/N)种颜色。

    方法零:.ptr和[]操作符

    Mat最直接的访问方法是通过.ptr<>函数得到一行的指针,并用[]操作符访问某一列的像素值。

    1. // using .ptr and []  
    2. void colorReduce0(cv::Mat &image, int div=64) {  
    3.       int nr= image.rows; // number of rows  
    4.       int nc= image.cols * image.channels(); // total number of elements per line  
    5.       for (int j=0; j<nr; j++) {  
    6.           uchar* data= image.ptr<uchar>(j);  
    7.           for (int i=0; i<nc; i++) {  
    8.                   data[i]= data[i]/div*div + div/2;  
    9.             }                    
    10.       }  
    11. }  


    方法一:.ptr和指针操作

    除了[]操作符,我们可以移动指针*++的组合方法访问某一行中所有像素的值。

    1. // using .ptr and * ++   
    2. void colorReduce1(cv::Mat &image, int div=64) {  
    3.       int nr= image.rows; // number of rows  
    4.       int nc= image.cols * image.channels(); // total number of elements per line  
    5.       for (int j=0; j<nr; j++) {  
    6.           uchar* data= image.ptr<uchar>(j);  
    7.           for (int i=0; i<nc; i++) {  
    8.                  *data++= *data/div*div + div/2;  
    9.             } // end of row                   
    10.       }  
    11. }  


    方法二:.ptr、指针操作和取模运算

    方法二和方法一的访问方式相同,不同的是color reduce用模运算代替整数除法

    1. // using .ptr and * ++ and modulo  
    2. void colorReduce2(cv::Mat &image, int div=64) {  
    3.       int nr= image.rows; // number of rows  
    4.       int nc= image.cols * image.channels(); // total number of elements per line  
    5.       for (int j=0; j<nr; j++) {  
    6.           uchar* data= image.ptr<uchar>(j);  
    7.           for (int i=0; i<nc; i++) {  
    8.                   int v= *data;  
    9.                   *data++= v - v%div + div/2;  
    10.             } // end of row                   
    11.       }  
    12. }  


    方法三:.ptr、指针运算和位运算

    由于进行量化的单元div通常是2的整次方,因此所有的乘法和除法都可以用位运算表示。

    1. // using .ptr and * ++ and bitwise  
    2. void colorReduce3(cv::Mat &image, int div=64) {  
    3.       int nr= image.rows; // number of rows  
    4.       int nc= image.cols * image.channels(); // total number of elements per line  
    5.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
    6.       // mask used to round the pixel value  
    7.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
    8.       for (int j=0; j<nr; j++) {  
    9.           uchar* data= image.ptr<uchar>(j);  
    10.           for (int i=0; i<nc; i++) {  
    11.             *data++= *data&mask + div/2;  
    12.             } // end of row                   
    13.       }  
    14. }  


    方法四:指针运算

    方法四和方法三量化处理的方法相同,不同的是用指针运算代替*++操作。

    1. // direct pointer arithmetic  
    2. void colorReduce4(cv::Mat &image, int div=64) {  
    3.       int nr= image.rows; // number of rows  
    4.       int nc= image.cols * image.channels(); // total number of elements per line  
    5.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
    6.       int step= image.step; // effective width  
    7.       // mask used to round the pixel value  
    8.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
    9.       // get the pointer to the image buffer  
    10.       uchar *data= image.data;  
    11.       for (int j=0; j<nr; j++) {  
    12.           for (int i=0; i<nc; i++) {  
    13.             *(data+i)= *data&mask + div/2;  
    14.             } // end of row                   
    15.             data+= step;  // next line  
    16.       }  
    17. }  


    方法五:.ptr、*++、位运算以及image.cols * image.channels()

    这种方法就是没有计算nc,基本是个充数的方法。

    1. // using .ptr and * ++ and bitwise with image.cols * image.channels()  
    2. void colorReduce5(cv::Mat &image, int div=64) {  
    3.       int nr= image.rows; // number of rows  
    4.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
    5.       // mask used to round the pixel value  
    6.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
    7.       for (int j=0; j<nr; j++) {  
    8.           uchar* data= image.ptr<uchar>(j);  
    9.           for (int i=0; i<image.cols * image.channels(); i++) {  
    10.             *data++= *data&mask + div/2;  
    11.             } // end of row                   
    12.       }  
    13. }  

    方法六:连续图像

    Mat提供了isContinuous()函数用来查看Mat在内存中是不是连续存储,如果是则图片被存储在一行中。

    1. // using .ptr and * ++ and bitwise (continuous)  
    2. void colorReduce6(cv::Mat &image, int div=64) {  
    3.       int nr= image.rows; // number of rows  
    4.       int nc= image.cols * image.channels(); // total number of elements per line  
    5.       if (image.isContinuous())  {  
    6.           // then no padded pixels  
    7.           nc= nc*nr;   
    8.           nr= 1;  // it is now a 1D array  
    9.        }  
    10.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
    11.       // mask used to round the pixel value  
    12.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
    13.       for (int j=0; j<nr; j++) {  
    14.           uchar* data= image.ptr<uchar>(j);  
    15.           for (int i=0; i<nc; i++) {  
    16.             *data++= *data&mask + div/2;  
    17.             } // end of row                   
    18.       }  
    19. }  


    方法七:continuous+channels

    与方法六基本相同,也是充数的。

    1. // using .ptr and * ++ and bitwise (continuous+channels)  
    2. void colorReduce7(cv::Mat &image, int div=64) {  
    3.       int nr= image.rows; // number of rows  
    4.       int nc= image.cols ; // number of columns  
    5.       if (image.isContinuous())  {  
    6.           // then no padded pixels  
    7.           nc= nc*nr;   
    8.           nr= 1;  // it is now a 1D array  
    9.        }  
    10.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
    11.       // mask used to round the pixel value  
    12.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
    13.       for (int j=0; j<nr; j++) {  
    14.           uchar* data= image.ptr<uchar>(j);  
    15.           for (int i=0; i<nc; i++) {  
    16.             *data++= *data&mask + div/2;  
    17.             *data++= *data&mask + div/2;  
    18.             *data++= *data&mask + div/2;  
    19.             } // end of row                   
    20.       }  
    21. }  


    方法八:Mat _iterator

    真正有区别的方法来啦,用Mat提供的迭代器代替前面的[]操作符或指针,血统纯正的官方方法~

    1. // using Mat_ iterator   
    2. void colorReduce8(cv::Mat &image, int div=64) {  
    3.       // get iterators  
    4.       cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();  
    5.       cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>();  
    6.       for ( ; it!= itend; ++it) {  
    7.         (*it)[0]= (*it)[0]/div*div + div/2;  
    8.         (*it)[1]= (*it)[1]/div*div + div/2;  
    9.         (*it)[2]= (*it)[2]/div*div + div/2;  
    10.       }  
    11. }  

    方法九:Mat_ iterator 和位运算

    把方法八中的乘除法换成位运算。

    1. // using Mat_ iterator and bitwise  
    2. void colorReduce9(cv::Mat &image, int div=64) {  
    3.       // div must be a power of 2  
    4.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
    5.       // mask used to round the pixel value  
    6.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
    7.       // get iterators  
    8.       cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();  
    9.       cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>();  
    10.       for ( ; it!= itend; ++it) {  
    11.         (*it)[0]= (*it)[0]&mask + div/2;  
    12.         (*it)[1]= (*it)[1]&mask + div/2;  
    13.         (*it)[2]= (*it)[2]&mask + div/2;  
    14.       }  
    15. }  


    方法十:MatIterator_

    和方法八基本相同。

    1. // using MatIterator_   
    2. void colorReduce10(cv::Mat &image, int div=64) {  
    3.       cv::Mat_<cv::Vec3b> cimage= image;  
    4.       cv::Mat_<cv::Vec3b>::iterator it=cimage.begin();  
    5.       cv::Mat_<cv::Vec3b>::iterator itend=cimage.end();  
    6.       for ( ; it!= itend; it++) {   
    7.         (*it)[0]= (*it)[0]/div*div + div/2;  
    8.         (*it)[1]= (*it)[1]/div*div + div/2;  
    9.         (*it)[2]= (*it)[2]/div*div + div/2;  
    10.       }  
    11. }  

    方法十一:图像坐标

    1. // using (j,i)  
    2. void colorReduce11(cv::Mat &image, int div=64) {  
    3.       int nr= image.rows; // number of rows  
    4.       int nc= image.cols; // number of columns  
    5.       for (int j=0; j<nr; j++) {  
    6.           for (int i=0; i<nc; i++) {  
    7.                   image.at<cv::Vec3b>(j,i)[0]=     image.at<cv::Vec3b>(j,i)[0]/div*div + div/2;  
    8.                   image.at<cv::Vec3b>(j,i)[1]=     image.at<cv::Vec3b>(j,i)[1]/div*div + div/2;  
    9.                   image.at<cv::Vec3b>(j,i)[2]=     image.at<cv::Vec3b>(j,i)[2]/div*div + div/2;  
    10.             } // end of row                   
    11.       }  
    12. }  


    方法十二:创建输出图像

    之前的方法都是直接修改原图,方法十二新建了输出图像,主要用于后面的时间对比。

    1. // with input/ouput images  
    2. void colorReduce12(const cv::Mat &image, // input image   
    3.                  cv::Mat &result,      // output image  
    4.                  int div=64) {  
    5.       int nr= image.rows; // number of rows  
    6.       int nc= image.cols ; // number of columns  
    7.       // allocate output image if necessary  
    8.       result.create(image.rows,image.cols,image.type());  
    9.       // created images have no padded pixels  
    10.       nc= nc*nr;   
    11.       nr= 1;  // it is now a 1D array  
    12.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
    13.       // mask used to round the pixel value  
    14.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
    15.       for (int j=0; j<nr; j++) {  
    16.           uchar* data= result.ptr<uchar>(j);  
    17.           const uchar* idata= image.ptr<uchar>(j);  
    18.           for (int i=0; i<nc; i++) {  
    19.             *data++= (*idata++)&mask + div/2;  
    20.             *data++= (*idata++)&mask + div/2;  
    21.             *data++= (*idata++)&mask + div/2;  
    22.           } // end of row                   
    23.       }  
    24. }  


    方法十三:重载操作符

    Mat重载了+&等操作符,可以直接将两个Scalar(B,G,R)数据进行位运算和数学运算。

    1. // using overloaded operators  
    2. void colorReduce13(cv::Mat &image, int div=64) {  
    3.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
    4.       // mask used to round the pixel value  
    5.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
    6.       // perform color reduction  
    7.       image=(image&cv::Scalar(mask,mask,mask))+cv::Scalar(div/2,div/2,div/2);  
    8. }  


    时间对比

    通过迭代二十次取平均时间,得到每种方法是运算时间如下。

    可以看到,指针*++访问和位运算是最快的方法;而不断的计算image.cols*image.channles()花费了大量重复的时间;另外迭代器访问虽然安全,但性能远低于指针运算;通过图像坐标(j,i)访问时最慢的,使用重载操作符直接运算效率最高。

  • 相关阅读:
    POJ 1426 Find The Multiple(数论——中国同余定理)
    POJ 2253 Frogger(Dijkstra变形——最短路径最大权值)
    POJ 3790 最短路径问题(Dijkstra变形——最短路径双重最小权值)
    POJ 3278 Catch That Cow(模板——BFS)
    HDU 1071 The area
    HDU 1213 How Many Tables(模板——并查集)
    POJ 1611 The Suspects
    light oj 1214 Large Division
    POJ 1258 Agri-Net(Prim算法求解MST)
    POJ 2387 Til the Cows Come Home(模板——Dijkstra算法)
  • 原文地址:https://www.cnblogs.com/souxun2014/p/4070036.html
Copyright © 2011-2022 走看看