OpenCV 入门(五) —— 人脸识别模型训练与 Windows 下的人脸识别

news2024/11/24 16:23:57

OpenCV 入门系列:

OpenCV 入门(一)—— OpenCV 基础
OpenCV 入门(二)—— 车牌定位
OpenCV 入门(三)—— 车牌筛选
OpenCV 入门(四)—— 车牌号识别
OpenCV 入门(五)—— 人脸识别模型训练与 Windows 下的人脸识别
OpenCV 入门(六)—— Android 下的人脸识别
OpenCV 入门(七)—— 身份证识别

本文主要内容:

  1. 如何训练 OpenCV 的人脸识别模型
  2. 如何在 Windows 下利用 OpenCV 进行人脸识别

1、概述

人脸识别需要人脸模型(特征集合)的支持,人脸定位的速度与准确度取决于模型。

OpenCV 提供了已经训练好的模型,无论是 Windows 版本还是 Android 版本的 SDK,都在 etc 目录下提供了两种级联分类器模型:

2024-3-31.OpenCV两种级联分类器模型

“Haarcascades” 和 “Lbpcascades” 都是级联分类器模型,用于目标检测和识别,特别是在人脸检测领域中常被使用:

  • Haarcascades 基于 Haar-like 特征(哈尔特征)的级联分类器。Haar-like 特征是一种基于像素差值的特征描述方法,通过计算图像中不同区域的像素值之和的差异,来捕捉图像中的纹理和形状信息。Haarcascades 模型使用了这些特征来构建级联分类器,以在图像中快速检测人脸或其他目标
  • Lbpcascades 使用的是局部二值模式(Local Binary Patterns,LBP)特征的级联分类器。LBP 特征是一种描述图像纹理的方法,通过比较像素点与其邻域像素的灰度值,将其转化为二进制编码。Lbpcascades 模型利用这些二进制编码来构建级联分类器,用于目标检测和识别,例如人脸检测

两个文件夹内都提供了多种模型用以识别物体,比如 lbpcascades 文件夹下的 lbpcascade_frontalface.xml 可以用于识别人脸,lbpcascade_frontalcatface.xml 用于识别猫脸:

2024-3-28.OpenCV提供的人脸特征集合文件

Windows 版本的 SDK 提供了文档与演示代码,在 opencv\sources\doc\tutorials 目录下,比如 objdetect 就是介绍物体识别的。比如 cascade_classifier.markdown 介绍级联分类器,traincascade.markdown 介绍如何训练模型。当然这些文档都是英文的,如果想查看中文文档,可以去 OpenCV 的中国 Wiki 论坛提供的中文文档,比如级联分类器训练。此外演示代码在 opencv\sources\samples\ 目录下,Android 相关的演示在 android 目录中。

除了使用 OpenCV 提供的级联分类器模型,我们也可以使用 OpenCV 提供的工具自己训练模型,具体的操作方法会在下一节介绍。

编码时 Windows 和 Android SDK 使用的都是 4.1.0 版本。

2、人脸模型训练

OpenCV 识别事务实际上就是对事物进行分类。给 OpenCV 各种样本去学习,使得 OpenCV 学习区分不同类别的事物。以人脸为例,给 OpenCV 的正样本全都是各种人脸,负样本全是与人脸无关的事物,那么 OpenCV 就能识别出什么人脸,什么不是。因此供 OpenCV 学习的样本越多越好。

OpenCV 提供的模型可以识别所有人脸,假如现在有个需求,就是只识别某一个人脸,其他的不识别,该如何实现呢?

这就需要自己训练模型了。假如要求只识别你的人脸,那么在采集图像时,保证摄像头内只有你的脸,通过 OpenCV 识别到人脸,然后将人脸部分转为 24 * 24 的灰度图保存到指定的目录内。用目录内的这些小图片通过 OpenCV 提供的工具进行训练,就可以训练出只识别你的脸的模型。

说到 OpenCV 的训练工具,这里要特别说明一下。我们写 Demo 用的是 OpenCV 的 4.1.0 版本,但是在该版本中,训练工具被移除了。在 3.4.X 版本中,这个工具是存在的(如 3.4.6 或 3.4.16 等版本都行):

2024-4-24.OpenCV训练工具

