在Visual Studio上,使用OpenCV实现人脸识别
1. 环境与说明
本文介绍了如何在Visual Studio
上,使用OpenCV
来实现人脸识别的功能
环境说明 :
- 操作系统 :
windows 10 64位
Visual Studio
版本 :Visual Studio Community 2022 (社区版)
OpenCV
版本 :OpenCV-4.8.0 (2023年7月最新版)
实现效果如图所示,识别到的人脸会用红框框出来 :
2. 配置Visual Studio环境
这部分详见我的另一篇博客 : Visual Studio 2022 cmake配置opencv开发环境
最终配置好后,能够在Visual Studio
中正常调用OpenCV
,运行CMake
项目(C++
程序)
3. 实现摄像头预览
这部分要用到VideoCapture
这个类,VideoCapture
既支持从视频文件读取,也支持直接从摄像机等监控器中读取,还可以读取 IP
视频流,要想获取视频需要先创建一个 VideoCapture
对象来打开相机,然后就可以来操作视频帧了。
我们将项目代码修改为如下内容
#include "OpenCVTest.h"
#include "opencv2/opencv.hpp"using namespace std;
using namespace cv;int main()
{VideoCapture capture;//打开相机,这个传入的相机ID为0capture.open(0);if (!capture.isOpened()){cout << "opencv打开摄像头失败!\n" << endl;return -1;}//Mat矩阵,用来存一张图片Mat frame;while (true){//从capture中取数据,将画面输出到frame矩阵里面capture >> frame; if (frame.empty()){cout << "读取摄像头数据失败\n" << endl;}imshow("摄像头", frame); //显示图像if (waitKey(30) == 27) //按下ESC键退出程序{break;}}return 0;
}
运行程序,效果如下所示
4. 转化为灰度图像
接下来我们需要将图片转化为灰度图,为什么要进行灰度化处理呢 ? 主要有以下几个作用,提高人脸识别的准确性和可靠性
- 简化图像处理:灰度化可以将彩色图像转化为黑白图像,使得处理更加简单。彩色图像包含三个通道(红、绿、蓝),而灰度图像只有一个通道,使得处理更加快速和高效。
- 消除颜色信息:人脸识别对于颜色信息并不是非常敏感,而更关注形状和轮廓等特征。因此,通过灰度化处理,可以消除颜色信息对于后续处理的影响。
- 提高处理性能:灰度化处理可以减少计算量,提高处理性能。在人脸识别过程中,对每个像素进行颜色计算会消耗大量计算资源,而灰度化处理只需要对每个像素的亮度进行计算,减少了计算量。
- 突出图像特征:灰度化处理可以突出图像中的边缘和纹理等特征。这些特征对于人脸识别非常关键,可以帮助算法更好地识别人脸。
进行灰度化处理我们需要调用void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );
,这里src
是我们输入的图像,dst
是我们要输出的图像,code
需要传COLOR_BGR2GRAY
,表示将BGR
转化为灰度图。
要注意,在
OpenCV
中,是BGR
排列方式,而不是RGB
排列。
具体完整代码如下
#include "OpenCVTest.h"
#include "opencv2/opencv.hpp"using namespace std;
using namespace cv;int main()
{VideoCapture capture;capture.open(0);if (!capture.isOpened()){cout << "opencv打开摄像头失败!\n" << endl;return -1;}Mat frame; //摄像头彩色图像Mat grayFrame; //摄像头灰度图像while (true){//从capture中取数据,将画面输出到frame矩阵里面capture >> frame; if (frame.empty()){cout << "读取摄像头数据失败!\n" << endl;return -1;}imshow("摄像头", frame); //显示彩色图像//灰度化处理cvtColor(frame, grayFrame, COLOR_BGR2GRAY); //注意 : OpenCV中是BRGimshow("灰度化", grayFrame); //显示灰色图像if (waitKey(30) == 27) //ESC键{break;}}return 0;
}
运行程序,效果如下所示,左边的是彩色画面,右边的是黑白画面
5. 直方图均衡化处理
接着,要进行直方图均衡化处理,为什么要进行这一步操作呢 ? 主要有以下几个作用,提高人脸识别的准确性和可靠性
- 提高对比度:直方图均衡化通过重新分布图像像素的灰度级,将原始图像中的灰度级分布变得更加均匀。这样做可以增强图像的对比度,使得人脸的特征更加清晰可见。
- 消除光照变化:人脸识别中的一个挑战是光照变化对人脸图像的影响。直方图均衡化可以消除光照变化,使得人脸图像在不同光照条件下具有一致的亮度和对比度。
- 提高图像质量:直方图均衡化可以改善图像的质量,去除图像中的噪声和伪影。这对于后续的人脸特征提取和匹配非常重要,可以提高人脸识别的准确性和鲁棒性。
- 增强细节信息:直方图均衡化可以增强图像的细节信息,使得人脸图像中的纹理和特征更加明显。这对于人脸识别算法的性能至关重要,可以提高人脸识别的准确率和鲁棒性。
直方图均衡化处理需要调用void equalizeHist( InputArray src, OutputArray dst);
,src
是输入的图像,需要是单通道的灰度图,dst
是我们输出的图像。
具体完整代码如下
#include "OpenCVTest.h"
#include "opencv2/opencv.hpp"using namespace std;
using namespace cv;int main()
{VideoCapture capture;capture.open(0);if (!capture.isOpened()){cout << "opencv打开摄像头失败!\n" << endl;return -1;}Mat frame; //摄像头彩色图像Mat grayFrame; //摄像头灰度图像Mat equalizeFrame; //直方图while (true){capture >> frame; //从capture中取数据,将画面输出到frame矩阵里面if (frame.empty()){cout << "读取摄像头数据失败!\n" << endl;return -1;}imshow("摄像头", frame); //显示图像//灰度化处理cvtColor(frame, grayFrame, COLOR_BGR2GRAY); //注意 : OpenCV中是BRGimshow("灰度化", grayFrame); //显示图像//直方图均衡化,用来增强图像对比度,从而让轮廓更加明显equalizeHist(grayFrame, equalizeFrame);imshow("直方图", equalizeFrame);if (waitKey(30) == 27) //ESC键{break;}}return 0;
}
运行程序,效果如下所示,最右边的是经过直方图均衡化处理后的
6. 加载级联分类器
级联分类器CascadeClassifier
的作用是进行目标检测。它是一种基于机器学习的分类器,通过训练多个弱分类器来识别目标物体。这些弱分类器层层级联,形成一个级联分类器,能够快速准确地检测出图像中的目标物体。
级联分类器通常用于人脸检测,可以通过训练来识别人的面部特征,如眼睛、鼻子、嘴巴等,从而识别人脸并定位人脸的位置。在OpenCV
中,CascadeClassifier
类提供了一个方便的接口,可以加载预训练的级联分类器,并进行目标检测操作。
首先我们要去加载级联分类器文件(xml
文件),这些文件位于D:\Developer\opencv4.8.0\opencv\build\etc
目录下,这里我们用的是haarcascade
这种基于梯度提升决策树的分类器 (另一种lbpcascade
是一种基于局部二值模式LBP
的分类器)
在haarcascade
目录下,我们可以看到haarcascade_frontalface_alt.xml
这个文件,就是我们需要的,用于人脸识别的级联分类器了。
所以,我们加载级联分类器的时候,去指定这个路径D:\Developer\opencv4.8.0\opencv\build\etc\haarcascades\haarcascade_frontalface_alt.xml
,需要注意的是,放到代码里,这里的要将\
改为/
(或者改为\\
也行)。如果不改,那么路径不对,级联分类器会读取出错。
具体代码如下
int main()
{CascadeClassifier face_CascadeClassifier;if (!face_CascadeClassifier.load("D:/Developer/opencv4.8.0/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml")) {cout << "级联分类器加载失败!\n" << endl;return -1;}//这里省略了原本其他的代码 ...
}
7. 进行人脸检测
接下来我们就要进行人脸检测了,人脸检测需要调用detectMultiScale
方法,第一个参数 image
需要传入我们刚才处理后的直方图,第二个参数objects
会返回所有检测出来的人脸的坐标。
void detectMultiScale( InputArray image,CV_OUT std::vector<Rect>& objects,double scaleFactor = 1.1,int minNeighbors = 3, int flags = 0,Size minSize = Size(),Size maxSize = Size() );
还有一个rectangle
方法,用来在得到人脸坐标之后,进行画框。第一个参数img
代表要在哪个图像上画框,第二个参数rec
表示框的坐标,第三个参数color
表示画框的颜色。
void rectangle(InputOutputArray img, Rect rec,const Scalar& color, int thickness = 1,int lineType = LINE_8, int shift = 0);
主要代码如下所示
std::vector<Rect> faces;
face_CascadeClassifier.detectMultiScale(grayFrame, faces); //检测人脸for (size_t i = 0; i < faces.size(); i++)
{rectangle(frame,faces[i],Scalar(0,0,255)); //在人脸的位置画红色的框
}
来看一下完整代码
#include "OpenCVTest.h"
#include "opencv2/opencv.hpp"using namespace std;
using namespace cv;int main()
{//加载级联分类器CascadeClassifier face_CascadeClassifier;if (!face_CascadeClassifier.load("D:/Developer/opencv4.8.0/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml")) {cout << "级联分类器加载失败!\n" << endl;return -1;}VideoCapture capture;capture.open(0);if (!capture.isOpened()){cout << "opencv打开摄像头失败!\n" << endl;return -1;}Mat frame; //摄像头彩色图像Mat grayFrame; //摄像头灰度图像Mat equalizeFrame; //直方图while (true){capture >> frame; //从capture中取数据,将画面输出到frame矩阵里面if (frame.empty()){cout << "读取摄像头数据失败!\n" << endl;}//imshow("摄像头", frame); //显示图像//灰度化处理cvtColor(frame, grayFrame, COLOR_BGR2GRAY); //注意 : OpenCV中是BRG//imshow("灰度化", grayFrame); //显示图像//直方图均衡化,用来增强图像对比度,从而让轮廓更加明显equalizeHist(grayFrame, equalizeFrame);//imshow("直方图", equalizeFrame);std::vector<Rect> faces;face_CascadeClassifier.detectMultiScale(grayFrame, faces); //检测人脸for (size_t i = 0; i < faces.size(); i++){rectangle(frame,faces[i],Scalar(0,0,255));}imshow("摄像头", frame); //显示图像if (waitKey(30) == 27) //ESC键{break;}}return 0;
}
运行程序,来看一下效果
可以看到,人脸已经检测出来了,并对人脸进行了画框。但是可以画面非常的卡顿,因为人脸检测是非常耗时的,可能需要500毫秒甚至1-2秒时间,这里每一帧都去检测人脸,导致了异常卡顿。所以这种方式只适合用来检测静态图像,并不适合用作实时的摄像头人脸跟踪检测。
8. 实现实时人脸跟踪检测
8.1 OpenCV Android Demo
那我们需要来怎么做呢 ? 其实我们可以来看一下官方的示例,我们要去下载官方的Android包,里面有Android的官方示例。
8.2 DetectionBasedTracker_jni.cpp
我们下载解压后,可以在OpenCV-android-sdk\samples\face-detection\jni
目录下找到DetectionBasedTracker_jni.cpp
这个文件
在里面的nativeCreateObject
方法里,我们可以发现其调用了这几句代码
8.3 CascadeDetectorAdapter
CascadeDetectorAdapter
是一个适配器类,用于将CascadeClassifier
与Detector
接口适配起来,从而用于检测人脸。
再来看一下CascadeDetectorAdapter
这个类,里面的detect
方法就是用来检测人脸的
8.4 DetectorAgregator
然后来看一下第三行代码中的DetectorAgregator
,这里面有tracker = makePtr<DetectionBasedTracker>(mainDetector, trackingDetector, DetectorParams);
这行代码是我们需要的,用来传入mainDetector
和trackingDetector
,生成一个tracker
对象。
8.5 开始重新编写代码
这里我们将原来写的人脸检测的代码删除了,代码恢复到了刚配置好OpenCV的初始状态,然后将CascadeDetectorAdapter
这个类的代码复制到我们的项目中
class CascadeDetectorAdapter: public DetectionBasedTracker::IDetector
{
public:CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector):IDetector(),Detector(detector){CV_Assert(detector);}void detect(const cv::Mat &Image, std::vector<cv::Rect> &objects){Detector->detectMultiScale(Image, objects, scaleFactor, minNeighbours, 0, minObjSize, maxObjSize);}virtual ~CascadeDetectorAdapter(){}private:CascadeDetectorAdapter();cv::Ptr<cv::CascadeClassifier> Detector;
};
声明 tracker
这个对象。
cv::Ptr<DetectionBasedTracker> tracker;
然后创建tracker
,并调用run()
方法,会启动一个异步线程,后面的人脸检测会在这个异步线程进行检测了。
string stdFileName = "D:/Developer/opencv4.8.0/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml";
//创建一个主检测适配器
cv::Ptr<CascadeDetectorAdapter> mainDetector = makePtr<CascadeDetectorAdapter>(makePtr<CascadeClassifier>(stdFileName));
//创建一个跟踪检测适配器
cv::Ptr<CascadeDetectorAdapter> trackingDetector = makePtr<CascadeDetectorAdapter>(makePtr<CascadeClassifier>(stdFileName));
//创建跟踪器
DetectionBasedTracker::Parameters DetectorParams;
tracker = makePtr<DetectionBasedTracker>(mainDetector, trackingDetector, DetectorParams);
tracker->run();
然后在人脸检测的使用调用tracker->process(grayFrame);
进行人脸检测,并调用tracker->getObjects(faces);
获得识别出来的人脸。
tracker->process(grayFrame);
tracker->getObjects(faces);
核心代码就是如上所示,接下来我们再来看一下完整的代码
#include "OpenCVTest.h"
#include "opencv2/opencv.hpp"using namespace std;
using namespace cv;class CascadeDetectorAdapter : public DetectionBasedTracker::IDetector
{
public:CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector) :IDetector(),Detector(detector){CV_Assert(detector);}void detect(const cv::Mat& Image, std::vector<cv::Rect>& objects){Detector->detectMultiScale(Image, objects, scaleFactor, minNeighbours, 0, minObjSize, maxObjSize);}virtual ~CascadeDetectorAdapter(){}private:CascadeDetectorAdapter();cv::Ptr<cv::CascadeClassifier> Detector;
};cv::Ptr<DetectionBasedTracker> tracker;int main()
{string stdFileName = "D:/Developer/opencv4.8.0/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml";//创建一个主检测适配器cv::Ptr<CascadeDetectorAdapter> mainDetector = makePtr<CascadeDetectorAdapter>(makePtr<CascadeClassifier>(stdFileName));//创建一个跟踪检测适配器cv::Ptr<CascadeDetectorAdapter> trackingDetector = makePtr<CascadeDetectorAdapter>(makePtr<CascadeClassifier>(stdFileName));//创建跟踪器DetectionBasedTracker::Parameters DetectorParams;tracker = makePtr<DetectionBasedTracker>(mainDetector, trackingDetector, DetectorParams);tracker->run();VideoCapture capture;capture.open(0);if (!capture.isOpened()){cout << "opencv打开摄像头失败!\n" << endl;return -1;}Mat frame; //摄像头彩色图像Mat grayFrame; //摄像头灰度图像Mat equalizeFrame; //直方图while (true){capture >> frame; //从capture中取数据,将画面输出到frame矩阵里面if (frame.empty()){cout << "读取摄像头数据失败!\n" << endl;return -1;}//imshow("摄像头", frame); //显示图像//灰度化处理cvtColor(frame, grayFrame, COLOR_BGR2GRAY); //注意 : OpenCV中是BRG//imshow("灰度化", grayFrame); //显示图像//直方图均衡化,用来增强图像对比度,从而让轮廓更加明显equalizeHist(grayFrame, equalizeFrame);//imshow("直方图", equalizeFrame);std::vector<Rect> faces;tracker->process(grayFrame);tracker->getObjects(faces);for (size_t i = 0; i < faces.size(); i++){rectangle(frame, faces[i], Scalar(0, 0, 255));}imshow("摄像头", frame); //显示图像if (waitKey(30) == 27) //ESC键{break;}}tracker->stop();return 0;
}
8.6 运行效果
运行程序,我们就可以看到本文开头给出的效果了
至此,我们就使用OpenCV
完成实时人脸跟踪识别了。
9. 本文源码下载
使用OpenCV实现人脸识别示例Demo
相关文章:

在Visual Studio上,使用OpenCV实现人脸识别
1. 环境与说明 本文介绍了如何在Visual Studio上,使用OpenCV来实现人脸识别的功能 环境说明 : 操作系统 : windows 10 64位Visual Studio版本 : Visual Studio Community 2022 (社区版)OpenCV版本 : OpenCV-4.8.0 (2023年7月最新版) 实现效果如图所示࿰…...

搭建openGauss 5.0 一主一从复制集群
openGauss是一款支持SQL2003标准语法,支持主备部署的高可用关系型国产数据库。 多种存储模式支持复合业务场景,新引入提供原地更新存储引擎。NUMA化数据结构支持高性能。Paxos一致性日志复制协议,主备模式,CRC校验支持高可用。支…...

Docker碎碎念
docker和虚拟机的区别 虚拟机(VM)是通过在物理硬件上运行一个完整的操作系统来实现的。 每个虚拟机都有自己的内核、设备驱动程序和用户空间,它们是相互独立且完全隔离的。 虚拟机可以在不同的物理服务器之间迁移,因为它们是以整…...
【C++】extern
目录 1. 变量声明和定义的关系 2. 默认状态下,const对象仅在文件内有效 3. 链接指示:extern "C" 3.1 声明一个非C的函数 3.2 链接指示与头文件 3.3 指向extern "C"函数的指针 3.4 链接指示对整个声明都有效 3.5 导出C函数到…...

