C/C++开发,opencv-ml库学习,K近邻(KNN)应用

目录

一、k近邻算法

1.1 算法简介

1.2 opencv-k近邻算法

二、cv::ml::KNearest应用

2.1 数据集样本准备

2.2 KNearest应用

2.3 程序编译

2.4 main.cpp全代码


一、k近邻算法

1.1 算法简介

        K近邻算法(K-Nearest Neighbor,KNN)基本原理是:

        在特征空间中,如果一个样本附近的K个最近(即特征空间中最邻近)样本的大多数属于某一个类别,则该样本也属于这个类别。具体来说,给定一个训练数据集,对于新的输入实例,KNN算法会在训练数据集中找到与该实例最邻近的K个实例(即K个邻居)。然后,根据这K个邻居的类别进行投票,将票数最多的类别作为新输入实例的预测类别。

        KNN算法的优点包括:

  1. 简单易理解:KNN算法非常直观和简单,易于理解和实现。
  2. 适用于多分类问题:KNN算法可以很容易地应用于多分类问题。
  3. 适用于非线性数据:KNN算法对于非线性数据具有良好的适应性。
  4. 无需训练:KNN算法属于懒惰学习(lazy learning),不需要训练过程,节省了模型训练时间。

        KNN算法也存在一些缺点:

  1. 需要大量内存:KNN算法需要存储所有训练数据,因此在处理大规模数据集时需要大量内存。
  2. 计算复杂度高:当训练集很大时,KNN算法需要计算测试样本与所有训练样本之间的距离,计算复杂度较高。
  3. 预测时间长:由于需要计算测试样本与所有训练样本的距离,KNN算法的预测时间较长。
  4. 敏感度高:KNN算法对于异常值和噪声数据非常敏感,容易受到局部特征的影响。

        KNN算法的应用实例包括但不限于手写数字识别、电影推荐系统、人脸识别和疾病诊断等。在这些应用中,KNN算法可以通过计算测试样本与训练样本之间的距离,找到最相似的邻居,并根据邻居的类别进行预测或分类。常用的距离度量方法包括欧式距离、曼哈顿距离、闵可夫斯基距离等。

1.2 opencv-k近邻算法

        OpenCV中的K近邻算法(K-Nearest Neighbors, KNN)是一种常用的监督学习算法,主要用于分类和回归问题。该算法基于样本之间的距离来进行分类或回归。

        1)对于分类问题,KNN算法将未知样本与训练集中的样本逐个比较距离,并选择距离最近的K个邻居样本。然后,根据这K个邻居样本的标签进行投票,将未知样本归类为票数最多的标签。

        2)对于回归问题,KNN算法同样将未知样本与训练集中的样本逐个比较距离,并选择距离最近的K个邻居样本。但是,在回归问题中,KNN算法会取这K个邻居样本的平均值作为未知样本的预测值。

        OpenCV中的KNN算法实现包含在ml模块中,函数为cv.ml.KNearest_create()。通过这个函数,你可以创建一个KNN分类器或回归器,并使用训练数据对其进行训练。训练完成后,你可以使用训练好的模型对新的数据进行预测。

