当前位置: 首页 > news >正文

Opencv计算机视觉编程攻略-第十节 估算图像之间的投影关系

目录

1. 计算图像对的基础矩阵

2. 用RANSAC 算法匹配图像

3. 计算两幅图像之间的单应矩阵

4. 检测图像中的平面目标


        图像通常是由数码相机拍摄的,它通过透镜投射光线成像,是三维场景在二维平面上的投影,这表明场景和它的图像之间以及同一场景的不同图像之间都有着重要的关联。投影几何学是用数学术语描述和区分成像过程的工具。下文将介绍几种多视图图像中基本的投影关系,并解释如何在计算机视觉编程中将其投入应用。

        光线从被摄景象发出并穿过前置孔径,被相机捕获,捕获到的光线触发相机后面的成像平面(或图像传感器)

      进一步构建,世界坐标系-图像坐标系转换矩阵:

1. 计算图像对的基础矩阵

        上述投影方程解释了真实的场景是如何投影到单目相机的成像平面上的。在同一场景的两幅图像之间的投影关系:可以移动相机,从两个视角拍摄两幅照片;也可以使用两个相机,分别对同一个场景拍摄照片,如果这两个相机被刚性基线分割,我们就称之为立体视觉。

       沿着三维点X 和相机中心点之间的连线,可在图像上找到对应的点x,反过来,在三维空间中,与成像平面上的位置x 对应的场景点可以位于线条上的任何位置。这说明如果要根据图像中的一个点找到另一幅图像中对应的点,就需要在第二个成像平面上沿着这条线的投影搜索。这条虚线称为点x 的对极线。它规定了两个对应点必须满足的基本条件,即对于一个点,在另一视图中与它匹配的点必须位于它的对极线上,并且对极线的准确方向取决于两个相机的相对位置。

       即所有的对极线都通过同一个点。这个点对应着一个相机中心点在另一个相机上的投影(上图中的e 和e')。这个特殊的点称为极点,矩阵F(称为基础矩阵)的作用就是把一个视图上的二维图像点映射到另一个视图上的对极线上。如果两幅图像之间有一定数量的已知匹配点,就可以利用方程组来计算图像对的基础矩阵,即假设点(x, y)的对应点为(x', y'),这两个视图间的基础矩阵为F,由于(x', y') 位于(x, y)和F 相乘得到的对极线上(用齐次坐标表示)。

       这样的匹配项至少要有7 对,用OpenCV 函数cv::findFundamentalMat 计算基础矩阵时,将使用上一节获得的匹配点匹配项。

//1. 这些匹配项存储在cv::DMatch 类型的容器中,其中每个元素代表一个cv::keypoint 实例的索引。为了在cv::findFundamentalMat 中使用,需要先把这些关键点转换成cv::Point2f类型。为此可用下面的OpenCV 函数:
// 把关键点转换成Point2f
std::vector<cv::Point2f> selPoints1, selPoints2;
std::vector<int> pointIndexes1, pointIndexes2;
cv::KeyPoint::convert(keypoints1,selPoints1,pointIndexes1);
cv::KeyPoint::convert(keypoints2,selPoints2,pointIndexes2);//2. 结果是selPoints1 和selPoints2 这两个容器,容器的元素为两幅图像中相关像素的坐标。容器pointIndexes1 和pointIndexes2 包含这些被转换的关键点的索引。于是调用cv::findFundamentalMat 函数的方法为:
// 用7 对匹配项计算基础矩阵
cv::Mat fundamental= cv::findFundamentalMat(selPoints1, // 第一幅图像中的7 个点selPoints2, // 第二幅图像中的7 个点cv::FM_7POINT); // 7 个点的方法//3. 要想直观地验证这个基础矩阵的效果,可以选取一些点,画出它们的对极线。OpenCV 中有一个函数可计算指定点集的对极线。计算出对极线后,可用函数cv::line 画出它们。
// 在右侧图像上画出对极线的左侧点
std::vector<cv::Vec3f> lines1;
cv::computeCorrespondEpilines(selPoints1, // 图像点1, // 在第一幅图像中(也可以是在第二幅图像中)fundamental, // 基础矩阵lines1); // 对极线的向量// 遍历全部对极线
for (vector<cv::Vec3f>::const_iterator it= lines1.begin();it!=lines1.end(); ++it) {// 画出第一列和最后一列之间的线条cv::line(image2, cv::Point(0,-(*it)[2]/(*it)[1]),cv::Point(image2.cols,-((*it)[2]+ (*it)[0]*image2.cols)/(*it)[1]),cv::Scalar(255,255,255));
}

2. 用RANSAC 算法匹配图像

        如何进一步使用上一节介绍的极线约束,使图像特征的匹配更加可靠:在匹配两幅图像的特征点时,只接受位于对极线上的匹配项。若要判断是否满足这个条件,必须先知道基础矩阵,但计算基础矩阵又需要优质的匹配项。这看起来像是“先有鸡还是先有蛋”的问题,下图为原始匹配结果。

        我们的目的是计算两个视图间的基础矩阵和优质匹配项。因此,所有已发现的特征点的匹配度都要用上一节的极线约束验证

       通过单应矩阵可以将假设仅通过旋转变换得到得两张图片进行极线对齐,从而服务于下一步得视差估计。场景点中值为0 的坐标会消除掉投影矩阵的第三列,从而又变成一个3×3 的矩阵。这种特殊矩阵称为单应矩阵(homography),表示在特殊情况下(这里指纯旋转或平面目标),世界坐标系的点和它的影像之间是线性关系。此外,由于该矩阵是可逆的,所以只要两个视图只是经过了旋转,或者拍摄的是平面物体,那么就可以将一个视图中的像素点与另一个视图中对应的像素点直接关联起来。单应矩阵的格式为:

          其中H 是一个3×3 矩阵。这个关系式包含了一个尺度因子,用s 表示。计算得到这个矩阵后,一个视图中的所有点都可以根据这个关系式转换到另一个视图。

// 用RANSAC 算法匹配特征点
// 返回基础矩阵和输出的匹配项
cv::Mat match(cv::Mat& image1,cv::Mat& image2, // 输入图像std::vector<cv::DMatch>& matches, // 输出匹配项std::vector<cv::KeyPoint>& keypoints1, // 输出关键点std::vector<cv::KeyPoint>& keypoints2) {// 1.检测特征点detector->detect(image1,keypoints1);detector->detect(image2,keypoints2);// 2.提取特征描述子cv::Mat descriptors1, descriptors2;descriptor->compute(image1,keypoints1,descriptors1);descriptor->compute(image2,keypoints2,descriptors2);// 3.匹配两幅图像描述子// (用于部分检测方法)// 构造匹配类的实例(带交叉检查)cv::BFMatcher matcher(normType, // 差距衡量true); // 交叉检查标志// 匹配描述子std::vector<cv::DMatch> outputMatches;matcher.match(descriptors1,descriptors2,outputMatches);// 4.用RANSAC 算法验证匹配项cv::Mat fundamental= ransacTest(outputMatches,keypoints1, keypoints2,matches);// 返回基础矩阵return fundamental;
}

        RANSAC 算法旨在根据一个可能包含大量局外项的数据集,估算一个特定的数学实体。其原理是从数据集中随机选取一些数据点,并仅用这些数据点进行估算。选取的数据点数量,应该是估算数学实体所需的最小数量,对于基础矩阵,最小数量是8 个匹配对(实际上只需要7 个,但是8 个点的线性算法速度较快)。用这8 个随机匹配对估算基础矩阵后,对剩下的全部匹配项进行测试,验证其是否满足根据这个矩阵得到的极线约束。标识出所有满足极线约束的匹配项(即特征点与对极线距离很近的匹配项),这些匹配项就组成了基础矩阵的支撑集。RANSAC 算法背后的核心思想是:支撑集越大,所计算矩阵正确的可能性就越大。反之,如果一个(或多个)随机选取的匹配项是错误的,那么计算得到的基础矩阵也是错误的,并且它的支撑集肯定会很小。反复执行这个过程,最后留下支撑集最大的矩阵作为最佳结果:

      通过极线约束后可以将特征点进行限制,找到高质量得匹配点,从而计算H矩阵,并基于H矩阵实现图像拼接,opencv里有内置得拼接函数

// 读取输入的图像
std::vector<cv::Mat> images;
images.push_back(cv::imread("parliament1.jpg"));
images.push_back(cv::imread("parliament2.jpg"));
cv::Mat panorama; // 输出的全景图
// 创建拼接器
cv::Stitcher stitcher = cv::Stitcher::createDefault();
// 拼接图像
cv::Stitcher::Status status = stitcher.stitch(images, panorama);

3. 检测图像中的平面目标

       假定我们需要检测图像中的平面物体。这个物体可能是一张海报、一幅画等等。采取的方法是检测这个平面物体的特征点,然后试着在图像中匹配这些特征点。然后和前面一样,用鲁棒匹配方案来验证这些匹配项,但这次要基于单应矩阵

       将目标图像依次进行压缩像素采样,得到一系列类似金字塔的图像,从这些图像中就可以检测到特征点。

// 1. 初始化匹配器 使用两个快速得多尺度检测器
TargetMatcher tmatcher(cv::FastFeatureDetector::create(10),cv::BRISK::create());
tmatcher.setNormType(cv::NORM_HAMMING);

        因为不知道图像中目标物体的大小,所以我们把目标图像转换成一系列不同的尺寸,构建成一个金字塔。除了这种方法,也可以采用尺度不变特征。在金字塔中,目标图像的尺寸按特定比例(属性scaleFactor,默认为0.9)逐层缩小。

      detectTarget 接下来要执行三个步骤。

  1. 第一步,在输入图像中检测兴趣点。
  2. 第二步,将该图像与目标金字塔中的每幅图像进行鲁棒匹配,并把优质匹配项最多的那一层保留下来;如果这一层的匹配项足够多,就可认为已经找到目标。
  3. 第三步,使用得到的单应矩阵和cv::getPerspectiveTransform 函数,把目标中的四个角点重新投影到输入图像中。
// 检测预先定义的平面目标
// 返回单应矩阵和检测到的目标的4 个角点
cv::Mat detectTarget(
const cv::Mat& image, // 目标角点(顺时针方向)的坐标
std::vector<cv::Point2f>& detectedCorners) {
// 1.检测图像的关键点
std::vector<cv::KeyPoint> keypoints;
detector->detect(image, keypoints);
// 计算描述子
cv::Mat descriptors;
descriptor->compute(image, keypoints, descriptors);
std::vector<cv::DMatch> matches;
cv::Mat bestHomography;
cv::Size bestSize;
int maxInliers = 0;
cv::Mat homography;
// 构建匹配器
cv::BFMatcher matcher(normType);
// 2.对金字塔的每层,鲁棒匹配单应矩阵
for (int i = 0; i < numberOfLevels; i++) {
// 在目标和图像之间发现RANSAC 单应矩阵
matches.clear();
// 匹配描述子
matcher.match(pyrDescriptors[i], descriptors, matches);
// 用RANSAC 验证匹配项
std::vector<cv::DMatch> inliers;
homography = ransacTest(matches, pyrKeypoints[i],
keypoints, inliers);
if (inliers.size() > maxInliers) { // 有更好的H
maxInliers = inliers.size();
bestHomography = homography;
bestSize = pyramid[i].size();
}
}
// 3.用最佳单应矩阵找出角点坐标
if (maxInliers > 8) { // 估算值有效
// 最佳尺寸的目标角点
std::vector<cv::Point2f> corners;
corners.push_back(cv::Point2f(0, 0));
corners.push_back(cv::Point2f(bestSize.width - 1, 0));
corners.push_back(cv::Point2f(bestSize.width - 1,
bestSize.height - 1));
corners.push_back(cv::Point2f(0, bestSize.height - 1));
// 重新投影目标角点
cv::perspectiveTransform(corners, detectedCorners, bestHomography);
}
return bestHomography;
}

     本节内容还需多多学习,如果感兴趣,请下载上传代码自行研究。代码资源

相关文章:

Opencv计算机视觉编程攻略-第十节 估算图像之间的投影关系

目录 1. 计算图像对的基础矩阵 2. 用RANSAC 算法匹配图像 3. 计算两幅图像之间的单应矩阵 4. 检测图像中的平面目标 图像通常是由数码相机拍摄的&#xff0c;它通过透镜投射光线成像&#xff0c;是三维场景在二维平面上的投影&#xff0c;这表明场景和它的图像之间以及同一…...

RocketMQ 01

今天是2025/04/06 21:31 day 18 总路线请移步主页Java大纲相关文章 今天进行RocketMQ 1,2 个模块的归纳 首先是RocketMQ 的相关内容概括的思维导图 1. 核心组件 1.1 NameServer 核心功能 服务发现&#xff1a;作为轻量级注册中心&#xff0c;管理所有 Broker 的地址和路由信…...

牛客周赛———字符串

题目如下 思路&#xff08;贪心&#xff09; >和<的位置是固定不变的&#xff0c;所以先处理这两个符号&#xff0c;然后再遍历一遍检查‘Z’&#xff0c;如果不符合条件将Z的位置改变正负性使其满足条件&#xff0c;然后遍历的时候记数答案就行了&#xff0c;注意s的首…...

在Hive中,将数据从一个表查询并插入到另一个表

1. 确认目标表结构 确保目标表已存在且结构与查询结果匹配。若不存在&#xff0c;需先创建&#xff1a; CREATE TABLE target_table ( id INT, name STRING ) PARTITIONED BY (dt STRING) STORED AS ORC; 2. 选择插入方式 覆盖插入&#xff08;替换现有数据&#xff0…...

优雅实现级联选择器:CascadeSelect 类设计与实现

在现代Web开发中&#xff0c;级联选择器是一种常见的UI组件&#xff0c;它能够有效地组织和展示层级数据。本文将深入解析一个功能完善的级联选择器实现——CascadeSelect类&#xff0c;展示如何用面向对象的方式构建可复用的UI组件。 组件概述 CascadeSelect是一个二级下拉框…...

26考研 | 王道 | 数据结构 | 第五章 树

第五章 树 5.1. 树的概念 5.1.1. 树的基本定义 树:n(n>0)个节点的有限集合&#xff0c;是一种逻辑结构&#xff0c;当n0时为空树&#xff0c;且非空树满足: 有且仅有一个特定的称为根的节点当n>1时&#xff0c;其余结点可分为m (m >0) 个互不相交的有限集合&#x…...

Spring 怎么解决循环依赖问题?

Spring 循环依赖&#xff08;circular dependency&#xff09; 指的是多个 Bean 之间的相互依赖&#xff0c;比如&#xff1a; A 依赖 B&#xff0c;B 又依赖 A&#xff1b;或者 A → B → C → A 这种嵌套循环依赖。 这是一个常见又棘手的问题&#xff0c;但 Spring 是可以解…...

微软推出首款量子计算芯片Majorana 1

全球首款拓扑架构量子芯片问世&#xff0c;2025年2月20日&#xff0c;经过近20年研究&#xff0c;微软推出了首款量子计算芯片Majorana 1&#xff0c;其宣传视频如本文末尾所示。 微软表示&#xff0c;开发Majorana 1需要创造一种全新的物质状态&#xff0c;即所谓的“拓扑体”…...

OSI模型中协议数据单元(PDU)

OSI模型中协议数据单元&#xff08;PDU&#xff09; 协议数据单元&#xff08;Protocol Data Unit, PDU&#xff09;是网络通信中每一层协议处理的数据单位&#xff0c;其内容和格式由特定层的协议定义。PDU在不同OSI层次中有不同的名称和结构&#xff0c;体现了分层模型的核心…...

代码训练营day24 回溯算法

回溯算法part03 93.复原IP地址 题目链接/文章讲解&#xff1a;代码随想录 视频讲解&#xff1a;回溯算法如何分割字符串并判断是合法IP&#xff1f;| LeetCode&#xff1a;93.复原IP地址_哔哩哔哩_bilibili 本题关键在于终止条件 插入3个’.’时判断 ip地址最后一段是否…...

DP Alt Mode 与 DP协议的关系

1. 什么是 “Alt Mode”&#xff08;替代模式&#xff09;&#xff1f; Alt Mode&#xff08;Alternative Mode&#xff09; 是 USB Type-C 接口 的扩展协议机制&#xff0c;允许通过 物理接口复用&#xff08;Pin Reuse&#xff09; 将USB-C接口动态切换为其他协议&#xff0…...

【欧拉筛】哥德巴赫猜想题解

哥德巴赫猜想题解 题目传送门 1292. 哥德巴赫猜想 一、题目描述 哥德巴赫猜想指出&#xff1a;任意一个大于4的偶数都可以拆成两个奇素数之和。给定多个偶数(6 ≤ n < 10^6)&#xff0c;验证它们是否符合这个猜想。对于每个偶数&#xff0c;输出其素数分解中两数差最大的…...

A*算法详解及Python实现

一、什么是A*算法&#xff1f; A*&#xff08;读作"A-star"&#xff09;算法是一种广泛使用的路径查找和图形遍历算法&#xff0c;它结合了Dijkstra算法的完备性和贪婪最佳优先搜索的高效性。A*算法通过使用启发式函数来估算从当前节点到目标节点的成本&#xff0c;…...

【C++】第九节—string类(中)——详解+代码示例

hello&#xff01; 云边有个稻草人-CSDN博客 C_云边有个稻草人的博客-CSDN博客 菜鸡进化中。。。 目录 【补充】 二、string类里面的常用接口 1.resize 2.insert 3.assign 4.erase 5.replacefind 6.c_str 7.rfindsubstr 8.find_first_of、find_last_of、find_first…...

vite.config.js常用配置

vite 是一个基于 Vue3 单文件组件的非打包开发服务器&#xff0c;它做到了本地快速开发启动&#xff1a; 快速的冷启动&#xff0c;不需要等待打包操作&#xff1b; 即时的热模块更新&#xff0c;替换性能和模块数量的解耦让更新飞起&#xff1b; 真正的按需编译&#xff0c;不…...

【C++11(下)】—— 我与C++的不解之缘(三十二)

前言 随着 C11 的引入&#xff0c;现代 C 语言在语法层面上变得更加灵活、简洁。其中最受欢迎的新特性之一就是 lambda 表达式&#xff08;Lambda Expression&#xff09;&#xff0c;它让我们可以在函数内部直接定义匿名函数。配合 std::function 包装器 使用&#xff0c;可以…...

李臻20242817_安全文件传输系统项目报告_第6周

安全文件传输系统项目报告&#xff08;第 1 周&#xff09; 1. 代码链接 Gitee 仓库地址&#xff1a;https://gitee.com/li-zhen1215/homework/tree/master/Secure-file 代码结构说明&#xff1a; project-root/├── src/ # 源代码目录│ ├── main.c # 主程序入口│ ├…...

使用SymPy求解矩阵微分方程

引言 在数学、物理、工程等领域,微分方程常常被用来描述系统的变化和动态过程。对于多变量系统或者多方程系统,矩阵微分方程是非常常见的,它可以用来描述如电路、控制系统、振动系统等复杂的动态行为。今天,我们将通过Python 中的 SymPy 库来求解矩阵微分方程,帮助大家轻…...

Flutter之用户输入网络数据缓存

目录&#xff1a; 1、处理用户输入1.1、按钮1.2、文本1.3、富文本1.4、TextField1.5、Form 2、复选框、Switch 和 Radio2.1、复选框2.2、Switch2.3、Radio 3、选择日期或时间4、滑动5、网络和数据6、本地缓存6.1、在本地内存中缓存数据 7、web端和Flutter样式控制对比7.1、文本…...

华为IP(4)

VRRP&#xff08;虚拟路由冗余协议&#xff09; 前言&#xff1a; 局域网中的用户终端通常采用配置一个默认网关的形式访问外部网络&#xff0c;如果默认网关设备发生故障&#xff0c;那么所有用户终端访问外部网络的流量将会中断。可以通过部署多个网关的方式来解决单点故障…...

蓝桥杯刷题周计划(第四周)

目录 前言题目一题目代码题解分析 题目二题目代码题解分析 题目三题目代码题解分析 题目四题目代码题解分析 题目五题目代码题解分析 题目六题目代码题解分析 题目七题目代码题解分析 题目八题目代码题解分析 题目九题目代码题解分析 题目十题目代码题解分析题目代码题解分析 题…...

华为网路设备学习-17

目录 一、加密算法 二、验证算法 三、IPsec协议 1.IKE协议&#xff08;密钥交换协议&#xff09; ①‌ISAKMP&#xff08;Internet Security Association and Key Management Protocol&#xff09;互联网安全关联和密钥管理协议 ②安全关联&#xff08;SA&#xff09; ③…...

【动态规划】深入动态规划 非连续子序列问题

文章目录 前言例题一、最长递增子序列二、摆动序列三、最长递增子序列的个数四、最长数对链五、最长定差子序列六、最长的斐波那契子序列的长度七、最长等差数列八、等差数列划分II - 子序列 结语 前言 什么是动态规划中的非连续子序列问题&#xff1f; 动态规划中的非连续子序…...

灵魂拷问,指针为什么是C语言的灵魂?

目录 | 引 言 | 内存操作 | 构造复杂的数据结构 | 底层硬件交互 | 指针的陷阱 | 文 末 | 引 言 指针是C语言的灵魂&#xff01; 这句话是不是很耳熟&#xff1f;但为什么这么说&#xff0c;你知道吗&#xff1f; 本篇小文就从内存、数据结构、底层硬件交互这三个维度来…...

Node.js自定义中间件

目录 Node.js 自定义中间件详细介绍 1. 目录结构 2. 什么是自定义中间件&#xff1f; 3. 代码实现 1. 自定义日志中间件&#xff08;记录请求信息&#xff09; 2. 自定义身份验证中间件&#xff08;校验用户权限&#xff09; 3. 自定义请求时间中间件&#xff08;记录请…...

Qt 音乐播放器项目

具体代码见&#xff1a;https://gitee.com/Suinnnnnn/MusicPlayer 文章目录 0. 预备1. 界面1.1 各部位长度1.2 ui文件1.3 窗口前置设置1.4 设置QSS 2. 自定义控件2.1 按钮2.2 推荐页面2.3 CommonPage2.4 滑杆 3. 音乐管理4. 歌词界面4.1 ui文件4.2 LrcPage.h文件 5. 音乐播放控…...

初识数据结构——Java集合框架解析:List与ArrayList的完美结合

&#x1f4da; Java集合框架解析&#xff1a;List与ArrayList的完美结合 &#x1f31f; 前言&#xff1a;为什么我们需要List和ArrayList&#xff1f; 在日常开发中&#xff0c;我们经常需要处理一组数据。想象一下&#xff0c;如果你要管理一个班级的学生名单&#xff0c;或…...

LightRAG实战:轻松构建知识图谱,破解传统RAG多跳推理难题

作者&#xff1a;后端小肥肠 &#x1f34a; 有疑问可私信或评论区联系我。 &#x1f951; 创作不易未经允许严禁转载。 姊妹篇&#xff1a; 2025防失业预警&#xff1a;不会用DeepSeek-RAG建知识库的人正在被淘汰_deepseek-embedding-CSDN博客 从PDF到精准答案&#xff1a;Coze…...

Hyperlane框架全面详解与应用指南 [特殊字符][特殊字符][特殊字符]

Hyperlane框架全面详解与应用指南 &#x1f680;&#x1f680;&#x1f680; &#x1f4da; 前言 欢迎来到Hyperlane框架的全面详解与应用指南&#xff01;&#x1f389;&#x1f389;&#x1f389; 本文档旨在为开发者提供一个全面、详尽的Hyperlane框架使用指南&#xff0c…...

使用LVS的 NAT 模式实现 3 台RS的轮询访问

题目 使用LVS的 NAT 模式实现 3 台RS的轮询访问。IP地址和主机自己规划。 -i— turn&#xff0c;-g——DR模式&#xff0c;-m——NAT模式 节点规划 仅主机网段&#xff1a;192.168.216.0/24 NAT网段&#xff1a;192.168.88.0/24 主机角色系统网络ipclientclientredhat9.5仅…...

BGP路由协议之属性4

MED 多出口鉴别器 可选非过渡属性 EBGP 的邻居 Cost 开销值&#xff0c;控制如何进入 AS。越小越优。继承 IGP 的开销值&#xff0c;默认 0 MED(Multi-Exit Discriminator&#xff0c;多出口鉴别器)是可选非过属性&#xff0c;是一种度量值用于向外部对等体指出进入本 AS 的首…...

数据库的操作

1.创建数据库 CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [,create_specification] ...]create_specification: [DEFAULT] CHARACTER SET charset_name [DEFAULT] COLLATE collation_name 大写的表示关键字。[]是可选项。CHARACTER SET&#xff1a;指定…...

【愚公系列】《高效使用DeepSeek》055-可靠性评估与提升

🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! 👉 江湖人称"愚公搬代码",用七年如一日的精神深耕技术领域,以"…...

记录clickhouse记录一次性能优化,从60s到1s

文章目录 问题表结构类似如下分析第一步调整第一步观察多磁盘读继续观察sql 问题 一个查询接口&#xff0c;涉及多个clickhouse 查询&#xff0c;查询用时一下变成要60s 表结构类似如下 CREATE TABLE demo.test_local (id UUID,date DateTime,type String ) ENGINE Replic…...

二叉树的层序遍历

102. Binary Tree Level Order Traversal 广度优先搜索 将每个结点的层号记录下。 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* …...

嵌入式硬件篇---TOF陀螺仪SPI液晶屏

文章目录 前言1. TOF传感器&#xff08;Time of Flight&#xff09;原理STM32使用方法硬件连接SDASCLVCC\GND 软件配置初始化I2C外设库函数驱动&#xff1a;读取数据 2. 陀螺仪&#xff08;如MPU6050&#xff09;原理STM32使用方法硬件连接SDA/SCLINTVCC/GND 软件配置初始化I2C…...

OpenCV 在树莓派上进行实时人脸检测

这段 Python 代码借助 OpenCV 库实现了在树莓派上进行实时人脸检测的功能。它会开启摄像头捕获视频帧&#xff0c;在每一帧里检测人脸并以矩形框标记出来&#xff0c;同时在画面上显示帧率&#xff08;FPS&#xff09;。 依赖库 cv2&#xff1a;OpenCV 库&#xff0c;用于计算…...

55.跳跃游戏

​​题目来源&#xff1a; leetcode题目&#xff0c;网址&#xff1a;55. 跳跃游戏 - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1a; 遍历数组&#xff0c;若当前节点可达&#xff0c;更新可到达的最远距离&#xff0c;否则返回false。若可遍历整个数组&#xf…...

awk 实现listagg ,count 功能

awk命令实现分组统计 测试数据 ABC a1 ABC a2 ABC a3 ABD c1 ABD c2 分组统计 abc a1,a2,a3 3 abd c1,c2 awk 命令 awk {arr[$1]arr[$1] ? arr[$1] "," $2 : $2; count[$1]} END{for (i in arr) print tolower(i), arr[i], count[i]} group_…...

瑞萨RA4M2使用心得-GPIO输出

目录 一、新建项目 二、图形化开发 1.初始化IO 2.界面介绍 3.代码编写 4.所有内部函数的封装位置 5.LED闪烁函数编写 三.debug运行 总结 环境&#xff1a; 开发板&#xff1a;RA-Eco-RA4M2-100PIN-V1.0 IDE&#xff1a;e2 studio 一、新建项目 正常操作&#xff0c;下…...

uniapp微信小程序引入vant组件库

1、首先要有uniapp项目&#xff0c;根据vant官方文档使用yarn或npm安装依赖&#xff1a; 1、 yarn init 或 npm init2、 # 通过 npm 安装npm i vant/weapp -S --production# 通过 yarn 安装yarn add vant/weapp --production# 安装 0.x 版本npm i vant-weapp -S --production …...

COZE通关指南:工作流与插件开发

前言 本文隶属于专栏《AI Agent 通关指南》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和参考文献请见《AI Agent 通关指南》 正文 1. 平台基础介绍 🌟 1.1 COZE平台概述 COZE平台(coze.cn)是一个强大的AI应用开发平台…...

在Unity中,如果物体上的脚本丢失,可以通过编写一个自定义编辑器脚本来查找并删除这些丢失的组件

在Unity中&#xff0c;如果物体上的脚本丢失&#xff0c;可以通过编写一个自定义编辑器脚本来查找并删除这些丢失的组件。以下是一个示例脚本&#xff0c;它可以帮助你一键检索场景中所有丢失脚本的物体&#xff0c;并删除这些丢失的组件。 步骤&#xff1a; 创建编辑器脚本&a…...

青少年编程与数学 02-016 Python数据结构与算法 04课题、栈与队列

青少年编程与数学 02-016 Python数据结构与算法 04课题、栈与队列 一、栈1. 栈的定义2. 栈的特点3. 栈的基本操作示例 4. 栈的实现&#xff08;1&#xff09;数组实现&#xff08;2&#xff09;链表实现 5. 栈的应用&#xff08;1&#xff09;函数调用&#xff08;2&#xff09…...

Lucene.Net全文搜索引擎:架构解析与全流程实战指南

文章目录 引言&#xff1a;为什么选择Lucene.Net&#xff1f;一、Lucene.Net核心架构剖析1.1 模块化设计 二、Lucene.Net索引原理揭秘2.1 倒排索引&#xff1a;搜索的基石2.2 段&#xff08;Segment&#xff09;机制 三、全流程实战&#xff1a;从0到1构建搜索引擎3.1 环境准备…...

OpenSceneGraph 中的 LOD详解

LOD (Level of Detail&#xff0c;细节层次) 是3D图形中一种重要的优化技术&#xff0c;OpenSceneGraph 通过 osg::LOD 类提供了完整的LOD支持。 一、LOD 基本概念 1. 什么是LOD 核心思想&#xff1a;根据物体与相机的距离显示不同细节程度的模型 目的&#xff1a;减少远处物…...

程序化广告行业(64/89):AdX/SSP系统广告位设置全解析

程序化广告行业&#xff08;64/89&#xff09;&#xff1a;AdX/SSP系统广告位设置全解析 大家好&#xff01;我一直觉得在技术和营销不断融合的当下&#xff0c;程序化广告领域充满了机遇与挑战。之前和大家分享了程序化广告PDB模式的相关知识&#xff0c;今天想接着和大家一起…...

Pytorch中的计算图(Computational Graph)是什么

&#x1f9e9; 一、什么是计算图&#xff1f; 计算图是一种“有向无环图&#xff08;DAG&#xff09;”&#xff0c;表示变量&#xff08;张量&#xff09;之间的运算关系。 节点&#xff1a;张量或操作&#xff08;如加法、乘法&#xff09;边&#xff1a;数据流&#xff08;即…...

Java 大视界 -- Java 大数据在航天遥测数据分析中的技术突破与应用(177)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

【Linux操作系统——学习笔记三】Linux环境下多级目录构建与管理的命令行实践报告

1.在用户主目录下&#xff0c;使用以下方法新建目录&#xff0c;并显示详细执行过程&#xff1a; &#xff08;1&#xff09;使用绝对路径在当前目录下创建 new_dir目录 &#xff08;2&#xff09;使用相对路径、在当前目录创建dir1、dir2、dir3目录 &#xff08;3&#xff09…...