【opencv】示例-stereo_match.cpp 立体匹配:通过对左右视图图像进行处理来生成视差图和点云数据...

6dab1feafff1872424f8ab336146169c.png

/**  stereo_match.cpp*  calibration**  创建者 Victor Eruhimov,日期为 2010年1月18日。*  版权所有 2010 Argus Corp.**/#include "opencv2/calib3d/calib3d.hpp" // 导入OpenCV相机标定和三维重建相关的头文件
#include "opencv2/imgproc.hpp" // 导入OpenCV图像处理相关的头文件
#include "opencv2/imgcodecs.hpp" // 导入OpenCV图像编解码相关的头文件
#include "opencv2/highgui.hpp" // 导入OpenCV高层GUI(图形界面)相关的头文件
#include "opencv2/core/utility.hpp" // 导入OpenCV核心工具(utility)模块的头文件#include <stdio.h> // 导入C标准输入输出头文件
#include <sstream> // 导入C++字符串流处理头文件using namespace cv; // 使用OpenCV的命名空间// 声明了print_help函数,用于显示帮助信息
static void print_help(char** argv)
{// 打印使用demo时的帮助信息printf("\nDemo stereo matching converting L and R images into disparity and point clouds\n");// 打印程序使用方式的说明printf("\nUsage: %s <left_image> <right_image> [--algorithm=bm|sgbm|hh|hh4|sgbm3way] [--blocksize=<block_size>]\n""[--max-disparity=<max_disparity>] [--scale=scale_factor>] [-i=<intrinsic_filename>] [-e=<extrinsic_filename>]\n""[--no-display] [--color] [-o=<disparity_image>] [-p=<point_cloud_file>]\n", argv[0]);
}// 声明了saveXYZ函数,用于将三维点云数据保存到文件
static void saveXYZ(const char* filename, const Mat& mat)
{// 设置三维点深度的最大值const double max_z = 1.0e4;// 以文本写入方式打开文件FILE* fp = fopen(filename, "wt");// 遍历图像的每个像素点for(int y = 0; y < mat.rows; y++){for(int x = 0; x < mat.cols; x++){// 读取每个像素点的三维坐标Vec3f point = mat.at<Vec3f>(y, x);// 如果该点的Z坐标无效,则忽略此点if(fabs(point[2] - max_z) < FLT_EPSILON || fabs(point[2]) > max_z) continue;// 将有效的三维坐标写入到文件中fprintf(fp, "%f %f %f\n", point[0], point[1], point[2]);}}// 关闭文件fclose(fp);
}int main(int argc, char** argv)
{// 定义了一系列的字符串变量用来存储命令行参数std::string img1_filename = "";std::string img2_filename = "";std::string intrinsic_filename = "";std::string extrinsic_filename = "";std::string disparity_filename = "";std::string point_cloud_filename = "";// 定义了枚举类型,列出了所有双目算法enum { STEREO_BM=0, STEREO_SGBM=1, STEREO_HH=2, STEREO_VAR=3, STEREO_3WAY=4, STEREO_HH4=5 };int alg = STEREO_SGBM; // 默认使用STEREO_SGBM算法int SADWindowSize, numberOfDisparities; // 定义了SAD窗口大小和视差的数量bool no_display; // 定义了是否显示结果的标志位bool color_display; // 定义了是否彩色显示视差图的标志位float scale; // 定义了缩放因子// 创建两种双目匹配算法实例对象:StereoBM和StereoSGBMPtr<StereoBM> bm = StereoBM::create(16,9);Ptr<StereoSGBM> sgbm = StereoSGBM::create(0,16,3);// 使用命令行解析器解析参数cv::CommandLineParser parser(argc, argv,"{@arg1||}{@arg2||}{help h||}{algorithm||}{max-disparity|0|}{blocksize|0|}{no-display||}{color||}{scale|1|}{i||}{e||}{o||}{p||}");// 如果用户请求帮助,则调用print_help函数并退出if(parser.has("help")){print_help(argv);return 0;}// 获取命令行中指定的左右图像文件名img1_filename = samples::findFile(parser.get<std::string>(0));img2_filename = samples::findFile(parser.get<std::string>(1));// 解析算法参数if (parser.has("algorithm")){std::string _alg = parser.get<std::string>("algorithm");alg = _alg == "bm" ? STEREO_BM :_alg == "sgbm" ? STEREO_SGBM :_alg == "hh" ? STEREO_HH :_alg == "var" ? STEREO_VAR :_alg == "hh4" ? STEREO_HH4 :_alg == "sgbm3way" ? STEREO_3WAY : -1;}// 解析其他所有需要的命令行参数numberOfDisparities = parser.get<int>("max-disparity");SADWindowSize = parser.get<int>("blocksize");scale = parser.get<float>("scale");no_display = parser.has("no-display");color_display = parser.has("color");if( parser.has("i") )intrinsic_filename = parser.get<std::string>("i");if( parser.has("e") )extrinsic_filename = parser.get<std::string>("e");if( parser.has("o") )disparity_filename = parser.get<std::string>("o");if( parser.has("p") )point_cloud_filename = parser.get<std::string>("p");// 检查解析后的参数是否正确if (!parser.check()){parser.printErrors();return 1;}// 检查算法参数是否指定正确if( alg < 0 ){printf("Command-line parameter error: Unknown stereo algorithm\n\n");print_help(argv);return -1;}// 检查视差数量设置是否正确if ( numberOfDisparities < 1 || numberOfDisparities % 16 != 0 ){printf("Command-line parameter error: The max disparity (--maxdisparity=<...>) must be a positive integer divisible by 16\n");print_help(argv);return -1;}// 检查缩放因子是否正确if (scale < 0){printf("Command-line parameter error: The scale factor (--scale=<...>) must be a positive floating-point number\n");return -1;}// 检查SAD窗口大小设置是否正确if (SADWindowSize < 1 || SADWindowSize % 2 != 1){printf("Command-line parameter error: The block size (--blocksize=<...>) must be a positive odd number\n");return -1;}// 检查是否指定了左右图像文件if( img1_filename.empty() || img2_filename.empty() ){printf("Command-line parameter error: both left and right images must be specified\n");return -1;}// 检查内参和外参是否同时指定if( (!intrinsic_filename.empty()) ^ (!extrinsic_filename.empty()) ){printf("Command-line parameter error: either both intrinsic and extrinsic parameters must be specified, or none of them (when the stereo pair is already rectified)\n");return -1;}// 检查生成点云时是否指定了内参和外参if( extrinsic_filename.empty() && !point_cloud_filename.empty() ){printf("Command-line parameter error: extrinsic and intrinsic parameters must be specified to compute the point cloud\n");return -1;}// 根据算法的不同,设置图像的加载模式int color_mode = alg == STEREO_BM ? 0 : -1;// 加载左右视图图像Mat img1 = imread(img1_filename, color_mode);Mat img2 = imread(img2_filename, color_mode);// 如果左视图图像加载失败,打印错误并退出if (img1.empty()){printf("Command-line parameter error: could not load the first input image file\n");return -1;}// 如果右视图图像加载失败,打印错误并退出if (img2.empty()){printf("Command-line parameter error: could not load the second input image file\n");return -1;}// 如果缩放系数不等于1,则对图像进行缩放if (scale != 1.f){// 定义两个临时矩阵用于存储缩放后的图像Mat temp1, temp2;// 根据scale的大小选择合适的插值方法int method = scale < 1 ? INTER_AREA : INTER_CUBIC;// 对左右图像进行缩放resize(img1, temp1, Size(), scale, scale, method);img1 = temp1;resize(img2, temp2, Size(), scale, scale, method);img2 = temp2;}// 获取缩放后的图像大小Size img_size = img1.size();// 定义两个ROI区域以及Q矩阵(用于三维重建)Rect roi1, roi2;Mat Q;// 如果内参文件名不为空,则读取内(camera)参和外(stereo)参数if( !intrinsic_filename.empty() ){// 读取内参文件FileStorage fs(intrinsic_filename, FileStorage::READ);if(!fs.isOpened()){printf("Failed to open file %s\n", intrinsic_filename.c_str());return -1;}// 读取内参矩阵和畸变系数Mat M1, D1, M2, D2;fs["M1"] >> M1;fs["D1"] >> D1;fs["M2"] >> M2;fs["D2"] >> D2;// 根据缩放因子调整内参矩阵M1 *= scale;M2 *= scale;// 读取外参文件fs.open(extrinsic_filename, FileStorage::READ);if(!fs.isOpened()){printf("Failed to open file %s\n", extrinsic_filename.c_str());return -1;}// 读取旋转矩阵和平移矩阵Mat R, T, R1, P1, R2, P2;fs["R"] >> R;fs["T"] >> T;// 对立体图像进行校正stereoRectify( M1, D1, M2, D2, img_size, R, T, R1, R2, P1, P2, Q, CALIB_ZERO_DISPARITY, -1, img_size, &roi1, &roi2 );// 初始化校正映射矩阵Mat map11, map12, map21, map22;initUndistortRectifyMap(M1, D1, R1, P1, img_size, CV_16SC2, map11, map12);initUndistortRectifyMap(M2, D2, R2, P2, img_size, CV_16SC2, map21, map22);// 应用映射矩阵进行畸变校正和立体校正Mat img1r, img2r;remap(img1, img1r, map11, map12, INTER_LINEAR);remap(img2, img2r, map21, map22, INTER_LINEAR);// 更新校正后的图像img1 = img1r;img2 = img2r;}// 计算或更新视差的数量numberOfDisparities = numberOfDisparities > 0 ? numberOfDisparities : ((img_size.width/8) + 15) & -16;// 配置块匹配(Block Matching)算法的参数// 设置块匹配算法的区域兴趣(ROI),由roi1和roi2的矩形区域定义。bm->setROI1(roi1);bm->setROI2(roi2);// 设置前置滤波器的上限值用于块匹配算法。bm->setPreFilterCap(31);// 设置SAD窗口的大小,比较块大小。如果SADWindowSize变量大于0,就使用该变量的值,否则使用默认值9。bm->setBlockSize(SADWindowSize > 0 ? SADWindowSize : 9);// 设置最小视差,默认为0。bm->setMinDisparity(0);// 设置视差的数量,这里使用numberOfDisparities变量的值。bm->setNumDisparities(numberOfDisparities);// 设置纹理阈值,用于过滤掉纹理不够的区域。bm->setTextureThreshold(10);// 设置唯一性比例,用于判断最佳视差的唯一性。bm->setUniquenessRatio(15);// 设置视差连通区域变化的窗口大小,这里为100。bm->setSpeckleWindowSize(100);// 设置视差连通区域的最大视差变化范围,这里为32。bm->setSpeckleRange(32);// 设置左右视差图的最大差异,超过这个差异的视差值会被剔除。bm->setDisp12MaxDiff(1);// 配置半全局块匹配(Semi-Global Block Matching)算法的参数// 为半全局块匹配算法设置前置滤波器的上限值。sgbm->setPreFilterCap(63);// 计算SGBM算法的SAD窗口大小,如果SADWindowSize变量大于0,使用该变量的值,否则使用默认值3。int sgbmWinSize = SADWindowSize > 0 ? SADWindowSize : 3;// 设置SGBM算法的块大小。sgbm->setBlockSize(sgbmWinSize);// 根据输入图像的通道数计算常数值。int cn = img1.channels();// 设置SGBM算法的P1和P2参数,这些参数控制视差变化的平滑程度。sgbm->setP1(8*cn*sgbmWinSize*sgbmWinSize);sgbm->setP2(32*cn*sgbmWinSize*sgbmWinSize);// 设置最小视差,默认为0。sgbm->setMinDisparity(0);// 设置视差数量,这里使用numberOfDisparities变量的值。sgbm->setNumDisparities(numberOfDisparities);// 设置唯一性比例,用于判断最佳视差的唯一性。sgbm->setUniquenessRatio(10);// 设置视差连通区域变化的窗口大小,这里为100。sgbm->setSpeckleWindowSize(100);// 设置视差连通区域的最大视差变化范围,这里为32。sgbm->setSpeckleRange(32);// 设置左右视差图的最大差异,超过这个差异的视差值会被剔除。sgbm->setDisp12MaxDiff(1);// 根据选择的算法设置SGBM模式。if(alg==STEREO_HH)sgbm->setMode(StereoSGBM::MODE_HH);else if(alg==STEREO_SGBM)sgbm->setMode(StereoSGBM::MODE_SGBM);else if(alg==STEREO_HH4)sgbm->setMode(StereoSGBM::MODE_HH4);else if(alg==STEREO_3WAY)sgbm->setMode(StereoSGBM::MODE_SGBM_3WAY);Mat disp, disp8; // 定义存储视差图和转换后的8位视差图的矩阵。// 获取当前的时间刻度,用于计算视差计算的耗时。int64 t = getTickCount();float disparity_multiplier = 1.0f; // 定义视差倍数的默认值。// 根据选定的算法执行视差计算,并根据返回的数据类型设置合适的倍数。if( alg == STEREO_BM ){bm->compute(img1, img2, disp); // 使用BM算法计算视差。if (disp.type() == CV_16S)disparity_multiplier = 16.0f; // 如果视差图是16位有符号整型,则将倍数设为16。}else if( alg == STEREO_SGBM || alg == STEREO_HH || alg == STEREO_HH4 || alg == STEREO_3WAY ){sgbm->compute(img1, img2, disp); // 使用SGBM算法族计算视差。if (disp.type() == CV_16S)disparity_multiplier = 16.0f; // 如果视差图是16位有符号整型,则将倍数设为16。}t = getTickCount() - t; // 计算视差计算耗时。printf("Time elapsed: %fms\n", t*1000/getTickFrequency()); // 打印耗时信息。// 将计算出的视差图转换为8位图像以供显示或存储。if( alg != STEREO_VAR )disp.convertTo(disp8, CV_8U, 255/(numberOfDisparities*16.));elsedisp.convertTo(disp8, CV_8U);Mat disp8_3c; // 定义用于显示彩色视差图的矩阵。// 如果选项设置为显示彩色图,则对8位图像应用色彩映射。if (color_display)cv::applyColorMap(disp8, disp8_3c, COLORMAP_TURBO);// 如果指定了视差图文件名,则将视差图存储到文件中。if(!disparity_filename.empty())imwrite(disparity_filename, color_display ? disp8_3c : disp8);// 如果指定了点云文件名,则保存点云数据到文件中。if(!point_cloud_filename.empty()){printf("storing the point cloud..."); // 打印存储点云数据的信息。fflush(stdout);Mat xyz; // 定义用于存储3D坐标的矩阵。Mat floatDisp; // 定义用于存储转换后的视差图的矩阵。// 将视差图转换为浮点型,并应用视差倍数。disp.convertTo(floatDisp, CV_32F, 1.0f / disparity_multiplier);// 使用Q矩阵将视差图重投影到3D坐标。reprojectImageTo3D(floatDisp, xyz, Q, true);// 使用saveXYZ函数将3D坐标保存到指定的点云文件中。saveXYZ(point_cloud_filename.c_str(), xyz);printf("\n"); // 用于换行。}// 如果未设置不显示结果,则创建显示左、右图像和视差图的窗口。if( !no_display ){std::ostringstream oss; // 使用字符串流构建显示的标题。oss << "disparity  " << (alg==STEREO_BM ? "bm" :alg==STEREO_SGBM ? "sgbm" :alg==STEREO_HH ? "hh" :alg==STEREO_VAR ? "var" :alg==STEREO_HH4 ? "hh4" :alg==STEREO_3WAY ? "sgbm3way" : "");oss << "  blocksize:" << (alg==STEREO_BM ? SADWindowSize : sgbmWinSize);oss << "  max-disparity:" << numberOfDisparities;std::string disp_name = oss.str(); // 从流中获取构建好的标题字符串。// 创建并显示图像窗口。namedWindow("left", cv::WINDOW_NORMAL);imshow("left", img1);namedWindow("right", cv::WINDOW_NORMAL);imshow("right", img2);namedWindow(disp_name, cv::WINDOW_AUTOSIZE);imshow(disp_name, color_display ? disp8_3c : disp8);printf("press ESC key or CTRL+C to close..."); // 提示用户如何关闭窗口。fflush(stdout);printf("\n"); // 用于换行。while(1) // 循环等待用户按键操作。{if(waitKey() == 27) // 如果用户按下ESC键,则退出循环。break;}}return 0; // 正常结束程序。
}
enum { STEREO_BM=0, STEREO_SGBM=1, STEREO_HH=2, STEREO_VAR=3, STEREO_3WAY=4, STEREO_HH4=5 };

