OpenCV 介绍使用

 返回:OpenCV系列文章目录(持续更新中......)

上一篇:OpenCV4.9.0开源计算机视觉库使用简要说明

下一篇:

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) - 一个图像处理模块,包括线性和非线性图像过滤、几何图像变换(调整大小、仿射和透视变形、基于表格的通用重映射)、色彩空间转换、直方图等。
  • 视频分析(视频) - 一个视频分析模块,包括运动估计、背景减法和对象跟踪算法。
  • 相机校准和 3D 重建 (calib3d) - 基本的多视图几何算法、单视图和立体相机校准、物体姿态估计、立体对应算法和 3D 重建元素。
  • 2D 特征框架 (features2d) - 显著特征检测器、描述符和描述符匹配器。
  • 对象检测 (objdetect) - 检测对象和预定义类的实例(例如,人脸、眼睛、杯子、人、汽车等)。
  • 高级 GUI (highgui) - 简单 UI 功能的易于使用的界面。
  • 视频 I/O (videoio) - 一个易于使用的视频捕获和视频编解码器界面。
  • ...其他一些帮助程序模块,例如 FLANN 和 Google 测试包装器、Python 绑定等。

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

API 概念

cv 命名空间

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

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

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

自动内存管理

OpenCV 会自动处理所有内存。

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

​// 创建一个8Mb大图片矩阵
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 共享数据;之后是修改后的版本
//尽管C只是原始A的一行
A = D;
//现在使B成为一个空矩阵(它不引用内存缓冲区),
// 但A的修改版本仍将被C引用,
// 最后,制作C的完整副本。结果,大修改了
B.release();
//最后,制作C的完整副本。结果,大修改了
//矩阵将被解除分配,因为它不会被任何人引用
C = C.clone();

你可以看到,垫子和其他基本结构的使用很简单。但是,在不考虑自动内存管理的情况下创建的高级类甚至用户数据类型呢?对于他们来说,OpenCV 提供了类似于 C++11 中的 std::shared_ptr 的 cv::P tr 模板类。因此,不要使用普通指针:

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

您可以使用:

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

或:

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

Ptr<T>封装指向 T 实例的指针和与指针关联的引用计数器。有关详细信息,请参阅 cv::P tr 描述。

自动分配输出数据

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;
}

由于视频帧分辨率和位深度对视频捕获模块是已知的,因此阵列帧由操作员自动分配。阵列边缘由 cvtColor 函数自动分配。它与输入数组具有相同的大小和位深度。通道数为 1,因为传递了颜色转换代码 cv::COLOR_BGR2GRAY,这意味着颜色到灰度的转换。请注意,在循环体的第一次执行期间,帧和边缘只分配一次,因为所有下一个视频帧都具有相同的分辨率。如果以某种方式更改视频分辨率,则会自动重新分配阵列。>>

该技术的关键组件是 cv::Mat::create 方法。它采用所需的数组大小和类型。如果数组已具有指定的大小和类型,则该方法不执行任何操作。否则,它会释放以前分配的数据(如果有)(这部分涉及递减引用计数器并将其与零进行比较),然后分配所需大小的新缓冲区。大多数函数为每个输出数组调用 cv::Mat::create 方法,因此实现了自动输出数据分配。

此方案的一些值得注意的例外是 cv::mixChannels、cv::RNG::fill 以及其他一些函数和方法。他们无法分配输出数组,因此您必须提前执行此操作。

饱和算术

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

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

类似的规则也适用于 8 位有符号类型、16 位有符号类型和无符号类型。此cv::saturate_cast<>语义在库中随处可见。在 C++ 代码中,它是使用类似于标准 C++ 强制转换操作的函数完成的。请参阅下面提供的公式的实现

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

其中 cv::uchar 是 OpenCV 8 位无符号整数类型。在优化的SIMD代码中,使用了paddusb、packuswb等SSE2指令。它们有助于实现与 C++ 代码中完全相同的行为。

注意

当结果为 32 位整数时,不应用饱和度。

固定像素类型。模板的使用有限

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

  • CV_8UC1 ... CV_64FC4 常量(对于从1到4的多个通道)
  • 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 位)和通道数减去 1(取下一位)形成的 log2(CV_CN_MAX) bits.

例子:

​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(img.size(), CV_MAKETYPE(img.depth(), 1)); // make a 1-channel image of
// the same size and same
// channel type as img

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

  • 人脸检测算法仅适用于 8 位灰度或彩色图像。
  • 线性代数函数和大多数机器学习算法仅适用于浮点数组。
  • 基本函数,如cv::add,支持所有类型。
  • 色彩空间转换函数支持 8 位无符号、16 位无符号和 32 位浮点类型。

