• OpenCV学习笔记(三) 访问像素


    转自:OpenCV如何扫描图像、利用查找表和计时

    测试代码:opencvsamplescpp utorial_codecorehow_to_scan_images

    测试函数耗时

    cv::getTickCount()    the number of clock cycle

    cv::getTickFrequency()  the number of cycles per seconds

    double t = (double)getTickCount();
    // 做点什么 ...
    t = ((double)getTickCount() - t)/getTickFrequency();
    cout << "Times passed in seconds: " << t << endl;

    访问像素点

    以颜色缩减为例,可通过查找表替换颜色从而缩减存储,查找表构建方法:

    uchar table[256]; 
    for (int i = 0; i < 256; ++i)
       table[i] = divideWith* (i/divideWith);

    有以下几种访问像素方法:

    1. []运算符 加 查找表

    int nRows = I.rows * I.channels(); 
    int nCols = I.cols;
    
    if (I.isContinuous())
    {
        nCols *= nRows;
        nRows = 1;         
    }
    
    int i,j;
    uchar* p; 
    for( i = 0; i < nRows; ++i)
    {
        p = I.ptr<uchar>(i);
        for ( j = 0; j < nCols; ++j)
        {
            p[j] = table[p[j]];             
        }
    }
    

    我们获取了每一行开始处的指针,然后遍历至该行末尾。如果矩阵是以连续方式存储的,我们只需请求一次指针、然后一路遍历下去就行。彩色图像的情况有必要加以注意:因为三个通道的原因,我们需要遍历的元素数目也是3倍。

    2. 迭代器

    const int channels = I.channels();
    switch(channels)
    {
    case 1: 
        {
            MatIterator_<uchar> it, end; 
            for( it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it)
                *it = table[*it];
            break;
        }
    case 3: 
        {
            MatIterator_<Vec3b> it, end; 
            for( it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it)
            {
                (*it)[0] = table[(*it)[0]];
                (*it)[1] = table[(*it)[1]];
                (*it)[2] = table[(*it)[2]];
            }
        }
    }
    

    在cv::Mat_的子类中,下划线表示这是一个模板类。OpenCV将Mat设计为一个容器,可以这样声明迭代器:

    cv::MatIterator_<cv::Vec3b> it;
    cv::Mat_<cv::Vec3b>::iterator it;
    // 之后就可以使用begin()和end()等方法了
    cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();

    Mat_类型在使用begin和end方法时可以不加类型:

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

    3. On-the-fly 动态计算地址:at()函数

    const int channels = I.channels();
    switch(channels)
    {
    case 1: 
        {
            for( int i = 0; i < I.rows; ++i)
                for( int j = 0; j < I.cols; ++j )
                    I.at<uchar>(i,j) = table[I.at<uchar>(i,j)];
            break;
        }
    case 3: 
        {
         Mat_<Vec3b> _I = I;
            
         for( int i = 0; i < I.rows; ++i)
            for( int j = 0; j < I.cols; ++j )
               {
                   _I(i,j)[0] = table[_I(i,j)[0]];
                   _I(i,j)[1] = table[_I(i,j)[1]];
                   _I(i,j)[2] = table[_I(i,j)[2]];
            }
         I = _I;
         break;
        }
    }
    

    注意:当且仅当在 debug 模式下 它会检查你的输入坐标是否有效或者超出范围。

    cv::Mat_类型可以直接用operator()访问像素,省略.at(),少写两个字。

    cv::Mat_<uchar> im2= image; // im2 refers to image
    im2(50,100)= 0; // access to row 50 and column 100

    4. 核心函数LUT(The core function)

    Mat lookUpTable(1, 256, CV_8U);
    uchar* p = lookUpTable.data; 
    for( int i = 0; i < 256; ++i)
        p[i] = table[i];
    LUT(I, lookUpTable, J);
    

    对于一个给定的值,将其替换成其他的值是一个很常见的操作,OpenCV 提供里一个函数直接实现该操作,并不需要你自己扫描图像,就是:operationsOnArrays:LUT() <lut> ,一个包含于core module的函数。

    性能表现

    4. LUT > 1. Efficient way > 2. Iterator > 3. On-The-Fly random access

    输入:600*450

    输出:

    Time of reducing with the C operator [] (averaged for 100 runs): 4.05264 milliseconds.
    Time of reducing with the iterator (averaged for 100 runs): 137.583 milliseconds.
    Time of reducing with the on-the-fly address generation - at function (averaged for 100 runs): 255.371 milliseconds.
    Time of reducing with the LUT function (averaged for 100 runs): 3.51129 milliseconds.

    结论: 尽量使用 OpenCV 内置函数. 调用LUT 函数可以获得最快的速度. 这是因为OpenCV库可以通过英特尔线程架构启用多线程. 

  • 相关阅读:
    ES6 Symbol类型 附带:Proxy和Set
    why updating the Real DOM is slow, what is Virtaul DOM, and how updating Virtual DOM increase the performance?
    React高级指南
    池(Pool)
    计算机网络Intro
    React基础
    CommonJS 与 ES6 的依赖操作方法(require、import)
    webpack初识(biaoyansu)
    关于时间安排贪心算法正确性的证明
    DP总结
  • 原文地址:https://www.cnblogs.com/ericxing/p/3576747.html
Copyright © 2020-2023  润新知