eee9983d057c4435d686bdd70a1ed1a0.png

什么是视差图

047eaa55d1d5a937e9f132be4e8b94b2.png

在计算视差图时,遮挡或缺乏纹理的区域会有什么表现?

80a6ba14b4ec5b53a1a8544950ab7e0c.png

SGBM算法是如何处理遮挡和纹理缺失问题的?

dfda5f1553c44ce2ba3e5b2579ce68a8.png

stereoRectify( M1, D1, M2, D2, img_size, R, T, R1, R2, P1, P2, Q, CALIB_ZERO_DISPARITY, -1, img_size, &roi1, &roi2 );

ad562c68f29003be64cc0a514ba3d61a.png

这个函数的主要目的是通过计算两个矫正映射,让来自两个摄像头的图像在水平方向上对准,简化立体匹配的复杂性,提高计算效率和质量。正确定位了坐标对齐后,图像中对应的点就可以直接在同一行上进行匹配,使得视差计算更加准确和便捷。

reprojectImageTo3D(floatDisp, xyz, Q, true);

4ea77b4642d82c12b3a8a8e8a681ec64.png

909e0a4a1f6e42d87acfbc5ae52636ca.png

这个函数中的投影变换矩阵Q是如何计算得到的?

d2f0f6c5139b1cc22e7d7909a667fc72.png

