OpenCV几种不同的图像遍历方法分析与对比

学习《OpenCV2计算机视觉编程手册》第二章的学习体会

关键词:图像处理-图像变换-点运算-图像遍历-淡化像素

首先,看一下的基础代码,实现了图片遍历淡化每个像素;

void main()
{    
    Mat image = imread("lena.jpg");
    namedWindow("Image");
    
    colorReduce1(image);
    
    imshow("Image", image);

    waitKey(0);

}
void colorReduce1(Mat &image, int div = 64) //time=2.43ms
{
    int n1 = image.rows;
    int nc = image.cols*image.channels();
    for (int j = 0; j < n1; j++)
    {
        uchar* data = image.ptr<uchar>(j);
        
        for (int i = 0; i < nc; i++)
        data[i] = data[i] / div*div + div / 2;//(data[i]/div)*div
    }

}

书中给了多个图像遍历的方法,附上全部代码,代码如下:

#include <opencv2opencv.hpp>  
#include<iostream>
using namespace cv;

void colorReduce1(Mat &image, int div = 64) //time=2.43ms
{
    int n1 = image.rows;
    int nc = image.cols*image.channels();
    for (int j = 0; j < n1; j++)
    {
        uchar* data = image.ptr<uchar>(j);
        
        for (int i = 0; i < nc; i++)
        data[i] = data[i] / div*div + div / 2;//(data[i]/div)*div
    }

}

void colorReduce2(Mat &image, int div = 64)//time=2.06ms
{
    int n1 = image.rows;
    int nc = image.cols*image.channels();
    if (image.isContinuous())//***
    {
        nc = n1*nc;
        n1 = 1;

    }
    for (int j = 0; j < n1; j++)
    {
        uchar* data = image.ptr<uchar>(j);

        for (int i = 0; i < nc; i++)
            data[i] = data[i] / div*div + div / 2;//(data[i]/div)*div
    }

}


void colorReduce3_iterator(Mat &image, int div = 64)//time=58.15ms
{

    Mat_<Vec3b>::iterator it = image.begin<Vec3b>();
    Mat_<Vec3b>::iterator itend = image.end<Vec3b>();
    for (; it != itend; ++it)
    {
        (*it)[0] = (*it) [0]/ div*div + div / 2;
        (*it)[1] = (*it) [1]/ div*div + div / 2;
        (*it)[2] = (*it) [2]/ div*div + div / 2;

    }


}


void colorReduce4(Mat &image, int div = 64) // mermory slip out //time=97.67ms
{
    int n1 = image.rows;
    int nc = image.cols; //is not nc= image.cols*image.channels();
    
    for (int j = 0; j < n1; j++)
    {
        for (int i = 0; i < nc; i++)
        {
            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;
        }
    }
}

void colorReduce5_fast(Mat &image, int div = 64)//time=1.13ms
{
    int n1 = image.rows;
    int nc = image.cols;    
    if (image.isContinuous())//***
    {
        nc = n1*nc;
        n1 = 1;
    }
    int n = static_cast<int>(log(static_cast<double>(div))/log(2.0));

    uchar mask = 0xff << n;

    for (int j = 0; j < n1; 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;
        }
    }
}



void main()
{    
    Mat image = imread("lena.jpg");

    //Time test
    double tTime;
    tTime = (double)getTickCount();
    const int nTimes = 100;
    for (int i = 0; i < nTimes; i++)
    {
        //algrithom to be test ;
        colorReduce4(image);
    }
    tTime = 1000 * ((double)getTickCount() - tTime) /
        getTickFrequency();
    tTime /= nTimes;
    std::cout << tTime << std::endl;

    namedWindow("Image");
    imshow("Image", image);

    waitKey(0);

}

main()函数中,增加了Time test 函数,为了测试不同的图像遍历方法的运行效率。经过测试,每个遍历方法的运行时间,我已经注释在每一个colorReduce函数的后面。

从以上的结果来看,效率最高最低的排序是:colorReduce5_fast()>colorReduce2()>colorReduce1()>colorReduce3_iterator()>colorReduce4();

效率最高只需要占用1.13ms,效率最低要占用97.67ms。效率相差100倍左右,性能将提升90%以上;

从代码易读性上来排序(个人主观):

colorReduce3_iterator()>colorReduce4()>colorReduce1()>colorReduce2()>colorReduce5_fast();

综合考虑算法处理效率与代码易读性,我通常选择:

colorReduce1()>colorReduce2();

分析,不同的图像遍历方法:

colorReduce5_fast()

 遍历方法:使用指针,减少嵌套循环

>colorReduce2()

 遍历方法:使用指针,减少嵌套循环

>colorReduce1()

遍历方法:使用指针

>colorReduce3_iterator()

 遍历方法:使用迭代器

>colorReduce4()

 遍历方法:使用迭代器at()

从上面的不同的遍历方法来看,得出结论:为了提高遍历效率,尽量使用指针,而不是迭代器;尽量减少嵌套循环;

原文地址:https://www.cnblogs.com/pans0ul/p/9639193.html