opencv 笔记02Core_Scan

来源:互联网 发布:数据挖掘与r语言 源码 编辑:程序博客网 时间:2024/05/28 11:28

1. OpenCV提供了两个简便的可用于计时的函数 getTickCount() 和 getTickFrequency() 。第一个函数返回你的CPU自某个事件(如启动电脑)以来走过的时钟周期数,第二个函数返回你的CPU一秒钟所走的时钟周期数。这样,我们就能轻松地以秒为单位对某运算计时:

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


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

\newcommand{\tabItG}[1] { \textcolor{black}{#1} \cellcolor[gray]{0.8}}\begin{tabular} {ccccc}~ & \multicolumn{1}{c}{Column 0} &   \multicolumn{1}{c}{Column 1} &   \multicolumn{1}{c}{Column ...} & \multicolumn{1}{c}{Column m}\\Row 0 & \tabItG{0,0} & \tabItG{0,1} & \tabItG{...}  & \tabItG{0, m} \\Row 1 & \tabItG{1,0} & \tabItG{1,1} & \tabItG{...}  & \tabItG{1, m} \\Row ... & \tabItG{...,0} & \tabItG{...,1} & \tabItG{...} & \tabItG{..., m} \\Row n & \tabItG{n,0} & \tabItG{n,1} & \tabItG{n,...} & \tabItG{n, m} \\\end{tabular}

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

\newcommand{\tabIt}[1] { \textcolor{yellow}{#1} \cellcolor{blue} &  \textcolor{black}{#1} \cellcolor{green} & \textcolor{black}{#1} \cellcolor{red}}\begin{tabular} {ccccccccccccc}~ & \multicolumn{3}{c}{Column 0} &   \multicolumn{3}{c}{Column 1} &   \multicolumn{3}{c}{Column ...} & \multicolumn{3}{c}{Column m}\\Row 0 & \tabIt{0,0} & \tabIt{0,1} & \tabIt{...}  & \tabIt{0, m} \\Row 1 & \tabIt{1,0} & \tabIt{1,1} & \tabIt{...}  & \tabIt{1, m} \\Row ... & \tabIt{...,0} & \tabIt{...,1} & \tabIt{...} & \tabIt{..., m} \\Row n & \tabIt{n,0} & \tabIt{n,1} & \tabIt{n,...} & \tabIt{n, m} \\\end{tabular}

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

1.高效的方法 Efficient Way

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 * 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]];                     }    }    return I; }
另一种方法:使用datadata会从 Mat 中返回指向矩阵第一行第一列的指针。注意如果该指针为NULL则表明对象里面无输入

uchar* p = I.data;for( unsigned int i =0; i < ncol*nrows; ++i)    *p++ = table[*p];

2.迭代法 The iterator (safe) method

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; }
对于彩色图像中的一行,每列中有3个uchar元素,这可以被认为是一个小的包含uchar元素的vector,在OpenCV中用 Vec3b 来命名。如果要访问第n个子列,我们只需要简单的利用[]来操作就可以。OpenCV的迭代在扫描过一行中所有列后会自动跳至下一行

3. 通过相关返回值的On-the-fly地址计算

事实上这个方法并不推荐被用来进行图像扫描,它本来是被用于获取或更改图像中的随机元素
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;}
为避免反复输入数据类型和at带来的麻烦和浪费的时间,OpenCV 提供了:basicstructures:Mat_ <id3> data type. 它同样可以被用于获知矩阵的数据类型

4. 核心函数LUT(The Core Function)

在图像处理中,对于一个给定的值,将其替换成其他的值是一个很常见的操作
operationsOnArrays:LUT() <lut> ,一个包含于core module的函数
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);
I 是输入 J 是输出

性能表现

Efficient Way79.4717 millisecondsIterator83.7201 millisecondsOn-The-Fly RA93.7878 millisecondsLUT function32.5759 milliseconds

结论:推荐LUT批量查改,Efficient、Iterator其次,On-The-Fly随即存储