OpenCV学习C++接口 Mat像素遍历详解

来源:互联网 发布:get it right 编辑:程序博客网 时间:2024/06/05 20:54

    IplImage像素遍历和Mat之间的转换请看下一篇博文,

学习总结:

  

  1. 当Mat为多通道时,如3通道,如果我们将其内容输出到终端,则可以看出其列数为Mat::colsn倍,意思是说显示数据的时候r、g、b安顺输出,然后输出下一个像素的r、g、b,当然nMat的通道数。虽是如此,但是Mat::cols的数值并没有随之改变。
  2. 当复制一副图像时,利用函数cv::Mat::clone(),则将在内存中重新开辟一段新的内存存放复制的图像(图像数据也将全部复制),而如果利用cv::Mat::copyTo()复制图像,则不会在内存中开辟一段新的内存块,同时也不会复制图像数据,复制前后的图像的指针指向同一个内存块。使用的时候需注意两个函数的区别。
  3. 因为自从openCv可以用c++方式实现之后,我们可以使用迭代器和at的方式方式遍历像素,不过at几乎是所有方式中效率最低的一种,iterator的方式比使用at的方式好一点,这种方式比较安全和简单易懂明了。
  4. 在openCv 2计算机视觉一书中降到的像素压缩:利用位操作的算法效率最高,其次是利用整数除法中向下取整,效率最低的是取模运算。