因此我们需要再下载一个包含训练工具的 OpenCV 版本,然后在 opencv\build\x64\vc15\bin 目录下找到 opencv_createsamples.exe 和 opencv_traincascade.exe 工具,可以将目录添加到环境变量中。

稍微提一下为什么 OpenCV 4.X 版本中移除了训练工具。早期的 OpenCV 提供了 C 和 C++ 两种风格的 API。比如 C 风格的 CvMat、CvVideoCapture,而 C++ 风格 API 对应的就是 Mat、VideoCapture。

从 4.X 版本开始,OpenCV 移除了 C 风格的 API,而训练工具是用 C 写的,因此在源码 /opencv410/sources/app 目录下的 CMakeLists.txt 文件中,你能看到生成两个训练工具的代码被注释掉了:

2024-4-24.OpenCV4.X版本没有训练工具的原因

即便打开注释也无法编译出这两个训练工具,因为 C 的源码已经被移除了,所以才需要再下载一个带有训练工具的 3.4.X 版本,这也是 OpenCV 官方给出的解决方案。

2.1 训练步骤

训练模型需要正样本和负样本:

  • 正样本就是与目标模型相关性强的。比如训练只识别你的人脸的模型,那么前面收集的人脸灰度图就是正样本
  • 负样本就是与目标模型相关性弱的,甚至没有相关性的。比如训练人脸识别模型,那么负样本就可以是风景图等等

我们将正样本存入 pos 目录,将负样本存入 neg 目录,然后再创建正样本和负样本的描述文件 positive.txt 和 neg.txt:

2024-3-30.OpenCV训练库文件路径

样本描述文件格式为文件名、人脸数量、每个人脸的起始坐标与宽高范围:

2 个人脸分别为 (100,200) 处为左上角,宽高为 50x50 的范围和 (50,30) 处为左上角,宽高为 25x25 的范围
pos/1.jpg 2 100 200 50 50   50 30 25 25

按照上述格式,我们的正样本可以写为:

pos/0.jpg 1 0 0 24 24
pos/1.jpg 1 0 0 24 24
pos/2.jpg 1 0 0 24 24
pos/3.jpg 1 0 0 24 24
pos/4.jpg 1 0 0 24 24
pos/5.jpg 1 0 0 24 24
pos/6.jpg 1 0 0 24 24
中间省略...
pos/61.jpg 1 0 0 24 24

负样本也是类似的操作。当然需要注意正负样本的比例最好是 1:3,比如正样本有 100 个,负样本最好就是 300 个。

接下来就使用 OpenCV 提供的工具训练模型:

  • 首先运行 opencv_createsamples 命令创建正样本的向量文件:

    # -info: 正样本描述文件
    # -vec : 输出的正样本向量
    # -num : 正样本数量
    # -w -h: 输出样本的大小
    C:\Users\Desktop\train>opencv_createsamples -info positive.txt -vec pos.vec -num 61 -w 24 -h 24
    

    如果运行成功则会如上图所示在当前目录下生成 pos.vec 文件,log 会输出:

    Create training samples from images collection...
    Done. Created 61 samples
    

    如果因为文件路径不匹配,则运行会报错:

    Create training samples from images collection...
    Unable to open image: pos/pos/1.jpg
    OpenCV: terminate handler is called! The last OpenCV error is:
    OpenCV(3.4.16) Error: Assertion failed (0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows) in cv::Mat::Mat, file C:\build\3_4_winpack-build-win64-vc15\opencv\modules\core\src\matrix.cpp, line 751
    
  • 然后运行 opencv_traincascade 进行训练:

    # -data : 需要手动创建,训练的模型作为结果会输出到这个目录
    # -vec  : 正样本	
    # -bg	  : 负样本
    # -numPos :每级分类器训练时所用到的正样本数目
    # -numNeg :每级分类器训练时所用到的负样本数目,可以大于 -bg 数目
    # -numStages:训练分类器的级数,如果层数多,分类器的误差就更小,但是检测速度慢。(15-20)
    # -featureType: 采用 LBP 算法
    # -w -h:负样本的宽高可以设置的随意些,只要起始点 + 宽高不超过图片像素范围即可
    C:\Users\Desktop\train>opencv_traincascade -data data -vec pos.vec -bg neg.txt -numPos 61 -numNeg 300 -numStages 15 -featureType LBP -w 24 -h 24
    

    如果你没有手动创建 data 目录,运行上述命令会报错说无法打开 data/params.xml 文件:

    ===== TRAINING 0-stage =====
    <BEGIN
    POS count : consumed   61 : 61
    NEG count : acceptanceRatio    300 : 1
    Precalculation time: 0.026
    +----+---------+---------+
    |  N |    HR   |    FA   |
    +----+---------+---------+
    |   1|        1|        0|
    +----+---------+---------+
    END>
    Parameters can not be written, because file data/params.xml can not be opened.
    

    创建 data 后再次运行可能会有如下结果之一:

    # 1.训练成功
    Training until now has taken 0 days 0 hours 0 minutes 10 seconds.
    
    # 2.可以认为该训练阶段是成功的,达到了所需的叶子误报率,并且分支训练已经终止(样本太少,模型质量不行)
    Required leaf false alarm rate achieved. Branch training terminated.
    
    # 3.错误
    Bad argument < Can not get new positive sample. The most possible reason is insufficient count of samples in given vec-file.
    