2023全网Mysql 合集(25w字)附课程 从安装到高级,实战
mysql学习 1.安装mysql 安装教程 2.mysql的详细学习教程 mysql的详细教程 3.mysql 的高级优化 MySQL高级篇(SQL优化、索引优化、锁机制、主从复制) 4.MySQL 面试 MySQL数据库面试题总结 二.mysql实战 一、创建数据表并插入数据 1、学生表 Stud…...

张俊林:由ChatGPT反思大语言模型(LLM)的技术精要
转自:https://mp.weixin.qq.com/s/eMrv15yOO0oYQ-o-wiuSyw 导读:ChatGPT出现后惊喜或惊醒了很多人。惊喜是因为没想到大型语言模型(LLM,Large Language Model)效果能好成这样;惊醒是顿悟到我们对LLM的认知及发展理念&a…...
单机编排docker compose
Docker之旅(8)-单机编排docker compose 当在宿主机启动较多的容器时候,如果都是手动操作会觉得比较麻烦而且容易出错, 并且每个容器之间也会有先后启动的顺序依赖等。这个时候推荐使用 docker 单机 编排工具 docker-compose,docker-compose …...

C++ 面向对象三大特性——多态
✅<1>主页:我的代码爱吃辣 📃<2>知识讲解:C 继承 ☂️<3>开发环境:Visual Studio 2022 💬<4>前言:面向对象三大特性的,封装,继承,多态ÿ…...
相同数字的积木游戏
题目描述 题目描述 小华和小薇一起通过玩积木游戏学习数学。 他们有很多积木,每个积木块上都有一个数字,积木块上的数字可能相同。 小华随机拿一些积木挨着排成一排,请小薇找到这排积木中数字相同目所处位置最远的2块积木块,计算…...

