码迷,mamicode.com
首页 > 其他好文 > 详细

OpenCV扫描图像、利用查找表和计时的方法

时间:2015-10-22 12:11:34      阅读:378      评论:0      收藏:0      [点我收藏+]

标签:

对于一副图像,如果矩阵元素存储的是单通道像素,使用C或C++的无符号字符类型,那么像素可有256个不同值。但若是三通道图像,这种存储格式的颜色数就太多了(确切地说,有一千六百多万种)。用如此之多的颜色可能会对我们的算法性能造成严重影响。其实有时候,仅用这些颜色的一小部分,就足以达到同样效果。

这种情况下,常用的一种方法是 颜色空间缩减 

其做法是:将现有颜色空间值除以某个输入值,以获得较少的颜色数。例如,颜色值0到9可取为新值0,10到19可取为10,以此类推。

uchar (无符号字符,即0到255之间取值的数)类型的值除以 int 值,结果仍是 char 。因为结果是char类型的,所以求出来小数也要向下取整。利用这一点,刚才提到在 uchar 定义域中进行的颜色缩减运算就可以表达为下列形式:

                                                                                                         技术分享

这样的话,简单的颜色空间缩减算法就可由下面两步组成:一、遍历图像矩阵的每一个像素;二、对像素应用上述公式。值得注意的是,我们这里用到了除法和乘法运算,而这两种运算又特别费时,所以,我们应尽可能用代价较低的加、减、赋值等运算替换它们。此外,还应注意到,上述运算的输入仅能在某个有限范围内取值,如 uchar 类型可取256个值。

由此可知,对于较大的图像,有效的方法是预先计算所有可能的值,然后需要这些值的时候,利用查找表直接赋值即可。查找表是一维或多维数组,存储了不同输入值所对应的输出值,其优势在于只需读取。

图像矩阵是如何存储在内存之中的?

图像矩阵的大小取决于我们所用的颜色模型,确切地说,取决于所用通道数。如果是灰度图像,矩阵就会像这样:

技术分享

而对多通道图像来说,矩阵中的列会包含多个子列,其子列个数与通道数相等。例如,RGB颜色模型的矩阵:

技术分享

注意到,子列的通道顺序是反过来的:BGR而不是RGB。

很多情况下,因为内存足够大,可实现连续存储,因此,图像中的各行就能一行一行地连接起来,形成一个长行。连续存储有助于提升图像扫描速度,我们可以使用isContinuous() 来去判断矩阵是否是连续存储的.

遍历图像像素的方法:

1,直接用C风格的内存访问操作符[]遍历图像

技术分享
Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)
{
// accept only char type matrices
    CV_Assert(I.depth() != sizeof(uchar));     

    int channels = I.channels();

    int nRows = I.rows ; 
    int nCols = I.cols* channels;

    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]];             
                       }
    }
    return I; 

}
View Code

2,迭代器iterator遍历图像

技术分享
Mat& ScanImageAndReduceIterator(Mat& I, const uchar* const table)
{
    // accept only char type matrices
    CV_Assert(I.depth() != sizeof(uchar));     

    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]];
            }
        }
    }

    return I; 
}
View Code

3,动态地址计算遍历图像

技术分享
Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar* const table)
{
    // accept only char type matrices
    CV_Assert(I.depth() != sizeof(uchar));     

    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;
        }
    }

    return I;
}
View Code

 

 

//////////////////////////////////////////////////////////////

以下程序完成的功能:

1、以命令行参数形式读入图像,并用命令行参数给出的整数进行颜色缩减;

2、使用3中图像像素遍历的方法;

3、介绍并使用查找表的核心函数LUT;

4、介绍并使用时间计时函数getTickCount(),getTickFrequency();

    getTickCount()函数返回CPU自某个事件以来走过的时钟周期数;

    getTickFrequency()函数返回CPU一秒钟所走的时钟周期数.       

double t = (double)getTickCount();

     // do something...

    t=((double)getTickCount() - t)/getTickFrequency();

备注:t 结果为以秒为单位;

---------------------------------------------------------------------------------------------------------------------------------------------------------------

 扩展:

 

精确获取时间:

 

QueryPerformanceFrequency() - 基本介绍

 

类型:Win32API

 

原型:BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);

 

作用:返回硬件支持的高精度计数器的频率。

 

返回值:非零,硬件支持高精度计数器;零,硬件不支持,读取失败。

 

QueryPerformanceFrequency() - 技术特点

 

供WIN9X使用的高精度定时器:QueryPerformanceFrequency()和QueryPerformanceCounter(),要求计算机从硬件上支持高精度定时器。需包含windows.h头文件。

 

函数的原形是:

 

BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);

 

BOOL QueryPerformanceCounter (LARGE_INTEGER *lpCount);

 

数据类型LARGEINTEGER既可以是一个作为8字节长的整数,也可以是作为两个4字节长的整数的联合结构,其具体用法根据编译器是否支持64位而定。

-----------------------------------------------------------------------------------------------------------------------------------------------

 

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

 

参考博客及网页:1,http://www.cppblog.com/deane/articles/113151.html

                     2,http://blog.csdn.net/xiaowei_cqu/article/details/7771760

                     3,http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/core/how_to_scan_images/how_to_scan_images.html#howtoscanimagesopencv

 

OpenCV扫描图像、利用查找表和计时的方法

标签:

原文地址:http://www.cnblogs.com/chen-cqupt/p/4900396.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!