The End

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最优算法100例之47-从尾到头打印单链表

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 从尾到头打印单链表 题解报告 方法1:头插法逆置单链表然后依次打印;注意此处是不带头结点的单链表,带头节点的操作稍微有…

为什么光伏探勘测绘需要无人机?

随着全球对可再生能源需求的不断增长&#xff0c;光伏产业也迎来了快速发展的机遇。光伏电站作为太阳能发电的主要形式之一&#xff0c;其建设前期的探勘测绘工作至关重要。在这一过程中&#xff0c;无人机技术的应用正逐渐展现出其独特的优势。那么&#xff0c;为什么光伏探勘…

【opencv】示例-travelsalesman.cpp 使用模拟退火算法求解旅行商问题

// 载入 OpenCV 的核心头文件 #include <opencv2/core.hpp> // 载入 OpenCV 的图像处理头文件 #include <opencv2/imgproc.hpp> // 载入 OpenCV 的高层GUI(图形用户界面)头文件 #include <opencv2/highgui.hpp> // 载入 OpenCV 的机器学习模块头文件 #includ…

【C语言__结构体__复习篇3】

目录 前言 一、结构体基础知识 1.1 结构体的语法形式 1.2 创建结构体变量 1.3 结构体变量的初始化 1.4 点(.)操作符和箭头(->)操作符 二、匿名结构体 三、结构体自引用 四、结构体内存对齐 4.1 内存对齐的规则 4.2 出现结构体内存对齐的原因 4.3 修改默认对齐数 五、结…

