1.Opencv API reference

一 介绍

Opencv是一个基于BSD (Berkeley Software Distribution,伯克利软件套件)的开源库。

它包含了多种计算机视觉算法。2.x版本是C++风格的API,而1.x版本是C风格的。目前还有3.x版本,具体几个版本的区别待日后有了了解再进行补充。

Opencv具有模块化的结构,因此它的包包含了一些共享的和静态的库。下面为一些可用的模块:

  • core  该模块定义了基础的数据结构。包括多维阵列Mat和一些其他模块经常用到的基本函数。
  • imgproc 图像处理模块,包括线性和非线性滤波,几何变换,色彩空间转换,直方图变换等。
  • video 视频分析模块,包括运动估计,背景分离和物体跟踪算法。
  • calib3D 基础的多视图几何算法,单独的和立体的相机标定,物体姿态检测,立体匹配算法和3-D重建元素。
  • fetures2D 显著特征检测子,描述子和描述子匹配器。
  • objdetect 对一些有着预定义类的物体进行检测,例如脸,眼睛,马克杯,人,车灯。
  • highgui 提供一些方便的接口,如视频捕获,图像和视频编解码和简单的UI功能。
  • gpu 提供不同模块的GPU加速算法。
  • 还有一些其他的模块,例如flann,google test wrappers,python bindings。
其他章节对每个模块进行了详细的描述。

二 API概念

1.cv namespace

Opencv所有的类和函数都放置在cv namespace中。因此,为了使用函数,在函数前加上cv::
#include "opencv2/core/core.hpp"
...
cv::Mat H = cv::findHomography(points1, points2, CV_RANSAC, 5);
...
或者
#include "opencv2/core/core.hpp"
using namespace cv;
...
Mat H = findHomography(points1, points2, CV_RANSAC, 5 );
...
一些名称可能会与STL标准模板库命名空间发生冲突,这是要显示表明使用的命名空间以消除歧义:
Mat a(100, 100, CV_32F);
randu(a, Scalar::all(1), Scalar::all(std::rand()));
cv::log(a, a);
a /= std::log(2.);

2.自动内存管理

Opencv自动处理所有的内存。
首先,对于std::vector,Mat和其他的数据结构体有析构函数,在需要时对内存进行解除分配。这意味着对于Mat,析构函数不总是进行重新分配。他们考虑到数据共享的问题。析构函数减少矩阵内存对应的引用指针计数器。当计数器为0,时,该部分内存就被回收。同样,当一个Mat结构被复制,并没有产生新的数据,只是将引用指针指向该内存,同时引用指针计数器加1。 如果想对数据进行完全复制,需要使用Mat::clone函数,例如:
// create a big 8Mb matrix
Mat A(1000, 1000, CV_64F);

// create another header for the same matrix;
// this is an instant operation, regardless of the matrix size.
Mat B = A;
// create another header for the 3-rd row of A; no data is copied either
Mat C = B.row(3);
// now create a separate copy of the matrix
Mat D = B.clone();
// copy the 5-th row of B to C, that is, copy the 5-th row of A
// to the 3-rd row of A.
B.row(5).copyTo(C);
// now let A and D share the data; after that the modified version
// of A is still referenced by B and C.
A = D;
// now make B an empty matrix (which references no memory buffers),
// but the modified version of A will still be referenced by C,
// despite that C is just a single row of the original A
B.release();

// finally, make a full copy of C. As a result, the big modified
// matrix will be deallocated, since it is not referenced by anyone
对于高级的没有自动内存管理的类,Opencv提供了一种模板类Ptr<>的方法。改模板类似于c++ RT1中 std::shared_ptr。

普通方法:
T* ptr = new T(...);

Opencv方法:
Ptr<T> ptr = new T(...);
这里,在T中封装了引用计数器,在Ptr中可以找到详细的介绍。

3.输出数据的自动分配

Opencv对内存自动地进行回收,大多数情况下,也根据输出函数参数自动地进行内存分配。所以一个函数有一个或多个输入阵列(cv:Mat)和一些输出阵列,那么输出阵列的参数取决于输入阵列。需要的话,函数使用参数来决定输出阵列的性质。
例:
#include "cv.h"
#include "highgui.h"

using namespace cv;

int main(int, char**)
{
    VideoCapture cap(0);
    if(!cap.isOpened()) return -1;

    Mat frame, edges;
    namedWindow("edges",1);
    for(;;)
    {
        cap >> frame;
        cvtColor(frame, edges, CV_BGR2GRAY);
        GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
        Canny(edges, edges, 0, 30, 3);
        imshow("edges", edges);
        if(waitKey(30) >= 0) break;
    }
    return 0;
}
frame被算子>>自动分配,因为视频捕捉模块能够获得视频帧的分辨率和位数。edges被cvColor函数自动分配,它和输入阵列具有相同的大小和位数。通道数为1,因为使用了颜色转换代码CV_BGR2GRAY,这意味着一个到灰度图的转换。注意到frame和edges只在第一次执行循环时进行分配,因为接下来他们都具有相同的分辨率。如果改变了视频的分辨率,将对阵列进行重新分配。
这一技术关键的部分是Mat::create方法。它使用需要的大小和类型。如果一个阵列已经有了特定的大小和类型,那么它就什么都不做。否则,它会释放原先的内存,如果(这包括减少引用计数器并且与0相比),然后重新分配一个符合要求的大小。大多数函数调对每一个输出阵列调用Mat::create方法,所以自动输出内存分配得到执行。
一些例外值得注意,例如cv::mixChannels,cv::RNG::Fill和一些其他的函数和方法,他们不能自动分配输出内存,所以必须提前定义。

4.Saturation Arithmetics