安防监控视频云存储EasyCVR平台H.265转码功能更新:新增分辨率配置
安防视频集中存储EasyCVR视频监控综合管理平台可以根据不同的场景需求,让平台在内网、专网、VPN、广域网、互联网等各种环境下进行音视频的采集、接入与多端分发。在视频能力上,视频云存储平台EasyCVR可实现视频实时直播、云端录像、视频云存储、视频存储…...

图数据库_Neo4j学习cypher语言_常用函数_关系函数_字符串函数_聚合函数_数据库备份_数据库恢复---Neo4j图数据库工作笔记0008
然后再来看一些常用函数,和字符串函数,这里举个例子,然后其他的 类似 可以看到substring字符串截取函数 可以看到截取成功 聚合函数 这里用了一个count(n) 统计函数,可以看到效果 关系函数,我们用过就是id(r) 可以取出对应的r的id来这样.....
LeetCode150道面试经典题-- 加一(简单)
1.题目 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外,这个整数不会以零开头。 2.示例 示例 1: 输入&am…...

Centos7 配置Docker镜像加速器
docker实战(一):centos7 yum安装docker docker实战(二):基础命令篇 docker实战(三):docker网络模式(超详细) docker实战(四):docker架构原理 docker实战(五):docker镜像及仓库配置 docker实战(六):docker 网络及数据卷设置 docker实战(七):docker 性质及版本选择 认知升…...
微信小程序中pdf的上传、下载及excel导出
微信小程序中pdf的上传、下载及excel导出 pdf上传上传1:上传2: pdf下载导出excel pdf上传 上传两种方法: 上传1: 1.用vant weapp组件: //pdf上传--vant weapp组件 <view class"content"><van-u…...