训练成功后会在 data 目录下得到如下文件:

2024-3-30.OpenCV训练库结果

cascade.xml 就是我们训练出的库文件,将其拷贝到手机中,修改代码,用 cascade.xml 替代 OpenCV 提供的 lbpcascade_frontalface.xml:

		// 初始化 OpenCV
        val path = File(
            Environment.getExternalStorageDirectory(),
            /*"lbpcascade_frontalface.xml"*/
            "cascade.xml"
        ).absolutePath
        mOpenCVJNI.init(path)

使用 cascade.xml 模型去做人脸识别时,就只会识别训练样本中的人脸,而不会像 OpenCV 提供的 lbpcascade_frontalface.xml 识别所有人脸,这种识别特定人脸的需求与我们上班打卡的机器原理是类似的。

这里简单说下训练样本数量的选取标准。

minHitRate 是分类器的每一级希望得到的最小检测率。当设置为 0.995 时如果正训练样本个数为 100 个,那么其中的 0.5 个就很可能不被检测,第二次选择的时候必须多选择后面的 5 个,按照这种规律我们为后面的每级多增加 numPos*minHitRate 个正样本。

实际准备的正样本数量应该(读入 vec 的正样本数) >= numPos + (numStage - 1) * numPos * (1 - minHitRate)

按照此公式计算: x+14*x*0.005 = 1.07*x,也就是正样本数量要大于等于 1.07*x 而我们正样本是 100,所以 x = 93.45,但是此处传 100 也可以。

因为实际的检测率会比 minHitRate 高,所以在设置 numPos 时可以将其设置的稍微再大些,最终的目的是要尽量让所有的正样本都参与到训练中。但是,过大就会出错。

2.2 算法简介

LBP(Local Binary Patterns,局部二值模式)是一种用于纹理分析和模式识别的图像特征描述算法。它于 1994 年由 Ojala 等人提出,并被广泛应用于人脸识别、纹理分类、物体检测和图像检索等领域。

LBP 算法的基本思想是对图像中的每个像素点,根据其周围像素的灰度值进行编码,形成一个局部的二值模式。该编码方法具有旋转不变性和灰度不变性的特点,使得 LBP 特征适用于处理灰度图像。

LBP 算法的步骤如下:

  1. 对于图像中的每个像素点,选择一个固定大小的邻域窗口(通常为 3 × 3 或 5 × 5 的正方形)。

  2. 将邻域窗口中心像素的灰度值与邻域窗口中的其他像素逐一比较,若中心像素的灰度值大于或等于相邻像素的灰度值,则该像素点的位置被标记为 1,否则标记为 0。

  3. 将邻域窗口中的 8 个二值编码按顺时针或逆时针顺序排列,形成一个 8 位二进制数,即得到该像素点的 LBP 编码。

  4. 遍历图像中的所有像素点,重复步骤 2 和步骤 3,得到整幅图像的 LBP 编码图像。

  5. 统计 LBP 编码图像中不同 LBP 模式的出现频率,作为图像的 LBP 特征向量。

LBP 算法的主要优点是计算简单、特征表达能力强、对光照变化具有一定的不变性。然而,它也有一些不足之处,例如对噪声和旋转变化敏感。