【网站项目】面向企事业单位的项目申报小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

数据结构之排序

一、排序的概念及其应用 1、排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记…

宝塔面板Docker+Uwsgi+Nginx+SSL部署Django项目

这次为大家带来的是从零开始搭建一个django项目并将它部署到linux服务器上。大家可以按照我的步骤一步步操作&#xff0c;最终可以完成部署。 步骤1&#xff1a;在某个文件夹中创建一个django项目 安装django pip install django创建一个django项目将其命名为djangoProject …

计算机网络 实验指导 实验17

实验17 配置无线网络实验 1.实验拓扑图 Table PC0 和 Table PC1 最开始可能还会连Access Point0&#xff0c;无影响后面会改 名称接口IP地址网关地址Router0fa0/0210.10.10.1fa0/1220.10.10.2Tablet PC0210.10.10.11Tablet PC1210.10.10.12Wireless互联网220.10.10.2LAN192.16…

05.MySQL索引事务

1. 索引 1.1 概念 索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。 可以对表中的一列或多列创建索引&#xff0c;并指定索引的类型&#xff0c;各类索引有各自的数据结构实现 1.2 作用 数据库中的表、数据、索引之间的关系&#xff0c;类似于书架上的…

分布式ID的方案和架构

超过并发&#xff0c;超高性能分布式ID生成系统的要求 在复杂的超高并发、分布式系统中&#xff0c;往往需要对大量的数据和消息进行唯一标识如在高并发、分布式的金融、支付、餐饮、酒店、电影等产品的系统中&#xff0c;数据日渐增长&#xff0c;对数据分库分表后需要有一个唯…