作为一个计算机视觉库,Opencv通常处理的是使用8位或者16位的图像,因此数据会有一个范围。当对像素进行计算时,可能出现上溢或者下溢的情况,如果只储存最低的8位或者16位会影响后续的分析。Saturation Arithmetics可以解决该问题。例如对于一个8位的值,你会在0~255中找到一个与该值最近的整数进行替代,如下式:

I(x,y)= \min ( \max (\textrm{round}(r), 0), 255)
相同的规则适用于8位和16位的signed和unsigned char类型的数据,该语法在该库的任意地方使用。在Opencv中,saturate_cast<>类似于标准c++中的cast操作,下面是上式的代码执行
I.at<uchar>(y, x) = saturate_cast<uchar>(r);
这里cv::uchar是8-bit的数据类型, 注意Saturation不适用于32-bit的数据类型!

5.定点像素类型;模板的限制使用

模板是c++的一个重要特征,它能够让强大高效并且安全的结构体和算法得到应用。但是模板的广泛使用使得编译时间增加并且代码量巨大。对于基础的算法这种方法很好但是对于计算机视觉库,一个简单的算法可能会达到成千上万行的代码量。同时为了方便与其他语言的链接,例如python,java,matlab,这些语言是没有模板的,因此现在的Opencv基于多态和运行时调度( polymorphism and runtime dispatching)。像素入口操作运行时调度非常慢,Ptr<>操作不能使用运行时调度,saturate_cast<>()使用运行时调度不方便。现在的应用建议小的模板类,方法和函数。模板类的使用在现在的版本中都受到限制。

对应的,Opencv对可处理的原始数据类型也有一定限制。阵列元素必须是以下类型之一:
  • 8-bit unsigned integer (uchar)
  • 8-bit signed integer (schar)
  • 16-bit unsigned integer (ushort)
  • 16-bit signed integer (short)
  • 32-bit signed integer (int)
  • 32-bit floating-point number (float)
  • 64-bit floating-point number (double)
  • 通道的最大数由常量 CV_CN_MAX 定义(现在被设置为512)
下面的枚举量分别代表对应的数据类型
enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };
多通道的类型可这样表示:
  • CV_8UC1 ... CV_64FC4 适用于通道数1to4
  • CV_8UC(n) ... CV_64FC(n) or CV_MAKETYPE(CV_8U, n) ... CV_MAKETYPE(CV_64F, n) 适用于通道数超过4或者在编译前通道数未知的情况
注意:
CV_32FC1==CV_32F , CV_32FC2==CV_32FC(2)==CV_MAKETYPE(CV_32F,2) ,and  CV_MAKETYPE(depth,n)==(depth&7)+((n-1)<<3)
这意味着类型由最低三位决定,通道数减一后左移3位。
例: 
Mat mtx(3, 3, CV_32F); // make a 3x3 floating-point matrix
Mat cmtx(10, 1, CV_64FC2); // make a 10x1 2-channel floating-point
                           // matrix (10-element complex vector)
Mat img(Size(1920, 1080), CV_8UC3); // make a 3-channel (color) image
                                    // of 1920 columns and 1080 rows.
Mat grayscale(image.size(), CV_MAKETYPE(image.depth(), 1)); // make a 1-channel image of
                                                            // the same size and same
                                                            // channel type as img
更加复杂的数据类型不能使用Opencv处理,并且,每一个Opencv函数只能对这些数据类型的一个子集进行处理。通常,随着复杂程度的增加,这个子集的范围也是越来越小的。具有限制的典型的例子如下:
  • 人脸识别算法只适用于8-bit的灰度图或者彩色图
  • 线性代数函数和大多数机器学习 函数只适用于浮点数
  • 基础函数适用于所有类型(如cv::add)
  • 颜色空间转换支持8-bit unsigned,16-bit unsigned和32-bit 浮点数
子集的定义是从实际工作中得到,也会在未来的工作需求中得到拓展。

6.输入阵列和输出阵列

许多Opencv函数处理稠密的二维或者多维数值阵列。通常这些函数使用cpp::class:Mat作为参数,但是有时使用std::vector或者Matx<>更加方便,为了避免过多的重复,一种近似类被引入。基类InputArray被用于传递只读阵列作为函数的输入,衍生类 OutputArray被用于指定一个输出阵列类型。通常不需要考虑中间类型,即不需要显式声明变量和类型,这些工作会自动完成。可以认为你可以使用Mat,std::vector,MAtx<>,Vec<>和Scalar代替InputArray/OutputArray。当一个函数有一个可选择的输入或者输出阵列,那么使用cv::noArray()。

7.错误处理

Opencv使用exceptions来显示关键错误。当输入数据形式正确并且在特定范围内,但是由于某些原因算法不能成功(比如算法不收敛),它返回了一个特殊的错误代码(典型的是一个布尔变量)。
exceptions可以使cv::Exception类或者它的衍生类。反过来cv::Exception是std::exception的衍生类。所以,它能在使用标准c++库的代码上使用。使用 CV_Error(errcode,description)宏,CV_Error_(errcode,printf-spec,(printf-args))变体,CV_Assert(condition)宏exception丢进错误区域。对于关键执行代码,存在一个只有Debug版本的配置 CV_DbgAssert(condition)。
因为自动内存管理,当突然的错误发生时,所有的中间缓存被自动释放。你只需要增加一个try块去捕获exceptions:
try
{
    ... // call OpenCV
}
catch( cv::Exception& e )
{
    const char* err_msg = e.what();
    std::cout << "exception caught: " << err_msg << std::endl;
}
8.多线程和可重入性
现在Opencv应用是完全可重入的。同样cv:Mat也是可以在不同线程中使用,因为引用计数操作为原子操作。





























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值