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

Opencv之RANSAC算法用于直线拟合及特征点集匹配详解

Opencv之RANSAC算法用于直线拟合及特征点集匹配详解

    1. 讲述Ransac拟合与最小二乘在曲线拟合上的优缺点
    1. 讲述在进行特征点匹配时,最近邻匹配与Ransac匹配的不同之处
    1. 另外,Ransac也被用于椭圆拟合、变换矩阵求解等

1. 直线拟合

1.1 原理

  • RANSAC(RANdom SAmple Consensus,随机采样一致)算法是从一组含有“外点”(outliers)的数据中正确估计数学模型参数的迭代算法。“外点”一般指的的数据中的噪声,比如说匹配中的误匹配和估计曲线中的离群点。故RANSAC也是一种“外点”检测算法。同时RANSAC是一个非确定性算法,在某种意义上说,它会产生一个在一定概率下合理的结果,其允许使用更多次的迭代来使其概率增加。

  • RANSAC算最早是由Fischler和Bolles在SRI上提出用来解决LDP(Location Determination Problem,位置确定问题)问题的。

  • 对于RANSAC算法来说一个基本的假设就是数据是由“内点”和“外点”组成的。“内点”就是组成模型参数的数据,“外点”就是不适合模型的数据。同时RANSAC假设:在给定一组含有少部分“内点”的数据,存在一个程序可以估计出符合“内点”的模型

  • 算法主要思想:

  • 给定一个数据集S,从中选择建立模型所需的最小样本数(空间直线最少可以由两个点确定,所以最小样本数是2,空间平面可以根据不共线三点确定,所以最小样本数为3,拟一个圆时,最小样本数是3),记选择数据集为S1
    使用选择的数据集S1计算得到一个数学模型M1
  • 用计算的模型M1去测试数据集中剩余的点,如果测试的数据点在误差允许的范围内,则将该数据点判为内点(inlier),否则判为外点(outlier),记所有内点组成的数据集为S1*,S1* 称作 S1的一致性集合
  • 比较当前模型和之前推出的最好的模型的“内点”的数量,记录最大“内点”数量时模型参数和“内点”数量
  • 重复1-4步,直到迭代结束或者当前模型已经足够好了(“内点数目大于设定的阈值”);每次产生的模型要么因为内点太少而被舍弃,要么因为比现有的模型更好而被选用
  • 其过程如下图所示:
    取点集中的两点确定一条直线,然后通过设定规则选取筛选内殿,拿最多的内点拟合出来的模型作为最终的可用模型
    在这里插入图片描述

1.2 迭代次数推导

  • 根据上面RANSAC基本原理的介绍,在这算法流程中存在两个重要的参数需要设置,迭代次数(采样次数)和距离阈值。
    迭代的次数我们应该选择多大呢?这个值是否可以事先知道应该设为多少呢?还是只能凭经验决定呢? 这个值其实是可以估算出来的。下面来推算一下。
    在这里插入图片描述

内点的概率t通常是一个先验值。然后P 是我们希望RANSAC得到正确模型的概率。如果事先不知道t 的值,可以使用自适应迭代次数的方法。也就是一开始设定一个无穷大的迭代次数,然后每次更新模型参数估计的时候,用当前的内点比值当成t 来估算出迭代次数。

1.3 与最小二乘区别

  • 最小二乘法尽量去适应包括外点在内的所有点。因此,最小二乘法只适合与误差较小的情况。假使需要从一个噪音较大的数据集中提取模型(比方说只有20%的数据时符合模型的)时,最小二乘法就显得力不从心了。
    在这里插入图片描述
  • RANSAC相当于一个概率模型,它通过计算内点出现的概率,找出噪点之外的点集拟合出的 最优模型,通常更能表示系统属性。其相当于迭代使用最小二乘法+抽样测试。

1.4 代码实现

  • C++实现:
//====================================================================//
//Program:RANSAC直线拟合,并与最小二乘法结果进行对比
//====================================================================//
#include <iostream>
#include <opencv2/opencv.hpp>//RANSAC 拟合2D 直线
//输入参数:points--输入点集
//        iterations--迭代次数
//        sigma--数据和模型之间可接受的差值,车道线像素宽带一般为10左右
//              (Parameter use to compute the fitting score)
//        k_min/k_max--拟合的直线斜率的取值范围.
//                     考虑到左右车道线在图像中的斜率位于一定范围内,
//                      添加此参数,同时可以避免检测垂线和水平线
//输出参数:line--拟合的直线参数,It is a vector of 4 floats
//              (vx, vy, x0, y0) where (vx, vy) is a normalized
//              vector collinear to the line and (x0, y0) is some
//              point on the line.
//返回值:无
void fitLineRansac(const std::vector<cv::Point2f>& points,cv::Vec4f &line,int iterations = 1000,double sigma = 1.,double k_min = -7.,double k_max = 7.)
{unsigned int n = points.size();if(n<2){return;}cv::RNG rng;double bestScore = -1.;for(int k=0; k<iterations; k++){int i1=0, i2=0;while(i1==i2){i1 = rng(n);i2 = rng(n);}const cv::Point2f& p1 = points[i1];const cv::Point2f& p2 = points[i2];cv::Point2f dp = p2-p1;//直线的方向向量dp *= 1./norm(dp);double score = 0;if(dp.y/dp.x<=k_max && dp.y/dp.x>=k_min ){for(int i=0; i<n; i++){cv::Point2f v = points[i]-p1;double d = v.y*dp.x - v.x*dp.y;//向量a与b叉乘/向量b的摸.||b||=1./norm(dp)//score += exp(-0.5*d*d/(sigma*sigma));//误差定义方式的一种if( fabs(d)<sigma )score += 1;}}if(score > bestScore){line = cv::Vec4f(dp.x, dp.y, p1.x, p1.y);bestScore = score;}}
}int main()
{cv::Mat image(720,1280,CV_8UC3,cv::Scalar(125,125,125));//以车道线参数为(0.7657,-0.6432,534,548)生成一系列点double k = -0.6432/0.7657;double b = 548 - k*534;std::vector<cv::Point2f> points;for (int i = 360; i < 720; i+=10){cv::Point2f point(int((i-b)/k),i);points.emplace_back(point);}//加入直线的随机噪声cv::RNG rng((unsigned)time(NULL));for (int i = 360; i < 720; i+=10){int x = int((i-b)/k);x = rng.uniform(x-10,x+10);int y = i;y = rng.uniform(y-30,y+30);cv::Point2f point(x,y);points.emplace_back(point);}//加入噪声for (int i = 0; i < 720; i+=20){int x = rng.uniform(1,640);int y = rng.uniform(1,360);cv::Point2f point(x,y);points.emplace_back(point);}int n = points.size();for (int j = 0; j < n; ++j){cv::circle(image,points[j],5,cv::Scalar(0,0,0),-1);}//RANSAC 拟合if(1){cv::Vec4f lineParam;fitLineRansac(points,lineParam,1000,10);double k = lineParam[1] / lineParam[0];double b = lineParam[3] - k*lineParam[2];cv::Point p1,p2;p1.y = 720;p1.x = ( p1.y - b) / k;p2.y = 360;p2.x = (p2.y-b) / k;cv::line(image,p1,p2,cv::Scalar(0,255,0),2);}//最小二乘法拟合if(1){cv::Vec4f lineParam;cv::fitLine(points,lineParam,cv::DIST_L2,0,0.01,0.01);double k = lineParam[1] / lineParam[0];double b = lineParam[3] - k*lineParam[2];cv::Point p1,p2;p1.y = 720;p1.x = ( p1.y - b) / k;p2.y = 360;p2.x = (p2.y-b) / k;cv::line(image,p1,p2,cv::Scalar(0,0,255),2);}cv::imshow("image",image);cv::waitKey(0);return 0;
}

在这里插入图片描述

  • Python 实现:
#!/usr/bin/env python3
#coding=utf-8#============================#
#Program:RANSAC_Line.py
===========#import numpy as np
import random
import mathimport cv2def fitLineRansac(points,iterations=1000,sigma=1.0,k_min=-7,k_max=7):"""RANSAC 拟合2D 直线:param points:输入点集,numpy [points_num,1,2],np.float32:param iterations:迭代次数:param sigma:数据和模型之间可接受的差值,车道线像素宽带一般为10左右(Parameter use to compute the fitting score):param k_min::param k_max:k_min/k_max--拟合的直线斜率的取值范围.考虑到左右车道线在图像中的斜率位于一定范围内,添加此参数,同时可以避免检测垂线和水平线:return:拟合的直线参数,It is a vector of 4 floats(vx, vy, x0, y0) where (vx, vy) is a normalizedvector collinear to the line and (x0, y0) is somepoint on the line."""line = [0,0,0,0]points_num = points.shape[0]if points_num<2:return linebestScore = -1for k in range(iterations):i1,i2 = random.sample(range(points_num), 2)p1 = points[i1][0]p2 = points[i2][0]dp = p1 - p2 #直线的方向向量dp *= 1./np.linalg.norm(dp) # 除以模长,进行归一化score = 0a = dp[1]/dp[0]if a <= k_max and a>=k_min:for i in range(points_num):v = points[i][0] - p1dis = v[1]*dp[0] - v[0]*dp[1]#向量a与b叉乘/向量b的摸.||b||=1./norm(dp)# score += math.exp(-0.5*dis*dis/(sigma*sigma))误差定义方式的一种if math.fabs(dis)<sigma:score += 1if score > bestScore:line = [dp[0],dp[1],p1[0],p1[1]]bestScore = scorereturn lineif __name__ == '__main__':image = np.ones([720,1280,3],dtype=np.ubyte)*125# 以车道线参数为(0.7657, -0.6432, 534, 548)生成一系列点k = -0.6432 / 0.7657b = 548 - k * 534points = []for i in range(360,720,10):point = (int((i-b)/k),i)points.append(point)# 加入直线的随机噪声for i in range(360,720,10):x = int((i-b)/k)x = random.sample(range(x-10,x+10),1)y = iy = random.sample(range(y - 30, y + 30),1)point = (x[0],y[0])points.append(point)# 加入噪声for i in range(0,720,20):x = random.sample(range(1, 640), 1)y = random.sample(range(1, 360), 1)point = (x[0], y[0])points.append(point)for point in points:cv2.circle(image,point,5,(0,0,0),-1)points = np.array(points).astype(np.float32)points = points[:,np.newaxis,:]# RANSAC 拟合if 1:[vx, vy, x, y] = fitLineRansac(points,1000,10)k = float(vy) / float(vx)  # 直线斜率b = -k * x + yp1_y = 720p1_x = (p1_y-b) / kp2_y = 360p2_x = (p2_y-b) / kp1 = (int(p1_x),int(p1_y))p2 = (int(p2_x), int(p2_y))cv2.line(image,p1,p2,(0,255,0),2)# 最小二乘法拟合if 1:[vx, vy, x, y] = cv2.fitLine(points, cv2.DIST_L2, 0, 0.1, 0.01)k = float(vy) / float(vx)  # 直线斜率b = -k * x + yp1_y = 720p1_x = (p1_y - b) / kp2_y = 360p2_x = (p2_y - b) / kp1 = (int(p1_x), int(p1_y))p2 = (int(p2_x), int(p2_y))cv2.line(image, p1, p2, (0, 0, 255), 2)cv2.imshow('image',image)cv2.waitKey(0)

2. 特征匹配

  • 基于特征的图像匹配中会存在误匹配对,因此为提高匹配率,在粗匹配的基础上实现精匹配,可采用下面两种方法:
    在这里插入图片描述
  • 用RANSAC算法来寻找最佳单应性矩阵H,在此先提取SIFT特征点进行最近邻粗匹配,然后采取Ransac进行细匹配,最后再进行变换矩阵求解
  • 代码实现如下:
//RANSAC算法
int main()
{Mat img_object = imread("./data/101.png", IMREAD_GRAYSCALE);Mat img_scene = imread("./data/100.png", IMREAD_GRAYSCALE);if (img_object.empty() || img_scene.empty()){cout << "Could not open or find the image!\n" << endl;return -1;}//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptorsint minHessian = 800; // default: 400Ptr<SURF> surf = SURF::create(800);std::vector<KeyPoint> keypoints_object, keypoints_scene;Mat descriptors_object, descriptors_scene;surf->detectAndCompute(img_object, noArray(), keypoints_object, descriptors_object);surf->detectAndCompute(img_scene, noArray(), keypoints_scene, descriptors_scene);//-- Step 2: Matching descriptor vectors with a FLANN based matcher// Since SURF is a floating-point descriptor NORM_L2 is usedPtr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::FLANNBASED);std::vector< std::vector<DMatch> > knn_matches;matcher->knnMatch(descriptors_object, descriptors_scene, knn_matches, 2);//-- Filter matches using the Lowe's ratio testconst float ratio_thresh = 0.75f;std::vector<DMatch> good_matches;for (size_t i = 0; i < knn_matches.size(); i++){if (knn_matches[i][0].distance < ratio_thresh * knn_matches[i][1].distance){good_matches.push_back(knn_matches[i][0]);}}//-- Draw matchesMat img_matches;drawMatches(img_object, keypoints_object, img_scene, keypoints_scene, good_matches, img_matches, Scalar::all(-1),Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);//-- Localize the objectstd::vector<Point2f> obj;std::vector<Point2f> scene;for (size_t i = 0; i < good_matches.size(); i++){//-- Get the keypoints from the good matchesobj.push_back(keypoints_object[good_matches[i].queryIdx].pt);scene.push_back(keypoints_scene[good_matches[i].trainIdx].pt);}vector<uchar>inliers;Mat H = findHomography(obj, scene, inliers, RANSAC);//-- Draw matches with RANSACMat img_matches_ransac;std::vector<DMatch> good_matches_ransac;for (size_t i = 0; i < inliers.size(); i++){if (inliers[i]){good_matches_ransac.push_back(good_matches[i]);}}drawMatches(img_object, keypoints_object, img_scene, keypoints_scene, good_matches_ransac, img_matches_ransac, Scalar::all(-1),Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);namedWindow("img_matches", WINDOW_NORMAL);imshow("img_matches", img_matches);imwrite("img_matches.jpg", img_matches);namedWindow("img_matches_ransac", WINDOW_NORMAL);imshow("img_matches_ransac", img_matches_ransac);imwrite("img_matches_ransac.jpg", img_matches_ransac);waitKey();return 0;
}
  • 只进行knn匹配与加上Ransac匹配的效果对比图如下:
    在这里插入图片描述

参考:

1.https://blog.csdn.net/leonardohaig/article/details/104570965?spm=1001.2014.3001.5506
2.https://blog.csdn.net/H19981118/article/details/122014318?spm=1001.2014.3001.5506

相关文章:

Opencv之RANSAC算法用于直线拟合及特征点集匹配详解

Opencv之RANSAC算法用于直线拟合及特征点集匹配详解 讲述Ransac拟合与最小二乘在曲线拟合上的优缺点 讲述在进行特征点匹配时&#xff0c;最近邻匹配与Ransac匹配的不同之处 另外&#xff0c;Ransac也被用于椭圆拟合、变换矩阵求解等 1. 直线拟合 1.1 原理 RANSAC(RANdom …...

Jenkins环境部署与任务构建

一、CI/CD 1、CI/CD 概念&#xff1a; CI/CD 是一种软件开发和交付方法&#xff0c;旨在加速应用程序的开发、测试和部署过程&#xff0c;以提高软件交付的质量和效率。 (1) 持续集成 (CI Continuous Integration): 持续集成是开发团队频繁集成其代码更改的过程。开发者将其…...

ES6 Class和Class继承

1.class的基本语法 class可以理解为是一个语法糖&#xff0c;将js只能通过构造函数创建实例的方法进行了补充 构造函数&#xff1a; function Person ({ name, age18 }) {this.name namethis.age age } new Person({name: 张三}) Class类&#xff1a; class Person {con…...

C++11 packaged_task

std::packaged_task 把一个方法打包成一个task扔到线程中执行&#xff0c;然后通过packaged_task中的furture等待执行结果。 void test_promise() {std::packaged_task <int()> task([]()->int {std::cout << "packaged_task begin \n" << std…...

delete、drop、truncate三兄弟

比较方面/具体命令deletetruncatedrop删除范围逐行删除&#xff08;记录行&#xff09;逐页删除&#xff08;数据页&#xff09;整张表&#xff08;数据表结构&#xff09;所属范畴数据操作语言&#xff08;DML&#xff09;数据定义语言&#xff08;DDL&#xff09;数据定义语言…...

C/C++运算优先级

文章目录 前言1.运算优先级表2.举例说明&#xff1a;总结 前言 最近复习C基础知识的时候&#xff0c;发现对这部分还是有些模糊。常用的 - &#xff0c;括号等运算符对于它们的优先级还是比较明确的。但是涉及到移位运算&#xff0c;逻辑运算这种&#xff0c;再结合四则运算…...

apache搭建静态网站,moongoose搭建网站后台,出现的跨域问题解决

文章目录 1&#xff0c;问题描述1.1&#xff0c;当网页和后台是不同服务时会产生跨域问题1.2&#xff0c;跨域问题 2&#xff0c;nginx端口转发解决跨域问题2.1&#xff0c;下载并安装nginx2.1.1&#xff0c;解压后如下所示2.1.2&#xff0c;进入解压目录后&#xff0c;执行配置…...

LiveQing视频点播流媒体RTMP推流服务功能-支持视频点播分屏大屏展示视频轮巡分组播放RMP推流直播大屏展示

LiveQing支持视频点播分屏大屏展示视频轮播分组播放RMP推流直播大屏展示 1、分屏展示2、轮巡播放3、RTMP推流视频直播和点播流媒体服务 1、分屏展示 LiveQing支持将视频点播、鉴权直播&#xff0c;拉转直播视频流&#xff0c;进行分屏播放。 2、轮巡播放 3、RTMP推流视频直播和…...

tf loss构建常用到函数

1、tf.map_fn tf.map_fn是TensorFlow中的一个函数&#xff0c;用于对给定的函数和输入进行逐元素的映射&#xff0c;其定义如下&#xff1a; tf.map_fn(fn,elems,dtypeNone,parallel_iterationsNone,back_propTrue,swap_memoryFalse,infer_shapeTrue,nameNone,fn_output_sign…...

行为型模式-备忘录模式

备忘录模式保存一个对象的某个状态&#xff0c;以便在适当的时候恢复对象。备忘录模式属于行为型模式。 意图&#xff1a;在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态。 主要解决&#xff1a;所谓备忘录模式就是在不破坏…...

Android Studio初学者实例:RecyclerView学习--模仿今日头条--续

新学期开始了&#xff0c;这篇文章收到了很多人的评论有很多地方不懂&#xff0c;所以写下了以下的文章--续篇 首先使用RecyclerView也好还是使用ListView&#xff0c;更或是GridView你都要先构思需要什么 这些东西无一例外通常都是用在列表显示下&#xff0c;那么需要一些&a…...

栈和队列的C++模拟实现

一、栈stack 1.介绍&#xff08;库里面的文档介绍&#xff09; 1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入与提取操作。 2. stack是作为容器适配器被实现的&#xff0c;容器适配器即是对…...

UE4/5:通过Blender制作BlendShape导入【UE4/5曲线、变形目标,blender形态键】

UE4/5里面&#xff0c;我们经常可以在一些骨骼模型上面看到相关的曲线&#xff0c;如Metahuman里面就是通过这个曲线来改变人物的脸部表情。 而这里笔者将教导如何去制作这种曲线。 这种曲线都是存在于骨骼模型上的&#xff0c;所以我们要么直接制作骨骼模型导入ue&#xff0…...

微信小程序进阶——后台交互

目录 一、后台准备 1.1 pom.xml 1.2 配置数据源 1.3 整合mybatis 二、前后端交互 2.1 method1 2.2 method2 2.2.1 封装request 2.2.2 头部引用util 2.2.3 编写方法 2.2.4 展示效果 三、WXS的使用 3.1 会议状态 3.1.2 引入wxs 3.1.3 修改代码 3.1.4 展示效果 3…...

二维码智慧门牌管理系统升级解决方案:突破传统,实现质检与抽检的个性化配置

文章目录 前言一、引入“独立质检”二、个性化抽检类别设定三、触发重采要素的功能升级四、升级优势与展望 前言 在数字化时代&#xff0c;智慧门牌管理系统已经成为社会管理的重要工具。为了满足各种复杂需求&#xff0c;系统升级是必然趋势。本次升级主要针对质检和抽检两大…...

《动手学深度学习 Pytorch版》 9.4 双向循环神经网络

之前的序列学习中假设的目标是在给定观测的情况下对下一个输出进行建模&#xff0c;然而也存在需要后文预测前文的情况。 9.4.1 隐马尔可夫模型中的动态规划 数学推导太复杂了&#xff0c;略。 9.4.2 双向模型 双向循环神经网络&#xff08;bidirectional RNNs&#xff09;…...

【Axure高保真原型】可视化图表图标

今天和粉丝们免费分享可视化图表图标原型模板&#xff0c;包括柱状图、条形图、环形图、散点图、水波图等常用的可视化图表图标。 【原型效果】 【原型预览】 https://axhub.im/ax9/d402c647c82f9185/#c1 【原型下载】 这个模板可以在 Axure高保真原型哦 小程序里免费下载哦…...

安装mmcv及GPU版本的pytorch及torchvision

一、先装GPU版本的pytorch和torchvision pip install torch1.9.1cu111 torchvision0.10.1cu111 torchaudio0.9.1 -f https://download.pytorch.org/whl/torch_stable.html注意&#xff1a;以上适用cuda11.1版本 如果想离线安装&#xff0c;就看这篇文章 二、安装mmcv 看这篇…...

全国342个城市往返最短通勤时间(铁路)数据

全国342个城市往返最短通勤时间&#xff08;铁路&#xff09;数据 1、时间&#xff1a;采集时间是2022年 2、来源&#xff1a;12306 3、数据说明&#xff1a;数据采集12306数据&#xff0c;整理全国342个城市往返最短通勤时间&#xff0c;本数据是铁路包含动车、高铁所有路线…...

AWK语言第二版 第3章.探索性数据分析 3.1泰坦尼克号的沉没

这章也是第一版没有&#xff0c;第二版新增的。 3. 探索性数据分析 上一章给出了一些个人使用的小脚本&#xff0c;通常是特制或专用的。在本章中&#xff0c;我们还会展示Awk在现实中的典型使用场景&#xff1a;使用Awk和其他工具来非正式地探索一些真实的数据&#xff0c;目…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

【UE5 C++】通过文件对话框获取选择文件的路径

目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 &#xff0c;这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器&#xff0c;右键点击 .uproject 文件&#xff0c;选择 "Generate Visual Studio project files"&#xff0c;重…...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...

【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解

一、前言 在HarmonyOS 5的应用开发模型中&#xff0c;featureAbility是旧版FA模型&#xff08;Feature Ability&#xff09;的用法&#xff0c;Stage模型已采用全新的应用架构&#xff0c;推荐使用组件化的上下文获取方式&#xff0c;而非依赖featureAbility。 FA大概是API7之…...

rm视觉学习1-自瞄部分

首先先感谢中南大学的开源&#xff0c;提供了很全面的思路&#xff0c;减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接&#xff1a;https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架&#xff1a; 代码框架结构&#xff1a;readme有…...

医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor

1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...

使用homeassistant 插件将tasmota 接入到米家

我写一个一个 将本地tasmoat的的设备同通过ha集成到小爱同学的功能&#xff0c;利用了巴法接入小爱的功能&#xff0c;将本地mqtt转发给巴法以实现小爱控制的功能&#xff0c;前提条件。1需要tasmota 设备&#xff0c; 2.在本地搭建了mqtt服务可&#xff0c; 3.搭建了ha 4.在h…...