我们要清楚,人工智能都是基于大数据的。用上万张图片训练出模型用于物体识别。

3、Windows 人脸识别

这一节现在 Windows 上实现人脸识别,因为 Windows 上查看中间结果(灰度图、直方图等等)比较方便。我们在 Visual Studio 中新建项目,驱动电脑的摄像头进行人脸识别。

3.1 代码实现

实现过程大致可分为三步:

  1. 加载 OpenCV 提供的级联分类器以具备人脸识别能力
  2. 打开摄像头
  3. 对摄像头采集到的数据进行灰度化、均衡化处理后进行人脸识别,在识别出人脸的位置画一个矩形

代码如下:

void detect() {
	// 1.加载级联分类器
	if (!face_CascadeClassifier.load("G:/Tools/OpenCV/build/etc/haarcascades/haarcascade_frontalface_alt.xml")) {
		cout << "级联分类器加载失败!" << endl;
	}

	// 2.开启摄像头进行录制
	VideoCapture capture;
	capture.open(0);
	if (!capture.isOpened())
	{
		cout << "OpenCV 打开摄像头失败!\n" << endl;
		return;
	}

	// 3.处理采集到的图像
	Mat frame; // 摄像头彩色图像
	Mat gray; // 摄像头灰度图像
	while (true)
	{
		// 采集到的图像存入 frame
		capture >> frame;
		if (frame.empty()) {
			cout << "OpenCV 读取摄像头图像失败!" << endl;
			return;
		}

		// 灰度化处理,注意 OpenCV 颜色排序为 BGR
		cvtColor(frame, gray, COLOR_BGR2GRAY);

		// 直方图均衡化,增强对比度
		equalizeHist(gray, gray);

		// 一张图片可能包含多张人脸,因此保存结果的是一个集合
		vector<Rect> faces;

        // 对灰度图进行人脸识别,识别结果保存在 faces 集合中
		face_CascadeClassifier.detectMultiScale(gray, faces);

		for each (Rect face in faces)
		{
			// 在 frame 这张图片的 face 上画一个 BGR 颜色为 (0, 0, 255) 即红色的矩形
			rectangle(frame, face, Scalar(0, 0, 255));
			// 这种方式来检测相机实时人脸图像非常卡顿!只适合静态图像的检测
		}
		// 显示图像
		imshow("摄像头", frame);
		// wait 30ms,如果按 Esc 键就退出
		if (waitKey(30) == 27)
		{
			break;
		}
	}
}

人脸识别不需要图片的颜色,正相反,图片的颜色对于识别是一个干扰项,因此在识别之前通常要进行降噪处理,将图片处理成灰度图。

运行起来会发现虽然确实可以识别出人脸,在人脸位置画一个红色矩形,但是图像非常卡顿。这是因为不论是 OpenCV 还是 TensorFlow,检测人脸都是很耗时的,检测一次大概需要 1 ~ 2 秒的时间。因此我们不能向上面这样,对每一帧视频图片都进行检测,而是先检测到人脸,后续采用人脸跟踪。

下面对上述代码进行改造。

3.2 代码优化

上面提到,优化视频画面卡顿的方法是检测第一帧,检测到后,对后续的帧进行人脸跟踪。那么在 OpenCV 中,人脸检测的任务交给主检测适配器,人脸跟踪的任务交给跟踪检测适配器。这两种适配器必须是 DetectionBasedTracker::IDetector 的子类。我们直接使用 OpenCV 提供的代码示例 opencv\sources\samples\android\face-detection\jni\DetectionBasedTracker_jni.cpp 中定义的 CascadeDetectorAdapter 写入 OpenCV.h:

# pragma once

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

CascadeClassifier face_CascadeClassifier;
cv::Ptr<DetectionBasedTracker> tracker;

class CascadeDetectorAdapter : public DetectionBasedTracker::IDetector
{
public:
	CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector) :
		IDetector(),
		Detector(detector)
	{
		CV_Assert(detector);
	}

    // 每张 Image 图片中都可能会有多张人脸 objects,因此可能会多次调用 detect 进行识别
	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;
};

接下来我们通过宏定义的方式在原始代码上进行优化,加入使用跟随策略进行人脸检测的代码:

// 定义此宏则收集人脸图片数据保存到指定位置
#define COLLECT_SAMPLES
// 收集的人脸图片编号
int i = 0;

// 一次识别,后续跟踪来解决只通过检测的方式的卡顿问题
void track() {
// 如果定义了 DETECT 宏,则每一帧都进行检测,否则只检测一帧,后续跟随,这里我们没有定义这个宏
#ifdef DETECT
	// 1.加载级联分类器,注意路径一定是斜杠而不是反斜杠,否则会加载失败
	if (!face_CascadeClassifier.load("G:/Tools/OpenCV/build/etc/haarcascades/haarcascade_frontalface_alt.xml")) {
		cout << "级联分类器加载失败!" << endl;
		return;
	}
#else
	// 2.创建跟踪器并运行
	// 2.1 创建主检测适配器
	cv::Ptr<CascadeDetectorAdapter> mainDetector = makePtr<CascadeDetectorAdapter>(
		makePtr<CascadeClassifier>("G:/Tools/OpenCV/build/etc/haarcascades/haarcascade_frontalface_alt.xml"));
	// 2.2 创建跟踪检测适配器
	cv::Ptr<CascadeDetectorAdapter> trackingDetector = makePtr<CascadeDetectorAdapter>(
		makePtr<CascadeClassifier>("G:/Tools/OpenCV/build/etc/haarcascades/haarcascade_frontalface_alt.xml"));
	// 2.3 创建跟踪器
	DetectionBasedTracker::Parameters DetectorParams;
	tracker = makePtr<DetectionBasedTracker>(mainDetector, trackingDetector, DetectorParams);
	// 2.4 开始检测
	tracker->run();
#endif

	// 3.开启摄像头进行录制
	VideoCapture capture;
	capture.open(0);
	if (!capture.isOpened())
	{
		cout << "OpenCV 打开摄像头失败!\n" << endl;
		return ;
	}

	// 4.处理采集到的图像
	Mat frame; // 摄像头彩色图像
	Mat gray; // 摄像头灰度图像
	while (true)
	{
		// 采集到的图像存入 frame
		capture >> frame;
		if (frame.empty()) {
			cout << "OpenCV 读取摄像头图像失败!\n" << endl;
			return ;
		}

		// 灰度化处理,注意 OpenCV 颜色排序为 BGR
		cvtColor(frame, gray, COLOR_BGR2GRAY);

		// 直方图均衡化,增强对比度
		equalizeHist(gray, gray);

		// 一张图片可能包含多张人脸,因此要保存在 faces 集合中
		vector<Rect> faces;
// 如果每帧都识别,则通过 detectMultiScale,否则用 tracker 进行识别
#ifdef DETECT
		face_CascadeClassifier.detectMultiScale(gray, faces);
#else
		tracker->process(gray);
		tracker->getObjects(faces);
#endif // DETECT
		for each (Rect face in faces)
		{
			// 在 frame 这张图片的 face 上画一个 BGR 颜色为 (0, 0, 255) 即红色的矩形
			rectangle(frame, face, Scalar(0, 0, 255));
			// 这种方式来检测相机实时人脸图像非常卡顿!只适合静态图像的检测

#ifdef COLLECT_SAMPLES
			// 采集人脸样本,转换为 24 * 24 的灰度图保存到指定路径的文件中
			Mat sample;
			frame(face).copyTo(sample);
			resize(sample, sample, Size(24, 24));
			cvtColor(sample, sample, COLOR_BGR2GRAY);
			char p[100];
			// 目录需要手动创建,否则不会自动生成
			sprintf(p, "D:/opencv/train/face/pos/%d.jpg", i++);
			//imread 读取文件图像
			imwrite(p, sample);//将Mat写入文件	
#endif // COLLECT_SAMPLES
		}

		// 显示图像
		imshow("摄像头", frame);
		// Esc 键退出
		if (waitKey(30) == 27)
		{
			break;
		}
	}
#ifndef DETECT
	tracker->stop();
#endif // !DETECT
}

