简介

OpenCV(开源计算机视觉库 http://opencv.org ) 是一个开源的BSD许可库,包含数百种计算机视觉算法。 该文档描述了所谓的OpenCV 2.x API,它本质上是一个C ++ API,与基于C语言的OpenCV 1.x API有所差异。此文档针对于OpenCV 2.X API翻译,OPenCV 1.X API.pdf有关于C语言接口解释,敬请关注。

OpenCV具有模块化结构,这意味着该包包含多个共享库或静态库。 可以使用以下模块:

  • Core functionality:基础数据模块,包含一些发杂数据结构和基本函数方法。
  • Image processing :图像处理模块,包括线性和非线性图像滤波,几何图像变换(调整大小,仿射和透视扭曲,基于通用表的重新映射),颜色空间转换,直方图等。
  • video : 视频分析模块,包括运动估计,背景减法和对象跟踪算法。
  • calib3d : 基本的多视图几何算法,单一和立体摄像机校准,对象姿态估计,立体视觉匹配算法和3D重建元素。
  • features2d : 特征检测器,描述符和描述符匹配器。
  • objdetect : 检测预定义类的对象和实例(例如,面部,眼睛,马克杯,人,汽车等)。
  • highgui :UI界面以及UI功能
  • Video I/O :简单的视频捕获和视频编解码器接口。
  • gpu : 支持不同OpenCV模块的GPU加速算法.
  • ... 一些其他帮助器模块,例如FLANN和Google测试包装器,Python绑定等。
    文档的后续章节讲述了每个模块的功能。 但首先,请确保熟悉库中彻底使用的常见API概念。

API 概述

cv Namespace

所有OpenCV类和函数都放在cv命名空间中。 因此,要从代码中访问此功能,请使用cv :: specifier或using namespace cv; 指示:

#include "opencv2/core.hpp"
...
cv::Mat H = cv::findHomography(points1, points2, CV_RANSAC, 5);
...

or :

#include "opencv2/core.hpp"
using namespace cv;
...
Mat H = findHomography(points1, points2, CV_RANSAC, 5 );
...

在遇到OpenCV外部名称可能与STL或其他库冲突。 在这种情况下,使用显式名称空间说明符来解决名称冲突:

Mat a(100, 100, CV_32F);
randu(a, Scalar::all(1), Scalar::all(std::rand()));
cv::log(a, a);
a /= std::log(2.);
Automatic Memory Management(内存自动管理)

OpenCV自动处理所有内存。

首先,函数和方法使用的std :: vector,Mat和其他数据结构都有析构函数,可以在需要时释放底层内存缓冲区。 这意味着析构函数并不总是释放缓冲区,就像Mat一样。 他们考虑了可能的数据共享。 析构函数递减与矩阵数据缓冲区关联的引用计数器。 当且仅当引用计数器达到零时,即当没有其他结构引用相同的缓冲区时,缓冲区被释放。 同样,复制Mat实例时,实际上并未复制任何实际数据。 相反,引用计数器递增以记住存在相同数据的另一个所有者。 还有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
C = C.clone();

你看到Mat和其他基本结构的使用很简单。 但是,如果不考虑自动内存管理而创建的高级类甚至用户数据类型呢? 对于他们来说,OpenCV提供的Ptr模板类与C ++ 11中的std :: shared_ptr类似。 所以,而不是使用普通指针:

T* ptr = new T(...);

你可以使用:

Ptr<T> ptr(new T(...));

or:

Ptr<T> ptr = makePtr<T>(...);

Ptr <T>封装指向T实例的指针和指针相关联的引用计数器。 有关详细信息,请参阅Ptr说明。

Automatic Allocation of the Output Data(输出数据的自动分配)

OpenCV自动释放内存,并在大多数时间自动为输出函数参数分配内存。 因此,如果函数具有一个或多个输入数组(cv :: Mat实例)和一些输出数组,则会自动分配或重新分配输出数组。 输出数组的大小和类型由输入数组的大小和类型决定。 如果需要,函数会采用额外的参数来帮助确定输出数组属性。
Example:

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
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, COLOR_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;
}

