opencv介绍

环境说明

  • 语言:c++
  • opencv版本:4.5.5

opencv介绍

OpenCV(开源计算机视觉库:http://opencv.org)是一个开源库,包含数百种计算机视觉算法。该文档描述了所谓的OpenCV 2.x API,它本质上是一个C++API,而不是基于C的OpenCV 1.x API(自OpenCV 2.4发布以来,C API已被弃用,未使用“C”编译器进行测试)
OpenCV具有模块化结构,这意味着该包包含多个共享或静态库。以下模块可用:

  • 核心功能(core)-定义基本数据结构的紧凑模块,包括密集多维数组Mat和所有其他模块使用的基本功能。
  • 图像处理(imgproc)-一个图像处理模块,包括线性和非线性图像滤波、几何图像变换(调整大小、仿射和透视扭曲、基于通用表的重新映射)、颜色空间转换、直方图等。
  • 视频分析(Video)-一个视频分析模块,包括运动估计、背景减法和对象跟踪算法。
  • 相机校准和三维重建(calib3d)-基本的多视图几何算法、单摄像机和立体摄像机校准、物体姿态估计、立体对应算法和三维重建元素。
  • 2D特征框架(features2d)-显著特征检测器、描述符和描述符匹配器。
  • 对象检测(objdetect)-检测对象和预定义类的实例(例如,脸、眼睛、杯子、人、车等)。
  • 高级GUI(highgui)-一个易于使用的界面,可实现简单的UI功能。
  • 视频I/O(videoio)-一个易于使用的视频捕获和视频编解码器接口。
  • …一些其他帮助模块,如FLANN和Google测试包装器、Python绑定等。

本文档的其他章节描述了每个模块的功能。但首先,确保彻底熟悉库中使用的常见API概念。

API使用说明

所有OpenCV类和函数都放在cv命名空间中。因此,要从代码中访问此功能,请使用cv::说明符或使用命名空间cv指令:

#include "opencv2/core.hpp"
cv::Mat H = cv::findHomography(points1, points2, cv::RANSAC, 5); //直接使用cv::进行引入

//或者

#include "opencv2/core.hpp"
using namespace cv; //使用命名空间进行引入
Mat H = findHomography(points1, points2, RANSAC, 5 );

某些当前或将来的OpenCV外部名称可能与c++的STL或其他库冲突。在这种情况下,使用显式命名空间说明符来解决名称冲突:

Mat a(100, 100, CV_32F);
randu(a, Scalar::all(1), Scalar::all(std::rand()));
cv::log(a, a); //与std的log冲突,使用显示命名空间引入
a /= std::log(2.);

自动内存处理

OpenCV自动处理所有内存。首先,函数和方法使用的std::vector、cv::Mat和其他数据结构都有析构函数,可以在需要时释放底层内存缓冲区。这意味着析构函数并不总是像Mat那样释放缓冲区。它们考虑了可能的数据共享。析构函数递减与矩阵数据缓冲区相关的引用计数器。当且仅当引用计数器达到零时,即当没有其他结构引用同一缓冲区时,缓冲区才被释放。类似地,复制Mat实例时,不会真正复制实际数据。相反,引用计数器会递增,以记住相同数据的另一个所有者。还有Mat::clone方法可以创建矩阵数据的完整副本。请参见以下示例:

// 创建一个8Mb的矩阵(1000*1000*1*(64/8)=8000000b=0.76Mb)
Mat A(1000, 1000, CV_64F);
//为同一矩阵创建另一报头;这是一个即时操作,与矩阵大小无关。
Mat B = A;
//为A的第3行创建另一报头;也不会复制任何数据
Mat C = B.row(3);
//现在创建矩阵的单独副本
Mat D = B.clone();
//将B的第5行复制到C,即将A的第5列复制到A的第3行。
B.row(5).copyTo(C);
//现在让A和D共享数据;之后A的修改版本仍然由B和C引用。
A = D;
//现在让B成为一个空矩阵(它不引用内存缓冲区),但是修改后的A仍然会被C引用,尽管C只是原始A的一行
B.release();
//最后,制作C的完整副本。最终,大的修改矩阵将被取消分配,因为它没有被任何人引用
C = C.clone();

输出数据的自动分配

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

#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", WINDOW_AUTOSIZE);
    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;
}

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

固定的像素类型

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

可以使用以下选项指定多通道(n通道)类型:

  • CV_8UC1…CV_64FC4常量(适用于从1到4的通道数)
  • CV_8UC(n)…CV_64FC(n)或CV_MAKETYPE(CV_8U,n)……CV_MAKETYPE(CV_64F,n)宏。
Mat mtx(3, 3, CV_32F); // 创建一个3x3 的单精度浮点数矩阵
Mat cmtx(10, 1, CV_64FC2); // 创建一个10x1 2通道的单精度浮点数矩阵
Mat img(Size(1920, 1080), CV_8UC3); // 创建一个3通道的(彩色),大小为1920x1080的图像
Mat grayscale(image.size(), CV_MAKETYPE(image.depth(), 1)); // 创建一个1通道的和img具有相同大小相同通道数的图像

InputArray和OutputArray

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

多线程和可重用性

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AoDeLuo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值