每个函数支持的类型子集都是根据实际需求定义的,将来可以根据用户请求进行扩展。

输入数组和输出数组

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

错误处理

OpenCV 使用异常来发出严重错误的信号。当输入数据格式正确且属于指定值范围,但算法由于某种原因无法成功(例如,优化算法未收敛)时,它会返回一个特殊的错误代码(通常只是一个布尔变量)。

异常可以是 cv::Exception 类或其派生的实例。反过来,cv::Exception 是 的派生词。因此,可以使用其他标准 C++ 库组件在代码中优雅地处理它。std::exception

通常使用宏CV_Error(errcode, description) 或其类似 printf 的 CV_Error_(errcode, (printf-spec, printf-args))变体引发异常,或者使用 CV_Assert(condition) 宏来检查条件并在不满足异常时引发异常。对于性能关键代码,有 CV_DbgAssert(condition) 仅保留在调试配置中。由于自动内存管理,所有中间缓冲区都会在突然发生错误时自动释放。如果需要,只需添加 try 语句即可捕获异常:

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

多线程和可再输入性

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

参考文献:

1、《Introduction》 --Generated on Wed Dec 27 2023 21:56:11 for OpenCV by   ​编辑

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/480510.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【单元测试】一文读懂java单元测试

目录 1. 什么是单元测试2. 为什么要单元测试3. 单元测试框架 - JUnit3.1 JUnit 简介3.2 JUnit 内容3.3 JUnit 使用3.3.1 Controller 层单元测试3.3.2 Service 层单元测试3.3.3 Dao 层单元测试3.3.4 异常测试3.3.5 测试套件测多个类3.3.6 idea 中查看单元测试覆盖率3.3.7 JUnit …

戳-考察C++基础的两道小题

昨天分享了一天本来是考察unique_ptr禁止拷贝行为的&#xff0c;但是粘贴的时候贴成正确代码了&#xff0c;于是&#xff0c;今天继续找两道小题来练练手。 今天这两道小题&#xff0c;你能回答上来不&#xff0c;题目1有至少6处错误&#xff0c;你能找到几个&#xff1f;题目2…

基于转录组计算的肿瘤纯度与病理肿瘤纯度一致性差异

实体瘤组织由肿瘤和非肿瘤细胞组成&#xff0c;如基质细胞和免疫细胞。这些非肿瘤细胞构成肿瘤微环境&#xff08;TME&#xff09;的重要组成部分&#xff0c;可降低肿瘤纯度&#xff0c;并在癌变、恶性肿瘤进展、治疗耐药性和预后评估中发挥重要作用。 肿瘤间质比的预后影响 …

人工智能 vs 机器学习

本文是观看视频AI vs Machine Learning后的笔记。 这篇文章谈AI&#xff08;人工智能&#xff09;和ML&#xff08;机器学习&#xff09;的关系。 首先作者给出了他对AI的定义。他认为&#xff1a;人工智能基本上超越或匹配人类的能力。 那会涉及哪些能力&#xff0c;例如&am…

5.域控服务器都要备份哪些资料?如何备份DNS服务器?如何备份DHCP服务器?如何备份组策略?如何备份服务器状态的备份?

&#xff08;2.1) NTD(域控数据库&#xff09;备份 &#xff08;2.2&#xff09;DNS备份 &#xff08;2.3&#xff09;DHCP备份 &#xff08;2.4&#xff09;组策略备份 &#xff08;2.5&#xff09;CA证书备份 &#xff08;2.6&#xff09;系统状态备份 &#xff08;2.1)…

序列的使用

目录 序列的创建 序列的使 Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 在许多数据库之中都会存在有一种数据类型 — 自动增长列&#xff0c;它能够创建流水号。如果想在 Oracle 中实现这样的自动增长列&#xff0c;可…

我的电脑win11系统安装了谷歌浏览器,桌面的快捷方式打不开

安装好浏览器以后双击打不开右键打开文件位置也弹窗报错提示 但是我发现开始栏里面可以打开 说明我的软件应该是没有问题的&#xff0c;研究了一下 我实际的安装目录在&#xff1a;C:\Program Files\Google\Chrome\Application 桌面的快捷方式右键查看属性显示的地址却不对&a…

ChatGPTGPT4科研应用、数据分析与机器学习、论文高效写作、AI绘图技术教程