由于视频帧分辨率和比特深度对于视频捕获模块是已知的,所以阵列帧由">>"运算符自动分配。 数组边缘由cvtColor函数自动分配。 它具有与输入数组相同的大小和位深度。 通道数为1,因为颜色转换代码COLOR_BGR2GRAY被传递,这意味着颜色到灰度转换。 请注意,在第一次执行循环体时,帧和边仅分配一次,因为所有下一个视频帧具有相同的分辨率。 如果以某种方式更改视频分辨率,则会自动重新分配数组。
该技术的关键组件是Mat :: create方法。 它需要所需的数组大小和类型。 如果数组已具有指定的大小和类型,则该方法不执行任何操作。 否则,它释放先前分配的数据(如果有的话)(这部分涉及递减引用计数器并将其与零比较),然后分配所需大小的新缓冲区。 大多数函数为每个输出数组调用Mat :: create方法,因此实现了自动输出数据分配。
这个方案的一些值得注意的特别之处是cv :: mixChannels,cv :: RNG :: fill,以及一些其他函数和方法。 它们无法分配输出数组,因此您必须提前执行此操作。

Saturation Arithmetics(饱和度技术)

作为一个计算机视觉库,OpenCV经常处理图像像素,这些像素通常以紧凑的,每通道8-bit或16-bit编码形式,因此具有有限的值范围。 此外,对图像的某些操作,如色彩空间转换,亮度/对比度调整,锐化,复杂插值(bi-cubic,Lanczos)可以产生超出可用范围的值。 如果只存储结果的最低8(16)bit,则会导致视觉伪像,并可能影响进一步的图像分析。 为了解决这个问题,使用所谓的饱和算术。 例如,要将操作结果r存储到8位图像,您会在0..255范围内找到最接近的值:

                     I(x,y)=min(max(round(r),0),255)

类似的规则适用于8-bit带符号的16-bit有符号和无符号类型。 这种语义在库中的任何地方都使用。 在C ++代码中,它使用类似于标准C ++强制转换操作的saturate_cast <>函数完成。 见下文上面提供的公式的实施:

   I.at<uchar>(y, x) = saturate_cast<uchar>(r);

其中cv :: uchar是OpenCV 8-bit无符号整数类型。 在优化的SIMD代码中,使用诸如paddusb,packuswb等SSE2指令。 它们有助于实现与C ++代码完全相同的行为。
Note
当结果为32位整数时,不应用饱和度。

Fixed Pixel Types. Limited Use of Templates(固定像素,受限模板)

模板是C ++的一个很好的特性,它可以实现非常强大,高效且安全的数据结构和算法。但是,广泛使用模板可能会大大增加编译时间和代码大小。此外,当专门使用模板时,很难将界面和实现分开。这对于基本算法来说可能很好,但对于计算机视觉库来说并不好,其中单个算法可能跨越数千行代码。正因为如此,并且为了简化其他开发语言的绑定,如Python,Java,Matlab,它们根本没有模板或具有有限的模板功能,当前的OpenCV实现基于多态和基于模板的运行时调度。在那些运行时调度太慢(像素访问运算符),不可能(通用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)

  • a tuple of several elements where all elements have the same type (one of the above). An array whose elements are such tuples, are called multi-channel arrays, as opposite to the single-channel arrays, whose elements are scalar values. The maximum possible number of channels is defined by the CV_CN_MAX constant, which is currently set to 512.
    对于这些基本类型,应用以下枚举:

    enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };
    