k近邻算法是使用的是KNearest类 继承了StatModel类(base类)
class CV_EXPORTS_W KNearest : public StatModel
{
public://类代码
};
StatModel类 方法:训练函数ret = cv.ml_StatModel.train(samples,layout,responses)samples: 训练的样本矩阵layout: 排列方式responses: 标签矩阵返还一个bool类型变量来作为是否完成了模型训练samples 必须为float32类型layout  cv.ml.ROW_SAMPLE 样本按行排列cv.ml.COL_SAMPLE 按列排列responses: 单行或者单列的矩阵 类型为int 或者 float检测函数retval, res = cv.ml_StatModel.predict(samples)flags模型标志res 结果矩阵samples 输入矩阵retval: 第一个值得标签除了使用StatModel提供的通用的预测方法KNearest类也提供了预测方法retval,results,neighborResponses,dist = cv.ml_KNearest.findNearest(samplek)sample: 待预测数据k: 近邻数results: 预测结果neighborResponses: 可以选择输出的每个数据的k个最近邻dist: 输出k个最近邻的距离

        KNN算法的优点包括在线技术(新数据可以直接加入数据集而不必进行重新训练)、理论简单、容易实现、准确性高和对异常值和噪声有较高的容忍度。然而,KNN算法也存在一些缺点,如对于样本容量大的数据集计算量比较大、容易导致维度灾难、样本不平衡时预测偏差比较大,以及k值大小的选择需要依靠经验或交叉验证等。

        在OpenCV中,KNN算法可以用于各种图像处理任务,如图像分类、目标检测和模式识别等。通过调整k值和使用不同的距离度量方法,你可以优化KNN算法的性能以适应你的具体任务。

二、cv::ml::KNearest应用

2.1 数据集样本准备

   本文为了快速验证使用,采用mnist数据集,参考本专栏博文《C/C++开发,opencv-ml库学习,支持向量机(SVM)应用-CSDN博客》下载MNIST 数据集(手写数字识别),并解压。

        同时参考该博文“2.4 SVM(支持向量机)实时识别应用”的章节资料,利用python代码解压t10k-images.idx3-ubyte出图片数据文件。

2.2 KNearest应用

         类似ml模块的其他算法一样,创建了一个 cv::ml::KNearest对象,并设置了训练数据和终止条件。接着,我们调用 train 方法来训练决策树模型。最后,我们使用训练好的模型来预测一个新样本的类别。

	// 4. 设置并训练KNN模型 // 创建KNN模型  cv::Ptr<cv::ml::KNearest> knn = cv::ml::KNearest::create();  // 设置KNN参数 knn->setAlgorithmType(cv::ml::KNearest::BRUTE_FORCE); // 使用暴力搜索  knn->setIsClassifier(true); // 设置为分类器  knn->setDefaultK(3); // 设置K值  // 训练KNN模型  knn->train(trainingData, cv::ml::ROW_SAMPLE, labelsMat);  //同样预测函数调用cv::Mat testResp;float response = knn->predict(testData,testResp); //存储模型,文件名借用了博文的命名,不必在意knn->save("mnist_svm.xml");

        训练及测试过的算法模型,保存输出(.xml),然后调用。PS,训练图片解压读取请参见C/C++开发,opencv-ml库学习,支持向量机(SVM)应用-CSDN博客的“2.4 SVM(支持向量机)实时识别应用”章节。

cv::Ptr<cv::ml::KNearest> kkn = cv::ml::StatModel::load<cv::ml::KNearest>("mnist_svm.xml");//read img 28*28 sizecv::Mat image = cv::imread(fileName, cv::IMREAD_GRAYSCALE);//uchar->float32image.convertTo(image, CV_32F);//image data normalizationimage = image / 255.0;//28*28 -> 1*784image = image.reshape(1, 1);//预测图片float ret = knn->predict(image);std::cout << "predict val = "<< ret << std::endl;
2.3 程序编译

        和讲述支持向量机(SVM)应用的博文编译类似,采用opencv+mingw+makefile方式编译:

#/bin/sh
#win32
CX= g++ -DWIN32 
#linux
#CX= g++ -Dlinux BIN 		:= ./
TARGET      := opencv_ml04.exe
FLAGS		:= -std=c++11 -static
SRCDIR 		:= ./
#INCLUDES
INCLUDEDIR 	:= -I"../../opencv_MinGW/include" -I"./"
#-I"$(SRCDIR)"
staticDir   := ../../opencv_MinGW/x64/mingw/staticlib/
#LIBDIR		:= $(staticDir)/libopencv_world460.a\
#			   $(staticDir)/libade.a \
#			   $(staticDir)/libIlmImf.a \
#			   $(staticDir)/libquirc.a \
#			   $(staticDir)/libzlib.a \
#			   $(wildcard $(staticDir)/liblib*.a) \
#			   -lgdi32 -lComDlg32 -lOleAut32 -lOle32 -luuid 
#opencv_world放弃前,然后是opencv依赖的第三方库,后面的库是MinGW编译工具的库LIBDIR 	    := -L $(staticDir) -lopencv_world460 -lade -lIlmImf -lquirc -lzlib \-llibjpeg-turbo -llibopenjp2 -llibpng -llibprotobuf -llibtiff -llibwebp \-lgdi32 -lComDlg32 -lOleAut32 -lOle32 -luuid 
source		:= $(wildcard $(SRCDIR)/*.cpp) $(TARGET) :$(CX) $(FLAGS) $(INCLUDEDIR) $(source)  -o $(BIN)/$(TARGET) $(LIBDIR)clean:rm  $(BIN)/$(TARGET)

        make编译,make clean 清除可重新编译。

        运行效果,同样数据样本,相比前面博文所述算法训练结果,其准确率有了较大改善,大家可以尝试调整参数验证: 

2.4 main.cpp全代码

        main.cpp源代码,由于是基于前三篇博文支持向量机(SVM)应用、决策树(DTrees)应用、随机森林(RTrees)应用基础上,快速移用实现的,有很多支持向量机(SVM)应用或决策树(DTrees)的痕迹,采用的数据样本也非较合适的,仅仅是为了阐述c++ opencv K近邻算法(KNearest)应用说明。

#include <opencv2/opencv.hpp>  
#include <opencv2/ml/ml.hpp>  
#include <opencv2/imgcodecs.hpp>
#include <iostream>  
#include <vector>  
#include <iostream>
#include <fstream>int intReverse(int num)
{return (num>>24|((num&0xFF0000)>>8)|((num&0xFF00)<<8)|((num&0xFF)<<24));
}std::string intToString(int num)
{char buf[32]={0};itoa(num,buf,10);return std::string(buf);
}cv::Mat read_mnist_image(const std::string fileName) {int magic_number = 0;int number_of_images = 0;int img_rows = 0;int img_cols = 0;cv::Mat DataMat;std::ifstream file(fileName, std::ios::binary);if (file.is_open()){std::cout << "open images file: "<< fileName << std::endl;file.read((char*)&magic_number, sizeof(magic_number));//formatfile.read((char*)&number_of_images, sizeof(number_of_images));//images numberfile.read((char*)&img_rows, sizeof(img_rows));//img rowsfile.read((char*)&img_cols, sizeof(img_cols));//img colsmagic_number = intReverse(magic_number);number_of_images = intReverse(number_of_images);img_rows = intReverse(img_rows);img_cols = intReverse(img_cols);std::cout << "format:" << magic_number<< " img num:" << number_of_images<< " img row:" << img_rows<< " img col:" << img_cols << std::endl;std::cout << "read img data" << std::endl;DataMat = cv::Mat::zeros(number_of_images, img_rows * img_cols, CV_32FC1);unsigned char temp = 0;for (int i = 0; i < number_of_images; i++) {for (int j = 0; j < img_rows * img_cols; j++) {file.read((char*)&temp, sizeof(temp));//svm data is CV_32FC1float pixel_value = float(temp);DataMat.at<float>(i, j) = pixel_value;}}std::cout << "read img data finish!" << std::endl;}file.close();return DataMat;
}cv::Mat read_mnist_label(const std::string fileName) {int magic_number;int number_of_items;cv::Mat LabelMat;std::ifstream file(fileName, std::ios::binary);if (file.is_open()){std::cout << "open label file: "<< fileName << std::endl;file.read((char*)&magic_number, sizeof(magic_number));file.read((char*)&number_of_items, sizeof(number_of_items));magic_number = intReverse(magic_number);number_of_items = intReverse(number_of_items);std::cout << "format:" << magic_number << "  ;label_num:" << number_of_items << std::endl;std::cout << "read Label data" << std::endl;//data type:CV_32SC1,channel:1LabelMat = cv::Mat::zeros(number_of_items, 1, CV_32SC1);for (int i = 0; i < number_of_items; i++) {unsigned char temp = 0;file.read((char*)&temp, sizeof(temp));LabelMat.at<unsigned int>(i, 0) = (unsigned int)temp;}std::cout << "read label data finish!" << std::endl;}file.close();return LabelMat;
}//change path for real paths
std::string trainImgFile = "D:\\workForMy\\OpenCVLib\\opencv_demo\\opencv_ml01\\train-images.idx3-ubyte";
std::string trainLabeFile = "D:\\workForMy\\OpenCVLib\\opencv_demo\\opencv_ml01\\train-labels.idx1-ubyte";
std::string testImgFile = "D:\\workForMy\\OpenCVLib\\opencv_demo\\opencv_ml01\\t10k-images.idx3-ubyte";
std::string testLabeFile = "D:\\workForMy\\OpenCVLib\\opencv_demo\\opencv_ml01\\t10k-labels.idx1-ubyte";void train_SVM()
{//read train images, data type CV_32FC1cv::Mat trainingData = read_mnist_image(trainImgFile);//images data normalizationtrainingData = trainingData/255.0;std::cout << "trainingData.size() = " << trainingData.size() << std::endl;std::cout << "trainingData.type() = " << trainingData.type() << std::endl;  std::cout << "trainingData.rows = " << trainingData.rows << std::endl; std::cout << "trainingData.cols = " << trainingData.cols << std::endl; //read train label, data type CV_32SC1cv::Mat labelsMat = read_mnist_label(trainLabeFile);std::cout << "labelsMat.size() = " << labelsMat.size() << std::endl; std::cout << "labelsMat.type() = " << labelsMat.type() << std::endl;  std::cout << "labelsMat.rows = " << labelsMat.rows << std::endl; std::cout << "labelsMat.cols = " << labelsMat.cols << std::endl; std::cout << "trainingData & labelsMat finish!" << std::endl;  // //create SVM model// cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::create();  // //set svm args,type and KernelTypes// svm->setType(cv::ml::SVM::C_SVC);  // svm->setKernel(cv::ml::SVM::POLY);  // //KernelTypes POLY is need set gamma and degree// svm->setGamma(3.0);// svm->setDegree(2.0);// //Set iteration termination conditions, maxCount is importance// svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::EPS | cv::TermCriteria::COUNT, 1000, 1e-8)); // std::cout << "create SVM object finish!" << std::endl;  // std::cout << "trainingData.rows = " << trainingData.rows << std::endl; // std::cout << "trainingData.cols = " << trainingData.cols << std::endl; // std::cout << "trainingData.type() = " << trainingData.type() << std::endl; // // svm model train // svm->train(trainingData, cv::ml::ROW_SAMPLE, labelsMat);  // std::cout << "SVM training finish!" << std::endl; // // 创建决策树对象  // cv::Ptr<cv::ml::DTrees> dtree = cv::ml::DTrees::create();  // dtree->setMaxDepth(30);          // 设置树的最大深度  // dtree->setCVFolds(0);// dtree->setMinSampleCount(1);   // 设置分裂内部节点所需的最小样本数 // std::cout << "create dtree object finish!" << std::endl;  // // 训练决策树--trainingData训练数据,labelsMat训练标签// cv::Ptr<cv::ml::TrainData> td = cv::ml::TrainData::create(trainingData, cv::ml::ROW_SAMPLE, labelsMat);  // std::cout << "create TrainData object finish!" << std::endl; // if(dtree->train(td))// {// 	std::cout << "dtree training finish!" << std::endl;// }else{// 	std::cout << "dtree training fail!" << std::endl; // }//    // 3. 设置并训练随机森林模型  
//     cv::Ptr<cv::ml::RTrees> rf = cv::ml::RTrees::create();  
//     rf->setMaxDepth(30);                    // 设置决策树的最大深度  
//     rf->setMinSampleCount(2);             // 设置叶子节点上的最小样本数  
//     rf->setTermCriteria(cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 10, 0.1)); // 设置终止条件  
//     rf->train(trainingData, cv::ml::ROW_SAMPLE, labelsMat);  // 4. 设置并训练KNN模型 // 创建KNN模型  cv::Ptr<cv::ml::KNearest> knn = cv::ml::KNearest::create();  // 设置KNN参数 knn->setAlgorithmType(cv::ml::KNearest::BRUTE_FORCE); // 使用暴力搜索  knn->setIsClassifier(true); // 设置为分类器  knn->setDefaultK(3); // 设置K值  // 训练KNN模型  knn->train(trainingData, cv::ml::ROW_SAMPLE, labelsMat);  // svm model test  cv::Mat testData = read_mnist_image(testImgFile);//images data normalizationtestData = testData/255.0;std::cout << "testData.rows = " << testData.rows << std::endl; std::cout << "testData.cols = " << testData.cols << std::endl; std::cout << "testData.type() = " << testData.type() << std::endl; //read test label, data type CV_32SC1cv::Mat testlabel = read_mnist_label(testLabeFile);cv::Mat testResp;// float response = svm->predict(testData,testResp); // float response = dtree->predict(testData,testResp); // float response = rf->predict(testData,testResp); float response = knn->predict(testData,testResp); // std::cout << "response = " << response << std::endl; testResp.convertTo(testResp,CV_32SC1);int map_num = 0;for (int i = 0; i <testResp.rows&&testResp.rows==testlabel.rows; i++){if (testResp.at<int>(i, 0) == testlabel.at<int>(i, 0)){map_num++;}// else{// 	std::cout << "testResp.at<int>(i, 0) " << testResp.at<int>(i, 0) << std::endl;// 	std::cout << "testlabel.at<int>(i, 0) " << testlabel.at<int>(i, 0) << std::endl;// }}float proportion  = float(map_num) / float(testResp.rows);std::cout << "map rate: " << proportion * 100 << "%" << std::endl;std::cout << "SVM testing finish!" << std::endl; //save svm model// svm->save("mnist_svm.xml");// dtree->save("mnist_svm.xml");// rf->save("mnist_svm.xml");knn->save("mnist_svm.xml");
}void prediction(const std::string fileName,cv::Ptr<cv::ml::KNearest> knn)
// void prediction(const std::string fileName,cv::Ptr<cv::ml::DTrees> dtree)
// void prediction(const std::string fileName,cv::Ptr<cv::ml::SVM> svm)
{//read img 28*28 sizecv::Mat image = cv::imread(fileName, cv::IMREAD_GRAYSCALE);//uchar->float32image.convertTo(image, CV_32F);//image data normalizationimage = image / 255.0;//28*28 -> 1*784image = image.reshape(1, 1);//预测图片// float ret = dtree->predict(image);float ret = knn->predict(image);std::cout << "predict val = "<< ret << std::endl;
}std::string imgDir = "D:\\workForMy\\OpenCVLib\\opencv_demo\\opencv_ml01\\t10k-images\\";
std::string ImgFiles[5] = {"image_0.png","image_10.png","image_20.png","image_30.png","image_40.png",};
void predictimgs()
{//load svm model// cv::Ptr<cv::ml::SVM> svm = cv::ml::StatModel::load<cv::ml::SVM>("mnist_svm.xml");//load DTrees model// cv::Ptr<cv::ml::DTrees> dtree = cv::ml::StatModel::load<cv::ml::DTrees>("mnist_svm.xml");// cv::Ptr<cv::ml::RTrees> rf = cv::ml::StatModel::load<cv::ml::RTrees>("mnist_svm.xml");cv::Ptr<cv::ml::KNearest> kkn = cv::ml::StatModel::load<cv::ml::KNearest>("mnist_svm.xml");for (size_t i = 0; i < 5; i++){prediction(imgDir+ImgFiles[i],kkn);}
}int main()  
{  train_SVM();predictimgs();	return 0;  
}

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

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

相关文章

uniapp 微信开发工具上访问正常,真机调试一直跨域报错

微信小程序真机调试时&#xff0c;出现跨域问题&#xff0c;需要同时在后端设置多种允许跨域的设置&#xff1a; // 指定允许其他域名访问 header(Access-Control-Allow-Origin:*); // 响应类型 header(Access-Control-Allow-Methods:GET,POST,OPTION); // 响应头设置 header(…

【实验】根据docker部署nginx并且实现https

环境准备 systemctl stop firewalld setenforce 0 安装docker #安装依赖包 yum -y install yum-utils device-mapper-persistent-data lvm2 #设置阿里云镜像 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #安装最新版…

Unity 编辑器工具 - 资源引用查找器

在Unity项目开发过程中&#xff0c;管理和维护资源之间的引用关系是至关重要的。当然我们项目也是需要这个功能 毕竟项目大了之后查找资源引用还是交给 资源引用查找器 比较好。 功能概述 资源引用查找器允许开发者选择一个目标资源&#xff0c;并在整个项目中查找引用了该资…

记录vue报错问题 in ./node_modules/axios/lib/platform/index.js

今天这个问题困扰了我许久 报错内容如下&#xff1a; 最初一直以为是我没装axios&#xff0c;又重新装了一次&#xff0c;后面才发现是axios版本原因&#xff0c;真的总是被版本的原因困住真的很烦 解决方法如下&#xff1a; 将axios的版本改为1.5.0 1、打开项目的文件夹“…

wireshark的安装使用及相关UDP、TCP、 ARP

初步了解&#xff1a; 进入wireshark后如图&#xff1a; 从图中可以看到很多网络连接在操作的时候我们需要监测哪些 我们可以直接在本地的运行框中输入ipconfig来查看 如图&#xff1a; 从以上图片中我们可以清楚地看到哪些网络连接已经连接的我们只需要按需监测他们即可 但…

JSP与JavaBean

目录 一、JavaBean是什么 二、创建JavaBean 三、在JSP中使用JavaBean 1、按照Java语法直接使用 2、<jsp:useBean>动作 Bean的加载原理 scope属性的不同取值 3、<jsp:setProperty>动作 设置为一个表达式的值或字符序列 通过表单的参数的值来设置Bean的相应…

【C++】STL — List的接口讲解 +详细模拟实现

前言&#xff1a; 本章我们将学习STL中另一个重要的类模板list… list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。list的底层是带头双向循环链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xf…

论文笔记ColdDTA:利用数据增强和基于注意力的特征融合进行药物靶标结合亲和力预测

ColdDTA发表在Computers in Biology and Medicine 的一篇一区文章 突出 • 数据增强和基于注意力的特征融合用于药物靶点结合亲和力预测。 • 与其他方法相比&#xff0c;它在 Davis、KIBA 和 BindingDB 数据集上显示出竞争性能。 • 可视化模型权重可以获得可解释的见解。 …

三种滤波(EKF、UKF、CKF)的对比,含MATLAB源代码

使用MATLAB模拟三维的滤波,包含扩展卡尔曼滤波EKF、无迹卡尔曼滤波UKF、容积卡尔曼滤波CKF。 状态更新和观测更新均为非线性的,模拟一定强度的机动性,可用于卡尔曼滤波方法的对比学习,自己修改成需要的运动模型后,可以用于组合导航(GPS+DVL形式)。 运行结果 真值的三轴…

Unity UGUI Image 点击事件忽略空白像素区域

我们会遇到图片不是方形的不规则图片。这个时候我们希望只有点击到图像内容本身才算点击&#xff0c;点击空白区域则不算点击。而UGUI对图片的处理是整个图片都会算作点击区域&#xff0c;这样不能满足于我们的使用需求了。 首先我们需要把图片本身的Read/Write 选项打开 然后…

Meta Llama 3 使用 Hugging Face 和 PyTorch 优化 CPU 推理

原文地址&#xff1a;meta-llama-3-optimized-cpu-inference-with-hugging-face-and-pytorch 了解在 CPU 上部署 Meta* Llama 3 时如何减少模型延迟 2024 年 4 月 19 日 万众期待的 Meta 第三代 Llama 发布了&#xff0c;我想确保你知道如何以最佳方式部署这个最先进的&…

时间日志格式的统一和定制

返回当前格式的时间没有错误&#xff0c;但是不符合中国人的阅读习惯 解决&#xff1a; 方案一&#xff1a;JsonFormat 解决后端 传到 前端格式问题 依赖&#xff1a; <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jack…

STM32:GPIO输出

文章目录 1、GPIO介绍1.1 GPIO的基本结构1.1 GPIO的位结构 2、 GPIO工作模式3、GPIO标准外设库接口函数3.1 RCC接口函数3.2 GPIO接口函数3.2.1 GPIO的读取函数3.2.1 GPIO的写入函数 4、GPIO的初始化 1、GPIO介绍 GPIO&#xff08;General Purpose Input Output&#xff09;通用…

Python设计模式 - 单例模式

定义 单例模式是一种创建型设计模式&#xff0c; 其主要目的是确保一个类只有一个实例&#xff0c; 并提供一个全局访问点来访问该实例。 结构 应用场景 资源管理&#xff1a;当需要共享某个资源时&#xff0c;例如数据库连接、线程池、日志对象等&#xff0c;可以使用单例模…

【UnityRPG游戏制作】Unity_RPG项目_玩法相关

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;就业…

【算法与数据结构】哈希表

文章目录 引入哈希函数介绍便利店的例子Python3 中的哈希表C 中的哈希表 应用将散列表用于查找防止重复将散列表用作缓存 哈希冲突与解决链地址法开放寻址 总结参考资料写在最后 引入 假设你在一家便利店上班&#xff0c;你不熟悉每种商品的价格&#xff0c;在顾客需要买单是时…

详述DM9161芯片的特性和用法

目录 概述 1. 认识DM9161 2 DM9161的特性 2.1 特性总结 2.2 结构框图 3 功能描述 4 RMII接口 4.1 100Base-TX Operation 4.2 10Base-T Operation 4.3 Auto-Negotiation 4.4 HP Auto-MDIX功能描述 6 DM9161的寄存器 6.1 寄存器列表 6.2 寄存器功能介绍 6.2.1 基本…

ubuntu20中ros与anaconda的python版本冲突问题

系统环境 原本系统是ubuntu20 noetic&#xff0c;python都在/usr/bin中&#xff0c;一共是两个版本的python&#xff0c;一个是python3.8&#xff0c;另一个是python2.7。 问题发现 当安装anaconda后&#xff0c;并且将anaconda的bin目录加入到系统环境中时候&#xff0c;…

Stable Diffusion webUI 配置指南

Stable Diffusion webUI 配置指南 本博客主要介绍部署Stable Diffusion到本地&#xff0c;生成想要的风格图片。 文章目录 Stable Diffusion webUI 配置指南1、配置环境&#xff08;1&#xff09;pip环境[可选]&#xff08;2&#xff09;conda环境[可选] 2、配置Stable Diffu…

Monorepo(单体仓库)与MultiRepo(多仓库): Monorepo 单体仓库开发策略与实践指南

&#x1f31f; 引言 在软件开发的浩瀚宇宙里&#xff0c;选择合适的代码管理方式是构建高效开发环境的关键一步。今天&#xff0c;我们将深入探讨两大策略——Monorepo&#xff08;单体仓库&#xff09;与MultiRepo&#xff08;多仓库&#xff09;&#xff0c;并通过使用现代化…