LeetCode-31-下一个排列问题

题目说明 实现获取下一个排列的函数&#xff0c;算法需要将给定数字序列重新排列成字典序中下一个更大的排列。 如果不存在下一个更大的排列&#xff0c;则将数字重新排列成最小的排列&#xff08;即升序排列&#xff09;。 必须原地修改&#xff0c;只允许使用额外常数空间。…

数据结构与算法——20.B-树

这篇文章我们来讲解一下数据结构中非常重要的B-树。 目录 1.B树的相关介绍 1.1、B树的介绍 1.2、B树的特点 2.B树的节点类 3.小结 1.B树的相关介绍 1.1、B树的介绍 在介绍B树之前&#xff0c;我们回顾一下我们学的树。 首先是二叉树&#xff0c;这个不用多说&#xff…

网络篇09 | 运输层 udp

网络篇09 | 运输层 udp 01 简介UDP 是面向报文的 02 报文协议 01 简介 UDP 只在 IP 的数据报服务之上增加了一些功能&#xff1a;复用和分用、差错检测 UDP 的主要特点&#xff1a;无连接。发送数据之前不需要建立连接。 使用尽最大努力交付。即不保证可靠交付。 面向报文。…

eclipse 取消生成注释 TODO Auto-generated method stub

eclipse 取消生成注释 // TODO Auto-generated method stub 基本步骤 windows -> preferencesJava -> Code Style -> Code TemplatesCode -> Method body -> 编辑删除 // ${todo} Auto-generated method stub参考材料 Eclipse 中取消生成 TODO Auto-generated…