Python_11 类的方法
一、查缺补漏 1. 实例方法必须用类实例化对象()来调用,用类来调用时会执行,但是self中不是实例化类地址而是传的字符串 二、类中的方法 1. 实例方法 1. 定义在类里面的普通方法(函数) 2. 第一个参数必须是类实例,在方法调用的时候会自动…...
CentOS系统环境搭建(一)——Centos7更新
Centos7更新 更新 yum(包括centos内核) yum update执行后,系统将更新到centos 7.9。 从这一篇文章开始开始,我将开始在centos系统环境搭建🔗https://blog.csdn.net/weixin_43982359/category_12411496.html中开始对C…...

Mariadb高可用MHA
目录 前言 一、概述 (一)、概念 (二)、组成 (三)、特点 (四)、工作原理 二、案例 (一)、构建MHA 1.所有节点ssh免密登录 2、MySQL主从复制 &#x…...

SASS 学习笔记 II
SASS 学习笔记 II 上篇笔记,SASS 学习笔记 中包含: 配置 变量 嵌套 这里加一个扩展,嵌套中有一个 & 的用法,使用 & 可以指代当前 block 中的 selector,后面可以追加其他的选择器。如当前的 scope 是 form&a…...

提高 Snowflake 工作效率的 6 大工具
推荐:使用 NSDT场景编辑器 助你快速搭建可二次编辑的3D应用场景 Snowflake 彻底改变了企业存储、处理和分析数据的方式,提供了无与伦比的灵活性、可扩展性和性能。但是,与任何强大的技术一样,要真正利用其潜力,必须拥有…...
选项方式读取配置IOption、IOptionSnapshot、IOpstionMonitor的区别
IOption, IOptionsSnapshot, 和 IOptionsMonitor 都是 ASP.NET Core 中用于访问配置选项的接口。它们在不同的场景下用于获取配置选项值,并具有不同的生命周期和行为。 IOption: IOption 是一个泛型接口,表示一个配置选项的包装器。它通常在应用程序启动时被解析并注入到需…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...