代码如下,可以仔细研究一下和分析一下:
/*****************************************************************    内容摘要:本例采用8种方法对图像Mat的像素进行扫描,并对像素点的像*            素进行压缩,压缩间隔为div=64,并比较扫描及压缩的效率,效*            率最高的是采用.ptr及减少循环次数来遍历图像,并采用位操*            作来对图像像素进行压缩。*   参考资料:《OpenCV 2 computer Vision Application Programming*              cookbook》****************************************************************/#include <opencv2/core/core.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <opencv2/highgui/highgui.hpp>#include <iostream>//利用.ptr和数组下标进行图像像素遍历void colorReduce0(cv::Mat &image, int div = 64){    int nl = image.rows;    int nc = image.cols * image.channels();        //遍历图像的每个像素    for(int j=0; j<nl ;++j)    {        uchar *data = image.ptr<uchar>(j);        for(int i=0; i<nc; ++i)        {            data[i] = data[i]/div*div+div/2;     //减少图像中颜色总数的关键算法:if div = 64, then the total number of colors is 4x4x4;整数除法时,是向下取整。        }    }}//利用.ptr和 *++ 进行图像像素遍历void colorReduce1(cv::Mat &image, int div = 64){    int nl = image.rows;    int nc = image.cols * image.channels();        //遍历图像的每个像素    for(int j=0; j<nl ;++j)    {        uchar *data = image.ptr<uchar>(j);        for(int i=0; i<nc; ++i)        {            *data++ = *data/div*div + div/2;        }    }}//利用.ptr和数组下标进行图像像素遍历,取模运算用于减少图像颜色总数void colorReduce2(cv::Mat &image, int div = 64){    int nl = image.rows;    int nc = image.cols * image.channels();        //遍历图像的每个像素    for(int j=0; j<nl ;++j)    {        uchar *data = image.ptr<uchar>(j);        for(int i=0; i<nc; ++i)        {            data[i] = data[i]-data[i]%div +div/2;  //利用取模运算,速度变慢,因为要读每个像素两次        }    }}//利用.ptr和数组下标进行图像像素遍历,位操作运算用于减少图像颜色总数void colorReduce3(cv::Mat &image, int div = 64){    int nl = image.rows;    int nc = image.cols * image.channels();    int n = static_cast<int>(log(static_cast<double>(div))/log(2.0));   //div=64, n=6    uchar mask = 0xFF<<n;                                            //e.g. div=64, mask=0xC0        //遍历图像的每个像素    for(int j=0; j<nl ;++j)    {        uchar *data = image.ptr<uchar>(j);        for(int i=0; i<nc; ++i)        {            *data++ = *data&mask + div/2;        }    }}//形参传入const conference,故输入图像不会被修改;利用.ptr和数组下标进行图像像素遍历void colorReduce4(const cv::Mat &image, cv::Mat &result,int div = 64){    int nl = image.rows;    int nc = image.cols * image.channels();    result.create(image.rows,image.cols,image.type());        //遍历图像的每个像素    for(int j=0; j<nl ;++j)    {        const uchar *data_in = image.ptr<uchar>(j);        uchar *data_out = result.ptr<uchar>(j);        for(int i=0; i<nc; ++i)        {            data_out[i] = data_in[i]/div*div+div/2;     //减少图像中颜色总数的关键算法:if div = 64, then the total number of colors is 4x4x4;整数除法时,是向下取整。        }    }}//利用.ptr和数组下标进行图像像素遍历,并将nc放入for循环中(比较糟糕的做法)void colorReduce5(cv::Mat &image, int div = 64){    int nl = image.rows;        //遍历图像的每个像素    for(int j=0; j<nl ;++j)    {        uchar *data = image.ptr<uchar>(j);        for(int i=0; i<image.cols * image.channels(); ++i)        {            data[i] = data[i]/div*div+div/2;     //减少图像中颜色总数的关键算法:if div = 64, then the total number of colors is 4x4x4;整数除法时,是向下取整。        }    }}//利用迭代器 cv::Mat iterator 进行图像像素遍历void colorReduce6(cv::Mat &image, int div = 64){    cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>();    //由于利用图像迭代器处理图像像素,因此返回类型必须在编译时知道    cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>();    for(;it != itend; ++it)    {        (*it)[0] = (*it)[0]/div*div+div/2;        //利用operator[]处理每个通道的像素        (*it)[1] = (*it)[1]/div*div+div/2;        (*it)[2] = (*it)[2]/div*div+div/2;    }}//利用.at<cv::Vec3b>(j,i)进行图像像素遍历void colorReduce7(cv::Mat &image, int div = 64){    int nl = image.rows;    int nc = image.cols;        //遍历图像的每个像素    for(int j=0; j<nl ;++j)    {        for(int i=0; i<nc; ++i)        {            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;        }    }}//减少循环次数,进行图像像素遍历,调用函数较少,效率最高。void colorReduce8(cv::Mat &image, int div = 64){    int nl = image.rows;    int nc = image.cols;    //判断是否是连续图像,即是否有像素填充    if(image.isContinuous())    {        nc = nc*nl;        nl = 1;    }    int n = static_cast<int>(log(static_cast<double>(div))/log(2.0));    uchar mask = 0xFF<<n;        //遍历图像的每个像素    for(int j=0; j<nl ;++j)    {        uchar *data = image.ptr<uchar>(j);        for(int i=0; i<nc; ++i)        {            *data++ = *data & mask +div/2;            *data++ = *data & mask +div/2;            *data++ = *data & mask +div/2;        }    }}const int NumTests = 9;        //测试算法的数量const int NumIteration = 20;   //迭代次数int main(int argc, char* argv[]){    int64 t[NumTests],tinit;    cv::Mat image1;    cv::Mat image2;        //数组初始化    int i=0;    while(i<NumTests)    {        t[i++] = 0;    }    int n = NumIteration;        //迭代n次,取平均数    for(int i=0; i<n; ++i)    {        image1 = cv::imread("../boldt.jpg");        if(!image1.data)        {            std::cout<<"read image failue!"<<std::endl;            return -1;        }        // using .ptr and []        tinit = cv::getTickCount();        colorReduce0(image1);        t[0] += cv::getTickCount() - tinit;                // using .ptr and *++        image1 = cv::imread("../boldt.jpg");        tinit = cv::getTickCount();        colorReduce1(image1);        t[1] += cv::getTickCount()  - tinit;                // using .ptr and [] and modulo        image1 = cv::imread("../boldt.jpg");        tinit = cv::getTickCount();        colorReduce2(image1);        t[2] += cv::getTickCount()  - tinit;                // using .ptr and *++ and bitwise        image1 = cv::imread("../boldt.jpg");        tinit = cv::getTickCount();        colorReduce3(image1);        t[3] += cv::getTickCount()  - tinit;        //using input and output image        image1 = cv::imread("../boldt.jpg");        tinit = cv::getTickCount();        colorReduce4(image1,image2);        t[4] += cv::getTickCount()  - tinit;                // using .ptr and [] with image.cols * image.channels()        image1 = cv::imread("../boldt.jpg");        tinit = cv::getTickCount();        colorReduce5(image1);        t[5] += cv::getTickCount()  - tinit;                // using .ptr and *++ and iterator        image1 = cv::imread("../boldt.jpg");        tinit = cv::getTickCount();        colorReduce6(image1);        t[6] += cv::getTickCount()  - tinit;                //using at        image1 = cv::imread("../boldt.jpg");        tinit = cv::getTickCount();        colorReduce7(image1);        t[7] += cv::getTickCount()  - tinit;        //using .ptr and * ++ and bitwise (continuous+channels)        image1 = cv::imread("../boldt.jpg");        tinit = cv::getTickCount();        colorReduce8(image1);        t[8] += cv::getTickCount()  - tinit;    }    cv::namedWindow("Result");    cv::imshow("Result",image1);    cv::namedWindow("Result Image");    cv::imshow("Result Image",image2);    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 input and output image = "<<1000*t[4]/cv::getTickFrequency()/n<<"ms"<<std::endl;    std::cout<<"using .ptr and [] with image.cols * image.channels() = "<<1000*t[5]/cv::getTickFrequency()/n<<"ms"<<std::endl;    std::cout<<"using .ptr and *++ and iterator = "<<1000*t[6]/cv::getTickFrequency()/n<<"ms"<<std::endl;    std::cout<<"using at = "<<1000*t[7]/cv::getTickFrequency()/n<<"ms"<<std::endl;    std::cout<<"using .ptr and * ++ and bitwise (continuous+channels) = "<<1000*t[8]/cv::getTickFrequency()/n<<"ms"<<std::endl;    std::cout<<std::endl<<"-------------------------------------------------------------------------"<<std::endl<<std::endl;    cv::waitKey();    return 0;}


0 0
原创粉丝点击