(四)C++自制植物大战僵尸游戏启动流程

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/ErelL 一、启动方式 鼠标左键单机VS2022上方工具栏中绿色三角按钮&#xff08;本地Windows调试器&#xff09;进行项目启动。第一次启动项目需要编译项目中所有代码文件&#xff0c;编译生成需要一定的时间。不同性能的电…

Qt快速入门(Opencv小案例之人脸识别)

Qt快速入门&#xff08;Opencv小案例之人脸识别&#xff09; 编译出错记录 背景 因为主要使用qt&#xff0c;并且官网下载的win版本的编译好的opencv默认是vc的&#xff0c;所以我们需要自己下载opencv的源码使用mingw自行编译&#xff0c;我直接使用的vscode。 报错 报错…

Rust取代C++? 保守了!关于未来的讨论

当各种平台在大肆讨论rust即将取代C/C的时候&#xff0c;已经有不少人意识到这种讨论是聒噪而无聊的。笔者和老师们通过周末茶会的讨论&#xff0c;认为现今世界常见的大多数编程语言都会在50-80年内被AI取代&#xff0c;同时供人类审计而诞生的“审计语言”会兴起。届时计算机…

Niobe开发板OpenHarmony内核编程开发——事件标志

本示例将演示如何在Niobe Wifi IoT开发板上使用cmsis 2.0 接口使用事件标志同步线程 EventFlags API分析 osEventFlagsNew() /// Create and Initialize an Event Flags object./// \param[in] attr event flags attributes; NULL: default values./// \return e…

【C++】详解类的--封装思想(让你丝滑的从C语言过度到C++!!)

目录 一、前言 二、【面向过程】 与 【面向对象】 三、结构体 与 类 &#x1f34e;C中结构体的变化 &#x1f349;C中结构体的具体使用 &#x1f350;结构体 --> 类 ✨类-----语法格式&#xff1a; ✨类的两种定义方式&#xff1a; 四、类的访问限定符及封装【⭐】 …

【opencv】示例-stiching_detailed.cpp 使用OpenCV进行图像拼接的整体流程

#include <iostream> // 引入输入输出流库 #include <fstream> // 引入文件流库&#xff0c;用于文件输入输出 #include <string> // 引入字符串库 #include "opencv2/opencv_modules.hpp" // 引入OpenCV模块 #include <opencv2/core/utility.h…