简要说明:

  • 在第 2 步创建跟踪器时,使用了 OpenCV 的智能指针 Ptr 模板类,它采用引用计数型的句柄类实现计数。自动管理对象的释放,Ptr 中调用 release() 会将引用计数器减 1,如果计数器为 0 则会删除该对象。使用 Ptr 声明的对象可以不用手动释放
  • 创建的 mainDetector 负责检测,trackingDetector 负责跟随,调用 tracker->run() 会开启一个线程,其内部有一个无限循环,当 tracker->process() 传入灰度图开始检测后,检测到的人脸数据可以通过 tracker->getObjects(faces) 获取,faces 是一个 vector<Rect> 类型的入参出参数据,保存着一张图片中的所有人脸
  • 我们定义了 COLLECT_SAMPLES 宏用来收集人脸数据,将采集到的人脸图像转成灰度图再把尺寸设置为 24 * 24 保存在指定目录中,这些图片可以帮助我们使用 2.1 节中介绍的方法训练自己的模型

应用以上代码后就可以流畅的识别出人脸了。

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

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

相关文章

【负载均衡在线OJ项目日记】项目简介

目录 前言 什么是负载均衡 所用的技术和开发环境 所用技术 开发环境 项目的宏观结构 leetcode 结构 结构 编写思路 前言 从C语言的文章到现在Linux网络部分&#xff0c;我已经涉猎了很多知识&#xff1b;终于在今天我要开始搞项目了&#xff0c;通过项目我也可以开始…

《Fundamentals of Power Electronics》——一些常用变换器的正则电路参数值

对于理想的CCM PWM dc-dc转换器&#xff0c;其包含一个电感和电容&#xff0c;正则模型有效的低通滤波器需要包含一个电感和一个电容。正则模型简化为如下图所示。 假设电容与负载直接相连。基础的buck、boost和buck-boost转换器的参数值如下表所示。 该模型可以用传统的线性电…

【贪心算法】最小生成树Kruskal算法Python实现

文章目录 [toc]问题描述最小生成树的性质证明 Kruskal算法Python实现时间复杂性 问题描述 设 G ( V , E ) G (V , E) G(V,E)是无向连通带权图&#xff0c; E E E中每条边 ( v , w ) (v , w) (v,w)的权为 c [ v ] [ w ] c[v][w] c[v][w]如果 G G G的一个子图 G ′ G^{} G′是…

贪心问题 难度[普及-]一赏

目录 #小A的糖果 删数问题 陶陶摘苹果&#xff08;升级版&#xff09; P5019 NOIP2018 提高组 铺设道路 小A的糖果 原文链接: P3817 小A的糖果 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述 小 A 有 n 个糖果盒&#xff0c;第 i 个盒中有 a_i 颗糖果。 小 A 每…

【吃透Java手写】Spring(下)-AOP-事务及传播原理

【吃透Java手写】Spring&#xff08;下&#xff09;AOP-事务及传播原理 6 AOP模拟实现6.1 AOP工作流程6.2 定义dao接口与实现类6.3 初始化后逻辑6.4 原生Spring的方法6.4.1 实现类6.4.2 定义通知类&#xff0c;定义切入点表达式、配置切面6.4.3 在配置类中进行Spring注解包扫描…

Windows系统安装MySQL数据库详细教程

【确认本地是否安装mysql】 &#xff08;1&#xff09;按【winr】快捷键打开运行&#xff1b; &#xff08;2&#xff09;输入services.msc&#xff0c;点击【确定】&#xff1b; &#xff08;3&#xff09;在打开的服务列表中查找mysql服务&#xff0c;如果没有mysql服务&am…

计算机组成结构—虚拟存储器

目录 一、虚拟存储器的基本概念 二、页式虚拟存储器 1.页表 2.快表(TLB) 3.具有 TLB 和 Cache 的多级存储系统 三、段式虚拟存储器 四、段页式虚拟存储器 五、虚拟存储器和Cache比较 早期的计算机&#xff0c;CPU 是直接操作主存的&#xff0c;也就是运行程序时&#xf…

工业光源环形系列一高均匀条形光源特点

产品特点 ◆可以根据检测需求随意调整照射角度&#xff1a; ◆可以根据检测需求选择光源颜色&#xff1a; ◆多个条形光源可以自由组合&#xff1a; ◆使用贴片灯珠&#xff0c;均匀性更好。

使用Docker安装MySql数据库

