opencv学习摘要(图像存储以及访问)

基本的opencv模块
cv---核心函数库
cvaux--辅助函数库
cxcore-数据结构与线性代数库
highgui-gui函数库(graphical user interface)
ml-机器学习函数库


Linux opencv编译
g++ hello-world.cpp -o hello-world \
    -I /usr/local/include/opencv -L /usr/local/lib  \
    -lm -lcv -lhighgui -lcvaux
其中
 /usr/local/include/opencv 为opencv头文件目录.
 /usr/local/lib为库文件目录
 -lcv -lhighgui -lcvaux为链接库文件参数.
 
在不同的linux版本下,头文件可能包含不一样

--------------------------------------------------------------
Mat img = imread(filename,0); //直接创建灰度图像

在函数中传递图像是家常便饭,为了不降低程序速度,opencv使用引用计数机制,其思路是让每个Mat对象有自己的信息头,但共享同一个矩阵。这通过让矩阵指针指向同一地址而实现。而拷贝构造函数则只拷贝信息头和矩阵指针,而不拷贝矩阵。

 

示例1

Mat A,C;

A = imread(argv[1], CV_LOAD_IMAGE_COLOR);

 

Mat B(A);

C = A; // A,B,C统统指向同一个数据矩阵。

负责清理这个数据矩阵的对象,根据引用计数机制,找到最后一个使用它的对象。

 

如果想拷贝矩阵本身,可以使用函数clone()或者copyTo()

Mat F = A.clone();

Mat G;

A.copyTo(G);

 

Mat() 构造函数

    Mat M(2,2, CV_8UC3, Scalar(0,0,255)); 

    cout << "M = " << endl << " " << M << endl << endl;   

 

比如 CV_8UC3 表示使用8位的 unsigned char 型,每个像素由三个元素组成三通道。预先定义的通道数可以多达四个。 Scalar 是个short型vector。指定这个能够使用指定的定制化值来初始化矩阵。当然,如果你需要更多通道数,你可以使用大写的宏并把通道数放在小括号中。

解释一下,为什么2*2矩阵,会是上图中绿色部分,因为3通道的原因,默认是1通道。

 

 

  int sz[3] = {2,2,2}; 

    Mat L(3,sz, CV_8UC(1), Scalar::all(0));

上面的例子演示了如何创建一个超过两维的矩阵:指定维数,然后传递一个指向一个数组的指针,这个数组包含每个维度的尺寸;其余的相同

 

 

***为已存在IplImage指针创建信息头:

IplImage* img = cvLoadImage("greatwave.png", 1);

Mat mtx(img); // convert IplImage* -> Mat

 

***使用 clone() 或者 copyTo() 为一个存在的 Mat 对象创建一个新的信息头。

    Mat RowClone = C.row(1).clone();

    cout << "RowClone = " << endl << " " << RowClone << endl << endl;

 

***基于cv::Mat的std::vector

    vector<float> v;

    v.push_back( (float)CV_PI);   v.push_back(2);    v.push_back(3.01f);

    

    cout << "Vector of floats via Mat = " << Mat(v) << endl << endl;

 

 

Vector 也是矩阵。

 

 

如何遍历图像中的每一个像素?

Opencv的矩阵值是如何存储的?

如何测试我们所实现算法的性能?

查找表是什么?为什么要用它?

 

 

 

颜色空间缩减算法(为了使得颜色空间缩小),步骤:

遍历每一个像素;

对像素应用固定公式(向下取整,颜色值0到9可取为新值0,10到19可取为10,以此类推。),如下图。

 

 

根据上式可以建立查找表,从而得到两种颜色空间的映射空间,通过查找表是一种聪明的方法,省去了每次都来计算。

 

代码如下:

    int divideWith; // convert our input string to number - C++ style

    stringstream s;

    s << argv[2];

    s >> divideWith;

    if (!s)

    {

        cout << "Invalid number entered for dividing. " << endl; 

        return -1;

    }

    

    uchar table[256]; 

    for (int i = 0; i < 256; ++i)

       table[i] = divideWith* (i/divideWith);

 

 

 

 

 

 

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

double t = (double)getTickCount();

// 做点什么 ...

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

cout << "Times passed in seconds: " << t << endl;

 

 

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

连续存储或非连续存储,可以使用 isContinuous() 来去判断矩阵是否是连续存储的.

R,G,B,b存在最前面,g其次,r最后。

 

图像访问?

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 nCols = I.cols* channels;  //因为三个通道的原因,我们需要遍历//的元素数目也是3倍

    int nRows = I.rows;

 

    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; 

}

 

迭代法

 

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; //对于彩色图像中的一行,每列// 中有3个uchar元素,这可以被认为是一个小的包含uchar元素的vector,// 在OpenCV中用 Vec3b 来命名。

            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; 

}

 

 

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

这是最被推荐的用于实现批量图像元素查找和更该操作图像方法。在图像处理中,对于一个给定的值,将其替换成其他的值是一个很常见的操作,OpenCV 提供里一个函数直接实现该操作,并不需要你自己扫描图像,就是:operationsOnArrays:LUT() <lut> ,一个包含于core module的函数. 首先我们建立一个mat型用于查表:

    Mat lookUpTable(1, 256, CV_8U);

    uchar* p = lookUpTable.data; 

    for( int i = 0; i < 256; ++i)

        p[i] = table[i];

 

然后我们调用函数 (I 是输入 J 是输出):

        LUT(I, lookUpTable, J);

 

 

 

我们得出一些结论: 尽量使用 OpenCV 内置函数. 调用LUT 函数可以获得最快的速度. 这是因为OpenCV库可以通过英特尔线程架构启用多线程. 当然,如果你喜欢使用指针的方法来扫描图像,迭代法是一个不错的选择,不过速度上较慢。在debug模式下使用on-the-fly方法扫描全图是一个最 浪费资源的方法,在release模式下它的表现和迭代法相差无几,但是从安全性角度来考虑,迭代法是更佳的选择。

Onthefly就是使用at函数。

你可能感兴趣的:(opencv)