可以使用以下选项指定Multi-channel (n-channel)类型:

  • CV_8UC1 ... CV_64FC4 constants (for a number of channels from 1 to 4)

  • CV_8UC(n) ... CV_64FC(n) or CV_MAKETYPE(CV_8U, n) ... CV_MAKETYPE(CV_64F, n) macros when the number of channels is more than 4 or unknown at the compilation time.
    Note
    CV_32FC1 == CV_32F, CV_32FC2 == CV_32FC(2) == CV_MAKETYPE(CV_32F, 2), andCV_MAKETYPE(depth, n) == ((depth&7) + ((n-1)<<3)``。 这意味着常量类型由深度形成,取最低3位,通道数减1,取下一个`log2(CV_CN_MAX)bit。
    Examples:

    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 sam
                                                       // channel type as img
    

使用OpenCV无法构造或处理具有更复杂元素的数组。 此外,每个函数或方法只能处理所有可能的数组类型的子集。 通常,算法越复杂,支持的格式子集越小。 请参阅下面这些限制的典型示例:

  • 人脸检测算法仅适用于8-bit灰度或彩色图像。
  • 线性代数函数和大多数机器学习算法仅适用于浮点数组。
  • 基础函数,如cv :: add,支持所有类型。
  • 色彩空间转换功能支持8-bit无符号,16bit无符号和32-bit浮点类型。
    每个功能的受支持类型的子集已根据实际需要进行定义,并可根据用户请求在将来进行扩展。
InputArray and OutputArray

许多OpenCV函数处理密集的二维或多维数组。 通常这样的函数将cppMat作为参数,但在某些情况下,使用std :: vector <>(如,对于点集)或Matx <>(对于3x3单应矩阵等)更方便。 为了避免API中的许多重复,引入了特殊的“代理”类。 基础“代理”类是InputArray。 它用于在函数输入上传递只读数组。 从InputArray类派生的OutputArray用于指定函数的输出数组。 通常你不应该关心那些中间类型(并且您不应该显示声明这些类型的变量) - 它们都将自动运行。 你可以假设你可以使用Mat,std :: vector <>,Matx <>,Vec <>或Scalar来代替InputArray / OutputArray。 当一个函数有一个可选的输入或输出数组,并且你没有或不想要一个时,传递cv :: noArray()。

Error Handling

OpenCV使用异常来表示严重错误。 当输入数据具有正确的格式并且属于指定的值范围,但算法由于某种原因不能成功时(例如,优化算法没有收敛),它返回一个特殊的错误代码(通常只是一个布尔变量)。
异常可以是cv :: Exception类或其派生类的实例。 反过来,cv :: Exception是std :: exception的衍生物。 因此,可以使用其他标准C ++库组件在代码中优雅地处理它。
异常通常使用CV_Error(错误代码,描述)宏或其类似printf的CV_Error_(错误代码,printf-spec,(printf-args))变体或使用检查条件和的CV_Assert(条件)宏来抛出异常。 不满意时抛出异常。 对于性能关键代码,CV_DbgAssert(条件)仅保留在Debug配置中。 由于自动内存管理,所有中间缓冲区在发生突然错误时会自动解除分配。 如果需要,您只需要添加一个try语句来捕获异常:

try
{
    ... // call OpenCV
 }
catch( cv::Exception& e )
{
    const char* err_msg = e.what();
    std::cout << "exception caught: " << err_msg << std::endl;
}
Multi-threading and Re-enterability

当前的OpenCV实现是完全可以重新输入的。 也就是说,可以从不同的线程调用相同的函数,类实例的相同常量方法或不同类实例的相同非常量方法。 此外,相同的cv :: Mat可以在不同的线程中使用,因为引用计数操作使用特定于体系结构的原子指令。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,522评论 25 707
  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明先生_x阅读 15,968评论 3 119
  • 今天还是丁酉年正月十六。这还是地二十三篇简书。 时隔十分钟,我为什么又回来了呢。很明显,我想起来了。 还是要说身边...
    尘___世_美阅读 136评论 0 0
  • 公司简介 广州普升商贸有限公司创立于2010年,位于广东省广州市,是一家主要经营紫砂壶的企业。主要产品有圆壶、方壶...
    岚儿0阅读 223评论 0 0