大家好&#xff0c;今天给大家分享一下如何使用docker安装MySql数据库&#xff0c;关于docker的安装和常用命令&#xff0c;大家可以参考下面两篇文章&#xff0c;本文中不做过多描述。 Docker在Windows与CentOS上的安装 Docker常用命令 一、拉取MySql数据库镜像 docker pul…

远程桌面连接不上,远程桌面连接不上的专业解决策略

在信息技术领域&#xff0c;远程桌面连接是一种非常重要的工具&#xff0c;它允许用户从任何地点、任何时间访问和操作远程计算机。然而&#xff0c;当远程桌面连接出现问题时&#xff0c;可能会严重影响工作效率。以下是一些可能导致远程桌面连接不上的原因以及相应的解决方案…

usb个人总结

前言&#xff1a; 推荐快速上手资料&#xff1a; 《圈圈教你玩usb》讲用一个usb模块51如何让电脑识别出一个usb设备&#xff0c;也介绍了不少相关的字段内容。 其他例如uac\hid相关字段怎么看的建议去官网下载文档 USB-IF官方网站&#xff1a;Front Page | USB-IF USB中文…

AIGC绘画辅助网站

Midjourney风格样式 Midjourney Style Classifier | Andrei Kovalevs Midlibrary

系统维护启动盘 优启吧

优启吧-《优启时代系统维护盘》2025典藏版&#xff08;UD/ISO&#xff09;

STM32F4xx开发学习_SysTick

SysTick系统定时器 SysTick属于CM4内核外设&#xff0c;有关寄存器的定义和部分库函数都在core_cm4.h这个头文件中实现&#xff0c;可用于操作系统&#xff0c;提供必要的时钟节拍 SysTick简介 SysTick是一个 24 位向下定时器&#xff0c;属于CM4内核中的一个外设&#xff0c;…

Python类方法探秘:从单例模式到版本控制

引言&#xff1a; 在Python编程中&#xff0c;类方法作为一种特殊的实例方法&#xff0c;以其独特的魅力在众多编程范式中脱颖而出。它们不仅提供了无需实例即可调用的便捷性&#xff0c;还在设计模式、版本控制等方面发挥着重要作用。本文将通过几个生动的示例&#xff0c;带您…

八.吊打面试官系列-Tomcat优化-深入源码剖析Tomcat如何打破双亲委派

前言 上篇文章《Tomcat优化-深入Tomcat底层原理》我们从宏观上分析了一下Tomcat的顶层架构以及核心组件的执行流程。本篇文章我们从源码角度来分析Tomcat的类加载机制&#xff0c;且看它是如何打破JVM的ClassLoader双亲委派的 Tomcat ClassLoader 初始化 Tomcat的启动类是在…

5月7号(信息差)

&#x1f30d;首次&#xff0c;西湖大学用蛋白质语言模型定向改造碱基编辑器&#xff0c;登Cell子刊 https://www.jiqizhixin.com/articles/2024-05-07-10 &#x1f384; 哈马斯宣布同意停火提议 https://finance.eastmoney.com/a/202405073067687785.html ✨ 中国将对…

【陀螺仪JY61P维特智能】通过单片机修改波特率和角度参考的方法

根据官方文档&#xff1a; 修改波特率 1.解锁:FF AA 69 88 B5 1.1延时200ms 2.修改波特率:FF AA 04 06 00 2.1切换已修改的波特率然后重新发送解锁和保存指令 2.2解锁:FF AA 69 88 B5 2.3延时200ms 4.保存: FF AA 00 00 00 XY轴角度参考 角度参考是以传感器当前的实际位置&…

IDEA远程连接docker服务,windows版docker desktop

1.windows上安装docker desktop docker desktop下载地址&#xff1a;Docker Desktop: The #1 Containerization Tool for Developers | Docker 有的windows系统不支持安装docker desktop 安装完之后我们可以直接打开&#xff0c;可以选择不登录使用 我们用IDEA连接到docker …

python菜鸟级安装教程 -下篇(安装编辑器)

来来~接着上篇的来~ 安装好python.exe之后&#xff0c;我们可以根据cmd命令窗口&#xff0c;码代码。 这算最简单入门了~ 如果我们在安装个编辑器。是什么效果&#xff0c;一起体验一下吧 第一步&#xff0c;下载编辑器&#xff0c;选择官网&#xff0c;下载免费版本入门足…