原文链接&#xff1a;ChatGPTGPT4科研应用、数据分析与机器学习、论文高效写作、AI绘图技术教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247598506&idx2&sn14f96667bfbeba5f51366a1f019e3d64&chksmfa82004dcdf5895bba2784ba10f6715f6f5e4c59c9b1…

李国武:如何评估一家精益制造咨询公司的实施能力?

在制造业转型升级的大背景下&#xff0c;精益制造已成为企业提升竞争力、实现可持续发展的关键。然而&#xff0c;面对市场上众多的精益制造咨询公司&#xff0c;如何评估其实施能力成为了众多企业的难题。本文将从多个方面为大家揭示评估精益制造咨询公司实施能力的方法&#…

WEB组态可视化软件

体验地址&#xff1a;by组态[web组态插件] 1.什么是组态&#xff1f; 组态的概念来自于20世纪70年代中期出现的第一代集散控制系统&#xff08;Distributed Control System&#xff09;&#xff0c;可理解为“配置”、“设置”等&#xff0c;是指通过人机开发界面&#xff0c;…

Redis中的缓存击穿

缓存击穿 缓存击穿问题也叫热点key问题&#xff0c;就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了&#xff0c;无数的请求访问会在瞬间给数据库带来巨大压力。 &#x1f914;现象分析&#xff1a; 当线程1查询缓存时&#xff0c;未命中&#xff0c;于是从数据…

SAVEST实验室废液暂存柜

SAVEST实验室废液暂存柜是一款专门设计用于实验室废液中转暂存的设备。这款储存柜符合EN标准&#xff0c;具有耐火防爆性能&#xff0c;为实验室操作人员的安全和实验室废液的储存安全建立一道防线&#xff0c;可有效避免废液遗撒或保存不当造成的安全隐患。 实验室废液暂存柜…

【wubuntu】披着Win11皮肤主题的Ubuntu系统

wubuntu - 一款外观类似于 Windows 的 Linux 操作系统&#xff0c;没有任何硬件限制。以下是官方的描述 Wubuntu is an operating system based on Ubuntu LTS that has a similar appearance to Windows using the open-source themes. Wubuntu also comes with a set of adva…

苍穹外卖-day02

1. 新增员工 1.1 需求分析和设计 注意事项&#xff1a; 账号必须是唯一的手机号为合法的11位手机号码身份证号为合法的18位身份证号码密码默认为123456 本项目约定&#xff1a; 管理端发出的请求&#xff0c;统一使用**/admin**作为前缀。用户端发出的请求&#xff0c;统一使用…

贪心算法入门

简介 贪心算法&#xff08;Greedy Algorithm&#xff09;是一种在每一步选择中都采取在当前状态下最好或最优&#xff08;即最有利&#xff09;的选择&#xff0c;从而希望导致结果是全局最好或最优的算法。也就是首先选取局部最优&#xff0c;从局部最优推出全局最优。 举例…

axios前端参数的传递几种方法

直接拼接url const axios require(axios);// 假设有两个参数&#xff1a;id 和 category const id 123;// 使用模板字符串将参数拼接在 URL 上 axios.get(https://api.xxx.com/data?id${id}).then(response > {console.log(response.data);}).catch(error > {console.…

Altair Compose® 数学运算、编程、数据分析及可视化

Altair Compose 数学运算、编程、数据分析及可视化 分析数据、开发算法或创建模型 - Altair Compose 旨在将你的想法付诸实施。 Altair Compose 是一个用于数学计算、数据操作和可视化、编程和调试脚本的环境&#xff0c;对重复运算和流程自动化非常有用。Altair Compose 让用…

短视频矩阵系统----源头开发

短视频矩阵源码技术开发要求及实现流程&#xff1a; 短视频矩阵开发要求具备视频录制、编辑、剪辑、分享等基本功能&#xff0c;支持实时滤镜、特效、音乐等个性化编辑&#xff0c;能够实现高效的视频渲染和处理。开发流程主要包括需求分析、技术选型、设计架构、编码实现、测试…

2024-3-22-Qtday3作业

1> 思维导图 2> 要求&#xff1a; 使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否…

【GO全栈掌握入门】

GO语言全栈学习咯 ~ 1. GO 语言简介2.语言特性3.哪些公司使用GO语言&#xff1f;3. 安装GO开发环境4. 学习说明&#xff1a;5. GO结构篇5.1 工作空间5.2 导入包5.3 组织结构5.4 依赖管理 6. GO骨肉篇7.GO工具篇 1. GO 语言简介 起源于2007年&#xff0c;GO语言之年轻如你所见&…