zoukankan      html  css  js  c++  java
  • 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库可以通过英特尔线程架构启用多线程. 

  • 相关阅读:
    GitLab 介绍
    git 标签
    git 分支
    git 仓库 撤销提交 git reset and 查看本地历史操作 git reflog
    git 仓库 回退功能 git checkout
    python 并发编程 多进程 练习题
    git 命令 查看历史提交 git log
    git 命令 git diff 查看 Git 区域文件的具体改动
    POJ 2608
    POJ 2610
  • 原文地址:https://www.cnblogs.com/ericxing/p/3576747.html
Copyright © 2011-2022 走看看